@tenphi/tasty 0.0.0-snapshot.b6cc3cd → 0.0.0-snapshot.b7bfdb1
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 +147 -129
- package/dist/{babel-D8dm92E_.d.ts → babel-Brsw7Ax_.d.ts} +2 -2
- package/dist/{collector-BFuqdF2F.d.ts → collector-0YO-P1vW.d.ts} +2 -2
- package/dist/{collector-Di3C8btw.js → collector-DJqx7XO0.js} +3 -3
- package/dist/{collector-Di3C8btw.js.map → collector-DJqx7XO0.js.map} +1 -1
- package/dist/{config-DH7I0Ggx.d.ts → config-CscQCTAM.d.ts} +133 -40
- package/dist/{config-BrDt11hO.js → config-DsqqkmUs.js} +496 -1009
- package/dist/config-DsqqkmUs.js.map +1 -0
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +6 -6
- package/dist/{core-YWn1zgh4.js → core-KVEKOhEi.js} +145 -105
- package/dist/core-KVEKOhEi.js.map +1 -0
- package/dist/{css-writer-CQYbT4g_.js → css-writer-Cdrh5gHj.js} +3 -3
- package/dist/{css-writer-CQYbT4g_.js.map → css-writer-Cdrh5gHj.js.map} +1 -1
- package/dist/{format-rules-DdmLdntR.js → format-rules-CHNmNGhw.js} +5 -20
- package/dist/format-rules-CHNmNGhw.js.map +1 -0
- package/dist/{hydrate-D2ivfS-B.js → hydrate-DJhwbWq4.js} +3 -3
- package/dist/{hydrate-D2ivfS-B.js.map → hydrate-DJhwbWq4.js.map} +1 -1
- package/dist/{index-DljBkZhV.d.ts → index-BR9as3qn.d.ts} +52 -22
- package/dist/{index-LC3O3Jj4.d.ts → index-BmogEzTo.d.ts} +75 -16
- package/dist/index.d.ts +5 -5
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/{keyframes-CoLLjBcd.js → keyframes-CQY-i8dO.js} +110 -21
- package/dist/keyframes-CQY-i8dO.js.map +1 -0
- package/dist/{merge-styles-Cx_6ySBv.d.ts → merge-styles-BcLl1u_d.d.ts} +2 -2
- package/dist/{merge-styles-bdh7-1uh.js → merge-styles-voA8J__3.js} +2 -2
- package/dist/{merge-styles-bdh7-1uh.js.map → merge-styles-voA8J__3.js.map} +1 -1
- package/dist/{resolve-recipes-9JYSgubn.js → resolve-recipes-BP2NqOtQ.js} +3 -3
- package/dist/{resolve-recipes-9JYSgubn.js.map → resolve-recipes-BP2NqOtQ.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/README.md +13 -8
- package/docs/adoption.md +56 -31
- package/docs/ai-agents.md +78 -77
- package/docs/comparison.md +69 -40
- package/docs/configuration.md +164 -101
- package/docs/debug.md +4 -2
- package/docs/design-system.md +41 -22
- package/docs/dsl.md +263 -198
- package/docs/getting-started.md +60 -39
- package/docs/injector.md +63 -26
- package/docs/methodology.md +43 -37
- package/docs/migration-v3.md +49 -49
- package/docs/pipeline.md +1 -4
- package/docs/plugins.md +37 -33
- package/docs/react-api.md +66 -45
- package/docs/runtime-benchmarks.md +178 -0
- package/docs/ssr.md +56 -57
- package/docs/styles.md +9 -2
- package/docs/tasty-static.md +137 -104
- package/package.json +12 -7
- package/dist/config-BrDt11hO.js.map +0 -1
- package/dist/core-YWn1zgh4.js.map +0 -1
- package/dist/format-rules-DdmLdntR.js.map +0 -1
- package/dist/keyframes-CoLLjBcd.js.map +0 -1
|
@@ -52,16 +52,6 @@ const COLOR_FUNCS = new Set([
|
|
|
52
52
|
]);
|
|
53
53
|
/** A value that is a single `name(args)` call: captures the name and the args. */
|
|
54
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
55
|
const RE_UNIT_NUM = /^[+-]?(?:\d*\.\d+|\d+)([a-z][a-z0-9]*)$/;
|
|
66
56
|
const RE_NUMBER = /^[+-]?(?:\d*\.\d+|\d+)$/;
|
|
67
57
|
const RE_HEX = /^(?:[0-9a-f]{3,4}|[0-9a-f]{6}(?:[0-9a-f]{2})?)$/;
|
|
@@ -197,9 +187,6 @@ const OKLab_to_linear_sRGB_coefficients = [
|
|
|
197
187
|
]]
|
|
198
188
|
];
|
|
199
189
|
const dotXY = (a, b) => a[0] * b[0] + a[1] * b[1];
|
|
200
|
-
function srgbToLinear(c) {
|
|
201
|
-
return c <= .04045 ? c / 12.92 : ((c + .055) / 1.055) ** 2.4;
|
|
202
|
-
}
|
|
203
190
|
const INV_GAMMA = 1 / 2.4;
|
|
204
191
|
function srgbLinearToGamma(val) {
|
|
205
192
|
const sign = val < 0 ? -1 : 1;
|
|
@@ -241,22 +228,6 @@ const oklabToLinearSrgb = (lab) => {
|
|
|
241
228
|
-.004196076138675526 * l - .703418617935936 * m + 1.7076146940746113 * s
|
|
242
229
|
];
|
|
243
230
|
};
|
|
244
|
-
const linearSrgbToOklab = (rgb) => {
|
|
245
|
-
const r = rgb[0];
|
|
246
|
-
const g = rgb[1];
|
|
247
|
-
const b = rgb[2];
|
|
248
|
-
const l = .4122214708 * r + .5363325363 * g + .0514459929 * b;
|
|
249
|
-
const m = .2119034982 * r + .6806995451 * g + .1073969566 * b;
|
|
250
|
-
const s = .0883024619 * r + .2817188376 * g + .6299787005 * b;
|
|
251
|
-
const l_ = Math.cbrt(l);
|
|
252
|
-
const m_ = Math.cbrt(m);
|
|
253
|
-
const s_ = Math.cbrt(s);
|
|
254
|
-
return [
|
|
255
|
-
.2104542553 * l_ + .793617785 * m_ - .0040720468 * s_,
|
|
256
|
-
1.9779984951 * l_ - 2.428592205 * m_ + .4505937099 * s_,
|
|
257
|
-
.0259040371 * l_ + .7827717662 * m_ - .808675766 * s_
|
|
258
|
-
];
|
|
259
|
-
};
|
|
260
231
|
const computeMaxSaturationOKLC = (a, b) => {
|
|
261
232
|
const okCoeff = OKLab_to_linear_sRGB_coefficients;
|
|
262
233
|
const lmsToRgb = LMS_to_linear_sRGB_M;
|
|
@@ -450,53 +421,6 @@ function hslToRgbValues(h, s, l) {
|
|
|
450
421
|
];
|
|
451
422
|
}
|
|
452
423
|
/**
|
|
453
|
-
* RGB (0-255) to HSL.
|
|
454
|
-
* @returns [h (0-360), s (0-1), l (0-1)]
|
|
455
|
-
*/
|
|
456
|
-
function rgbToHsl(r, g, b) {
|
|
457
|
-
r /= 255;
|
|
458
|
-
g /= 255;
|
|
459
|
-
b /= 255;
|
|
460
|
-
const max = Math.max(r, g, b);
|
|
461
|
-
const min = Math.min(r, g, b);
|
|
462
|
-
const l = (max + min) / 2;
|
|
463
|
-
if (max === min) return [
|
|
464
|
-
0,
|
|
465
|
-
0,
|
|
466
|
-
l
|
|
467
|
-
];
|
|
468
|
-
const d = max - min;
|
|
469
|
-
const s = l > .5 ? d / (2 - max - min) : d / (max + min);
|
|
470
|
-
let h;
|
|
471
|
-
if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
472
|
-
else if (max === g) h = ((b - r) / d + 2) / 6;
|
|
473
|
-
else h = ((r - g) / d + 4) / 6;
|
|
474
|
-
return [
|
|
475
|
-
h * 360,
|
|
476
|
-
s,
|
|
477
|
-
l
|
|
478
|
-
];
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* RGB (0-255) to OKLCH via sRGB -> linear sRGB -> OKLab -> OKLCH.
|
|
482
|
-
* @returns [L, C, H] where H is in degrees (0-360)
|
|
483
|
-
*/
|
|
484
|
-
function rgbToOklch(r, g, b) {
|
|
485
|
-
const [L, a, bLab] = linearSrgbToOklab([
|
|
486
|
-
srgbToLinear(r / 255),
|
|
487
|
-
srgbToLinear(g / 255),
|
|
488
|
-
srgbToLinear(b / 255)
|
|
489
|
-
]);
|
|
490
|
-
const C = Math.sqrt(a * a + bLab * bLab);
|
|
491
|
-
let H = Math.atan2(bLab, a) * 180 / Math.PI;
|
|
492
|
-
if (H < 0) H += 360;
|
|
493
|
-
return [
|
|
494
|
-
L,
|
|
495
|
-
C,
|
|
496
|
-
H
|
|
497
|
-
];
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
424
|
* OKHSL to sRGB (0-1 range).
|
|
501
425
|
* @param h - Hue in degrees (0-360)
|
|
502
426
|
* @param s - Saturation (0-1)
|
|
@@ -700,80 +624,6 @@ function getNamedColorHex() {
|
|
|
700
624
|
]);
|
|
701
625
|
return _namedColorHex;
|
|
702
626
|
}
|
|
703
|
-
const hexCharToNum = (c) => {
|
|
704
|
-
if (c >= 48 && c <= 57) return c - 48;
|
|
705
|
-
if (c >= 65 && c <= 70) return c - 55;
|
|
706
|
-
if (c >= 97 && c <= 102) return c - 87;
|
|
707
|
-
return -1;
|
|
708
|
-
};
|
|
709
|
-
/**
|
|
710
|
-
* Parse a hex color string to RGBA values (RGB 0-255, alpha 0-1).
|
|
711
|
-
* Supports 3, 4, 6, and 8 character hex values (with or without `#`).
|
|
712
|
-
* For 3/6-char hex (no alpha channel), alpha defaults to 1.
|
|
713
|
-
*/
|
|
714
|
-
function hexToRgbaValues(hex) {
|
|
715
|
-
let start = 0;
|
|
716
|
-
if (hex.charCodeAt(0) === 35) start = 1;
|
|
717
|
-
const len = hex.length - start;
|
|
718
|
-
if (len === 3) {
|
|
719
|
-
const r = hexCharToNum(hex.charCodeAt(start));
|
|
720
|
-
const g = hexCharToNum(hex.charCodeAt(start + 1));
|
|
721
|
-
const b = hexCharToNum(hex.charCodeAt(start + 2));
|
|
722
|
-
if (r < 0 || g < 0 || b < 0) return null;
|
|
723
|
-
return [
|
|
724
|
-
r * 17,
|
|
725
|
-
g * 17,
|
|
726
|
-
b * 17,
|
|
727
|
-
1
|
|
728
|
-
];
|
|
729
|
-
}
|
|
730
|
-
if (len === 4) {
|
|
731
|
-
const r = hexCharToNum(hex.charCodeAt(start));
|
|
732
|
-
const g = hexCharToNum(hex.charCodeAt(start + 1));
|
|
733
|
-
const b = hexCharToNum(hex.charCodeAt(start + 2));
|
|
734
|
-
const a = hexCharToNum(hex.charCodeAt(start + 3));
|
|
735
|
-
if (r < 0 || g < 0 || b < 0 || a < 0) return null;
|
|
736
|
-
return [
|
|
737
|
-
r * 17,
|
|
738
|
-
g * 17,
|
|
739
|
-
b * 17,
|
|
740
|
-
a * 17 / 255
|
|
741
|
-
];
|
|
742
|
-
}
|
|
743
|
-
if (len === 6) {
|
|
744
|
-
const r1 = hexCharToNum(hex.charCodeAt(start));
|
|
745
|
-
const r2 = hexCharToNum(hex.charCodeAt(start + 1));
|
|
746
|
-
const g1 = hexCharToNum(hex.charCodeAt(start + 2));
|
|
747
|
-
const g2 = hexCharToNum(hex.charCodeAt(start + 3));
|
|
748
|
-
const b1 = hexCharToNum(hex.charCodeAt(start + 4));
|
|
749
|
-
const b2 = hexCharToNum(hex.charCodeAt(start + 5));
|
|
750
|
-
if (r1 < 0 || r2 < 0 || g1 < 0 || g2 < 0 || b1 < 0 || b2 < 0) return null;
|
|
751
|
-
return [
|
|
752
|
-
r1 * 16 + r2,
|
|
753
|
-
g1 * 16 + g2,
|
|
754
|
-
b1 * 16 + b2,
|
|
755
|
-
1
|
|
756
|
-
];
|
|
757
|
-
}
|
|
758
|
-
if (len === 8) {
|
|
759
|
-
const r1 = hexCharToNum(hex.charCodeAt(start));
|
|
760
|
-
const r2 = hexCharToNum(hex.charCodeAt(start + 1));
|
|
761
|
-
const g1 = hexCharToNum(hex.charCodeAt(start + 2));
|
|
762
|
-
const g2 = hexCharToNum(hex.charCodeAt(start + 3));
|
|
763
|
-
const b1 = hexCharToNum(hex.charCodeAt(start + 4));
|
|
764
|
-
const b2 = hexCharToNum(hex.charCodeAt(start + 5));
|
|
765
|
-
const a1 = hexCharToNum(hex.charCodeAt(start + 6));
|
|
766
|
-
const a2 = hexCharToNum(hex.charCodeAt(start + 7));
|
|
767
|
-
if (r1 < 0 || r2 < 0 || g1 < 0 || g2 < 0 || b1 < 0 || b2 < 0 || a1 < 0 || a2 < 0) return null;
|
|
768
|
-
return [
|
|
769
|
-
r1 * 16 + r2,
|
|
770
|
-
g1 * 16 + g2,
|
|
771
|
-
b1 * 16 + b2,
|
|
772
|
-
(a1 * 16 + a2) / 255
|
|
773
|
-
];
|
|
774
|
-
}
|
|
775
|
-
return null;
|
|
776
|
-
}
|
|
777
627
|
/**
|
|
778
628
|
* Convert hex color string to `rgb()` CSS string.
|
|
779
629
|
* Supports 3, 4, 6, and 8 character hex values (with or without `#`).
|
|
@@ -877,415 +727,7 @@ function oklchStringToRgb(oklchStr) {
|
|
|
877
727
|
return `rgb(${Math.round(r)} ${Math.round(g)} ${Math.round(b)})`;
|
|
878
728
|
}
|
|
879
729
|
//#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.
|
|
1003
|
-
*/
|
|
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;
|
|
1013
|
-
}
|
|
1014
|
-
//#endregion
|
|
1015
730
|
//#region src/utils/color-space.ts
|
|
1016
|
-
let currentColorSpace = "oklch";
|
|
1017
|
-
const colorSpaceCache = new Lru(500);
|
|
1018
|
-
const componentsCache = new Lru(500);
|
|
1019
|
-
function clearColorCaches() {
|
|
1020
|
-
colorSpaceCache.clear();
|
|
1021
|
-
componentsCache.clear();
|
|
1022
|
-
}
|
|
1023
|
-
function setColorSpace(space) {
|
|
1024
|
-
currentColorSpace = space;
|
|
1025
|
-
clearColorCaches();
|
|
1026
|
-
}
|
|
1027
|
-
function resetColorSpace() {
|
|
1028
|
-
currentColorSpace = "oklch";
|
|
1029
|
-
clearColorCaches();
|
|
1030
|
-
}
|
|
1031
|
-
function getColorSpaceSuffix() {
|
|
1032
|
-
return currentColorSpace;
|
|
1033
|
-
}
|
|
1034
|
-
function formatNum(n, precision) {
|
|
1035
|
-
return parseFloat(n.toFixed(precision)).toString();
|
|
1036
|
-
}
|
|
1037
|
-
function formatRgbComponent(n) {
|
|
1038
|
-
return parseFloat(n.toFixed(1)).toString();
|
|
1039
|
-
}
|
|
1040
|
-
function formatAlpha(a) {
|
|
1041
|
-
if (a === 0) return "0";
|
|
1042
|
-
return parseFloat(a.toFixed(4)).toString();
|
|
1043
|
-
}
|
|
1044
|
-
function rgbValuesToColorString(r, g, b, space, alpha) {
|
|
1045
|
-
const alphaSuffix = alpha != null && alpha < 1 ? ` / ${formatAlpha(alpha)}` : "";
|
|
1046
|
-
switch (space) {
|
|
1047
|
-
case "rgb": return `rgb(${Math.round(r)} ${Math.round(g)} ${Math.round(b)}${alphaSuffix})`;
|
|
1048
|
-
case "hsl": {
|
|
1049
|
-
const [h, s, l] = rgbToHsl(r, g, b);
|
|
1050
|
-
return `hsl(${formatNum(h, 2)} ${formatNum(s * 100, 2)}% ${formatNum(l * 100, 2)}%${alphaSuffix})`;
|
|
1051
|
-
}
|
|
1052
|
-
case "oklch": {
|
|
1053
|
-
const [L, C, H] = rgbToOklch(r, g, b);
|
|
1054
|
-
return `oklch(${formatNum(L, 5)} ${formatNum(C, 5)} ${formatNum(H, 2)}${alphaSuffix})`;
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
function rgbValuesToComponents(r, g, b, space) {
|
|
1059
|
-
switch (space) {
|
|
1060
|
-
case "rgb": return `${formatRgbComponent(r)} ${formatRgbComponent(g)} ${formatRgbComponent(b)}`;
|
|
1061
|
-
case "hsl": {
|
|
1062
|
-
const [h, s, l] = rgbToHsl(r, g, b);
|
|
1063
|
-
return `${formatNum(h, 2)} ${formatNum(s * 100, 2)}% ${formatNum(l * 100, 2)}%`;
|
|
1064
|
-
}
|
|
1065
|
-
case "oklch": {
|
|
1066
|
-
const [L, C, H] = rgbToOklch(r, g, b);
|
|
1067
|
-
return `${formatNum(L, 5)} ${formatNum(C, 5)} ${formatNum(H, 2)}`;
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
const parseColorFuncArgs = (str, prefix) => {
|
|
1072
|
-
const start = str.indexOf("(", prefix.length - 1);
|
|
1073
|
-
const end = str.lastIndexOf(")");
|
|
1074
|
-
if (start < 0 || end < 0) return null;
|
|
1075
|
-
const inner = str.slice(start + 1, end).trim();
|
|
1076
|
-
const slashIdx = inner.indexOf("/");
|
|
1077
|
-
let colorPart;
|
|
1078
|
-
let alpha = 1;
|
|
1079
|
-
if (slashIdx >= 0) {
|
|
1080
|
-
colorPart = inner.slice(0, slashIdx);
|
|
1081
|
-
const alphaStr = inner.slice(slashIdx + 1).trim();
|
|
1082
|
-
if (alphaStr) {
|
|
1083
|
-
alpha = alphaStr.endsWith("%") ? parseFloat(alphaStr) / 100 : parseFloat(alphaStr);
|
|
1084
|
-
if (Number.isNaN(alpha)) alpha = 1;
|
|
1085
|
-
}
|
|
1086
|
-
} else colorPart = inner;
|
|
1087
|
-
const parts = colorPart.trim().split(/[,\s]+/).filter(Boolean);
|
|
1088
|
-
if (parts.length < 3) return null;
|
|
1089
|
-
if (parts.length >= 4 && slashIdx < 0) {
|
|
1090
|
-
const legacyAlpha = parseFloat(parts[3]);
|
|
1091
|
-
if (!Number.isNaN(legacyAlpha)) alpha = legacyAlpha;
|
|
1092
|
-
}
|
|
1093
|
-
return {
|
|
1094
|
-
parts,
|
|
1095
|
-
alpha
|
|
1096
|
-
};
|
|
1097
|
-
};
|
|
1098
|
-
const parseHue = (hueStr) => {
|
|
1099
|
-
let h = parseFloat(hueStr);
|
|
1100
|
-
const lower = hueStr.toLowerCase();
|
|
1101
|
-
if (lower.endsWith("turn")) h = parseFloat(lower) * 360;
|
|
1102
|
-
else if (lower.endsWith("rad")) h = parseFloat(lower) * 180 / Math.PI;
|
|
1103
|
-
return (h % 360 + 360) % 360;
|
|
1104
|
-
};
|
|
1105
|
-
const parsePercent = (val) => {
|
|
1106
|
-
const num = parseFloat(val);
|
|
1107
|
-
return val.includes("%") ? num / 100 : num;
|
|
1108
|
-
};
|
|
1109
|
-
const clamp01 = (n) => Math.max(0, Math.min(1, n));
|
|
1110
|
-
function resolveToRgbaValues(color) {
|
|
1111
|
-
const trimmed = color.trim().toLowerCase();
|
|
1112
|
-
if (trimmed.startsWith("rgb")) {
|
|
1113
|
-
const parsed = parseColorFuncArgs(trimmed, "rgb");
|
|
1114
|
-
if (!parsed || parsed.parts.length < 3) return null;
|
|
1115
|
-
return [
|
|
1116
|
-
parsed.parts[0].endsWith("%") ? parseFloat(parsed.parts[0]) / 100 * 255 : parseFloat(parsed.parts[0]),
|
|
1117
|
-
parsed.parts[1].endsWith("%") ? parseFloat(parsed.parts[1]) / 100 * 255 : parseFloat(parsed.parts[1]),
|
|
1118
|
-
parsed.parts[2].endsWith("%") ? parseFloat(parsed.parts[2]) / 100 * 255 : parseFloat(parsed.parts[2]),
|
|
1119
|
-
parsed.alpha
|
|
1120
|
-
];
|
|
1121
|
-
}
|
|
1122
|
-
if (trimmed.startsWith("#")) return hexToRgbaValues(trimmed);
|
|
1123
|
-
if (trimmed.startsWith("hsl")) {
|
|
1124
|
-
const parsed = parseColorFuncArgs(trimmed, "hsl");
|
|
1125
|
-
if (!parsed) return null;
|
|
1126
|
-
const [r, g, b] = hslToRgbValues(parseHue(parsed.parts[0]), clamp01(parsePercent(parsed.parts[1])), clamp01(parsePercent(parsed.parts[2])));
|
|
1127
|
-
return [
|
|
1128
|
-
r,
|
|
1129
|
-
g,
|
|
1130
|
-
b,
|
|
1131
|
-
parsed.alpha
|
|
1132
|
-
];
|
|
1133
|
-
}
|
|
1134
|
-
if (trimmed.startsWith("oklch(")) {
|
|
1135
|
-
const parsed = parseColorFuncArgs(trimmed, "oklch");
|
|
1136
|
-
if (!parsed) return null;
|
|
1137
|
-
const [r, g, b] = oklchToRgbValues(clamp01(parsePercent(parsed.parts[0])), Math.max(0, parseFloat(parsed.parts[1])), parseHue(parsed.parts[2]));
|
|
1138
|
-
return [
|
|
1139
|
-
r,
|
|
1140
|
-
g,
|
|
1141
|
-
b,
|
|
1142
|
-
parsed.alpha
|
|
1143
|
-
];
|
|
1144
|
-
}
|
|
1145
|
-
const resolved = resolveFunctionColor(trimmed);
|
|
1146
|
-
if (resolved && resolved !== trimmed) return resolveToRgbaValues(resolved);
|
|
1147
|
-
const fallback = strToRgb(trimmed);
|
|
1148
|
-
if (fallback) {
|
|
1149
|
-
if (fallback !== trimmed) return resolveToRgbaValues(fallback);
|
|
1150
|
-
const vals = getRgbValuesFromRgbaString(fallback);
|
|
1151
|
-
if (vals.length >= 3) return [
|
|
1152
|
-
vals[0],
|
|
1153
|
-
vals[1],
|
|
1154
|
-
vals[2],
|
|
1155
|
-
1
|
|
1156
|
-
];
|
|
1157
|
-
}
|
|
1158
|
-
return null;
|
|
1159
|
-
}
|
|
1160
|
-
const SPACE_FUNCS = {
|
|
1161
|
-
rgb: ["rgb", "rgba"],
|
|
1162
|
-
hsl: ["hsl", "hsla"],
|
|
1163
|
-
oklch: ["oklch", "oklcha"]
|
|
1164
|
-
};
|
|
1165
|
-
const CANONICAL_FUNC = {
|
|
1166
|
-
rgb: "rgb",
|
|
1167
|
-
hsl: "hsl",
|
|
1168
|
-
oklch: "oklch"
|
|
1169
|
-
};
|
|
1170
|
-
/**
|
|
1171
|
-
* Parse a native CSS color function ONLY when its name matches the configured
|
|
1172
|
-
* output space. Splits arguments at the top level, preserving every token
|
|
1173
|
-
* (numbers, percentages, `var()`, `calc()`, `min()`, …) verbatim — no numeric
|
|
1174
|
-
* parsing or normalization is performed.
|
|
1175
|
-
*
|
|
1176
|
-
* Returns null when the input is not a same-space function (caller falls back
|
|
1177
|
-
* to the sRGB round-trip for genuine cross-space conversion / hex / named colors).
|
|
1178
|
-
*/
|
|
1179
|
-
function parseSameSpaceFunc(color, space) {
|
|
1180
|
-
const original = color.trim();
|
|
1181
|
-
const lower = original.toLowerCase();
|
|
1182
|
-
const funcs = SPACE_FUNCS[space];
|
|
1183
|
-
let funcName = null;
|
|
1184
|
-
for (const f of funcs) if (lower.startsWith(`${f}(`)) {
|
|
1185
|
-
funcName = f;
|
|
1186
|
-
break;
|
|
1187
|
-
}
|
|
1188
|
-
if (!funcName) return null;
|
|
1189
|
-
const start = funcName.length;
|
|
1190
|
-
const end = original.lastIndexOf(")");
|
|
1191
|
-
if (end < start) return null;
|
|
1192
|
-
const inner = original.slice(start + 1, end).trim();
|
|
1193
|
-
if (!inner) return null;
|
|
1194
|
-
const rawTokens = [];
|
|
1195
|
-
let depth = 0;
|
|
1196
|
-
let buf = "";
|
|
1197
|
-
for (const c of inner) if (c === "(") {
|
|
1198
|
-
depth++;
|
|
1199
|
-
buf += c;
|
|
1200
|
-
} else if (c === ")") {
|
|
1201
|
-
depth--;
|
|
1202
|
-
buf += c;
|
|
1203
|
-
} else if (depth === 0 && (c === " " || c === "," || c === " " || c === "\n")) {
|
|
1204
|
-
if (buf) {
|
|
1205
|
-
rawTokens.push(buf);
|
|
1206
|
-
buf = "";
|
|
1207
|
-
}
|
|
1208
|
-
} else buf += c;
|
|
1209
|
-
if (buf) rawTokens.push(buf);
|
|
1210
|
-
let alpha = null;
|
|
1211
|
-
const parts = [];
|
|
1212
|
-
for (let i = 0; i < rawTokens.length; i++) {
|
|
1213
|
-
const tok = rawTokens[i];
|
|
1214
|
-
if (tok === "/") {
|
|
1215
|
-
alpha = rawTokens[i + 1] ?? null;
|
|
1216
|
-
break;
|
|
1217
|
-
}
|
|
1218
|
-
parts.push(tok);
|
|
1219
|
-
}
|
|
1220
|
-
if (alpha === null && parts.length === 4) {
|
|
1221
|
-
alpha = parts[3];
|
|
1222
|
-
parts.length = 3;
|
|
1223
|
-
}
|
|
1224
|
-
if (parts.length !== 3) return null;
|
|
1225
|
-
if (parts.some((p) => !p)) return null;
|
|
1226
|
-
return {
|
|
1227
|
-
parts,
|
|
1228
|
-
alpha
|
|
1229
|
-
};
|
|
1230
|
-
}
|
|
1231
|
-
function buildSameSpaceString(parsed, space) {
|
|
1232
|
-
const func = CANONICAL_FUNC[space];
|
|
1233
|
-
const body = parsed.parts.join(" ");
|
|
1234
|
-
return parsed.alpha != null ? `${func}(${body} / ${parsed.alpha})` : `${func}(${body})`;
|
|
1235
|
-
}
|
|
1236
|
-
/**
|
|
1237
|
-
* Build the decomposed component list for a same-space value.
|
|
1238
|
-
*
|
|
1239
|
-
* Dynamic tokens (`var()` / `calc()` / …) are preserved verbatim — they can't
|
|
1240
|
-
* be parsed and must survive into the CSS output. Purely static components are
|
|
1241
|
-
* normalized to the canonical numeric form for the space so the companion
|
|
1242
|
-
* `--*-color-{space}` variable stays a valid `<number>+` value (rgb/oklch) —
|
|
1243
|
-
* WITHOUT round-tripping through sRGB, which would clamp wide-gamut oklch.
|
|
1244
|
-
*
|
|
1245
|
-
* Non-native, parse-time-only functions (`okhsl()` / `okhst()`) are always
|
|
1246
|
-
* resolved to a static `rgb(...%)` upstream, so this is the path that turns
|
|
1247
|
-
* their percentage channels back into 0-255 numbers.
|
|
1248
|
-
*/
|
|
1249
|
-
function buildSameSpaceComponents(parsed, space) {
|
|
1250
|
-
const parts = parsed.parts;
|
|
1251
|
-
if (parts.some((p) => p.includes("("))) return parts.join(" ");
|
|
1252
|
-
switch (space) {
|
|
1253
|
-
case "rgb": return parts.map((p) => p.endsWith("%") ? formatRgbComponent(parseFloat(p) / 100 * 255) : p).join(" ");
|
|
1254
|
-
case "hsl": return parts.join(" ");
|
|
1255
|
-
case "oklch": {
|
|
1256
|
-
const [l, c, h] = parts;
|
|
1257
|
-
return [
|
|
1258
|
-
l.endsWith("%") ? formatNum(parseFloat(l) / 100, 5) : l,
|
|
1259
|
-
c,
|
|
1260
|
-
h
|
|
1261
|
-
].join(" ");
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
/**
|
|
1266
|
-
* Convert any supported color string to the configured color space CSS format.
|
|
1267
|
-
* Preserves alpha channel when present in the input.
|
|
1268
|
-
* Returns null if the input cannot be parsed.
|
|
1269
|
-
*/
|
|
1270
|
-
function strToColorSpace(color) {
|
|
1271
|
-
if (!color) return void 0;
|
|
1272
|
-
const cached = colorSpaceCache.get(color);
|
|
1273
|
-
if (cached !== void 0) return cached;
|
|
1274
|
-
const sameSpace = parseSameSpaceFunc(color, currentColorSpace);
|
|
1275
|
-
if (sameSpace) {
|
|
1276
|
-
const result = buildSameSpaceString(sameSpace, currentColorSpace);
|
|
1277
|
-
colorSpaceCache.set(color, result);
|
|
1278
|
-
return result;
|
|
1279
|
-
}
|
|
1280
|
-
const rgba = resolveToRgbaValues(color);
|
|
1281
|
-
if (!rgba) {
|
|
1282
|
-
colorSpaceCache.set(color, null);
|
|
1283
|
-
return null;
|
|
1284
|
-
}
|
|
1285
|
-
const result = rgbValuesToColorString(rgba[0], rgba[1], rgba[2], currentColorSpace, rgba[3]);
|
|
1286
|
-
colorSpaceCache.set(color, result);
|
|
1287
|
-
return result;
|
|
1288
|
-
}
|
|
1289
731
|
/**
|
|
1290
732
|
* Set the alpha of a whole color, replacing any it already carries.
|
|
1291
733
|
*
|
|
@@ -1293,14 +735,13 @@ function strToColorSpace(color) {
|
|
|
1293
735
|
* emits. `oklch(from <color> l c h / <alpha>)` copies the channels over and
|
|
1294
736
|
* writes the alpha slot, which needs nothing from the color except that it *is*
|
|
1295
737
|
* a color: a `color-mix()`, a `light-dark()`, a `currentcolor`, a
|
|
1296
|
-
* `--name-color` written by hand-authored CSS
|
|
1297
|
-
*
|
|
1298
|
-
* the engine
|
|
738
|
+
* `--name-color` written by hand-authored CSS that Tasty never defined — all of
|
|
739
|
+
* them work, where writing into a channel slot directly would require channels
|
|
740
|
+
* the engine has no way to compute.
|
|
1299
741
|
*
|
|
1300
742
|
* Alpha is *replaced*, not composed. A token holding `rgb(255 0 0 / .8)` faded
|
|
1301
|
-
* to `.5` is alpha `.5
|
|
1302
|
-
*
|
|
1303
|
-
* cannot do this — it would multiply the two to `.4`.
|
|
743
|
+
* to `.5` is alpha `.5`. `color-mix()` against `transparent` cannot do this —
|
|
744
|
+
* it would multiply the two to `.4`.
|
|
1304
745
|
*
|
|
1305
746
|
* The alpha slot takes a `<number>` or a `<percentage>`, so an opacity custom
|
|
1306
747
|
* property passes straight through in whichever form the author declared it.
|
|
@@ -1350,115 +791,6 @@ function parseAlphaOverride(value) {
|
|
|
1350
791
|
alpha: match[2]
|
|
1351
792
|
} : null;
|
|
1352
793
|
}
|
|
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
|
-
/**
|
|
1375
|
-
* Extract the decomposed components of a color in the configured color space.
|
|
1376
|
-
* Returns a space-separated string of components without the wrapping function.
|
|
1377
|
-
* Alpha is NOT included — components are used for alpha composition via `/ alpha`.
|
|
1378
|
-
*/
|
|
1379
|
-
function getColorSpaceComponents(color) {
|
|
1380
|
-
const cached = componentsCache.get(color);
|
|
1381
|
-
if (cached !== void 0) return cached;
|
|
1382
|
-
const sameSpace = parseSameSpaceFunc(color, currentColorSpace);
|
|
1383
|
-
if (sameSpace) {
|
|
1384
|
-
const result = buildSameSpaceComponents(sameSpace, currentColorSpace);
|
|
1385
|
-
componentsCache.set(color, result);
|
|
1386
|
-
return result;
|
|
1387
|
-
}
|
|
1388
|
-
const rgba = resolveToRgbaValues(color);
|
|
1389
|
-
if (!rgba) return color;
|
|
1390
|
-
const result = rgbValuesToComponents(rgba[0], rgba[1], rgba[2], currentColorSpace);
|
|
1391
|
-
componentsCache.set(color, result);
|
|
1392
|
-
return result;
|
|
1393
|
-
}
|
|
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
|
-
/**
|
|
1430
|
-
* Convert a color initial value (from @property definitions) to components
|
|
1431
|
-
* in the configured color space.
|
|
1432
|
-
*/
|
|
1433
|
-
function colorInitialValueToComponents(initialValue) {
|
|
1434
|
-
if (initialValue == null) return getDefaultComponents();
|
|
1435
|
-
const val = String(initialValue).trim().toLowerCase();
|
|
1436
|
-
if (val === "transparent" || val === "rgba(0,0,0,0)" || val === "") return getDefaultComponents();
|
|
1437
|
-
if (val === "white") return rgbValuesToComponents(255, 255, 255, currentColorSpace);
|
|
1438
|
-
if (val === "black") return rgbValuesToComponents(0, 0, 0, currentColorSpace);
|
|
1439
|
-
const rgbMatch = val.match(/^rgba?\(\s*(\d+)[,\s]+(\d+)[,\s]+(\d+)/);
|
|
1440
|
-
if (rgbMatch) return rgbValuesToComponents(parseInt(rgbMatch[1]), parseInt(rgbMatch[2]), parseInt(rgbMatch[3]), currentColorSpace);
|
|
1441
|
-
return getDefaultComponents();
|
|
1442
|
-
}
|
|
1443
|
-
function getDefaultComponents() {
|
|
1444
|
-
switch (currentColorSpace) {
|
|
1445
|
-
case "rgb": return "0 0 0";
|
|
1446
|
-
case "hsl": return "0 0% 0%";
|
|
1447
|
-
case "oklch": return "0 0 0";
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
/**
|
|
1451
|
-
* Get the CSS @property syntax for the companion components variable.
|
|
1452
|
-
* RGB and OKLCH components are all plain numbers, so `<number>+` works.
|
|
1453
|
-
* HSL includes percentages (`h s% l%`), so `*` is the only safe choice.
|
|
1454
|
-
*/
|
|
1455
|
-
function getComponentPropertySyntax() {
|
|
1456
|
-
switch (currentColorSpace) {
|
|
1457
|
-
case "rgb":
|
|
1458
|
-
case "oklch": return "<number>+";
|
|
1459
|
-
default: return "*";
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
794
|
//#endregion
|
|
1463
795
|
//#region src/parser/types.ts
|
|
1464
796
|
const makeEmptyPart = () => ({
|
|
@@ -1878,6 +1210,96 @@ function classify(raw, opts, recurse) {
|
|
|
1878
1210
|
};
|
|
1879
1211
|
}
|
|
1880
1212
|
//#endregion
|
|
1213
|
+
//#region src/parser/lru.ts
|
|
1214
|
+
/**
|
|
1215
|
+
* Doubly-linked-list LRU.
|
|
1216
|
+
*
|
|
1217
|
+
* The list holds direct node references rather than keys, so rewiring on a
|
|
1218
|
+
* `get()` of a non-MRU entry is pure pointer work. Storing keys instead cost
|
|
1219
|
+
* three extra `Map.get()` lookups per read (prev, next and the current head),
|
|
1220
|
+
* which is measurable on these read-mostly caches: they are hit on every
|
|
1221
|
+
* render once the style pipeline is warm.
|
|
1222
|
+
*/
|
|
1223
|
+
var Lru = class {
|
|
1224
|
+
limit;
|
|
1225
|
+
map = /* @__PURE__ */ new Map();
|
|
1226
|
+
head = null;
|
|
1227
|
+
tail = null;
|
|
1228
|
+
onEvict;
|
|
1229
|
+
constructor(limit = 1e3, onEvict) {
|
|
1230
|
+
this.limit = limit;
|
|
1231
|
+
let normalized = Number.isFinite(this.limit) ? Math.floor(this.limit) : 1e3;
|
|
1232
|
+
if (normalized <= 0) normalized = 1e3;
|
|
1233
|
+
this.limit = normalized;
|
|
1234
|
+
this.onEvict = onEvict;
|
|
1235
|
+
}
|
|
1236
|
+
setOnEvict(fn) {
|
|
1237
|
+
this.onEvict = fn;
|
|
1238
|
+
}
|
|
1239
|
+
get(key) {
|
|
1240
|
+
const node = this.map.get(key);
|
|
1241
|
+
if (node === void 0) return void 0;
|
|
1242
|
+
if (this.head !== node) this.moveToHead(node);
|
|
1243
|
+
return node.value;
|
|
1244
|
+
}
|
|
1245
|
+
set(key, value) {
|
|
1246
|
+
const existing = this.map.get(key);
|
|
1247
|
+
if (existing !== void 0) {
|
|
1248
|
+
existing.value = value;
|
|
1249
|
+
if (this.head !== existing) this.moveToHead(existing);
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
const node = {
|
|
1253
|
+
key,
|
|
1254
|
+
prev: null,
|
|
1255
|
+
next: this.head,
|
|
1256
|
+
value
|
|
1257
|
+
};
|
|
1258
|
+
if (this.head) this.head.prev = node;
|
|
1259
|
+
this.head = node;
|
|
1260
|
+
if (!this.tail) this.tail = node;
|
|
1261
|
+
this.map.set(key, node);
|
|
1262
|
+
if (this.map.size > this.limit) this.evict();
|
|
1263
|
+
}
|
|
1264
|
+
delete(key) {
|
|
1265
|
+
const node = this.map.get(key);
|
|
1266
|
+
if (node === void 0) return;
|
|
1267
|
+
this.detach(node);
|
|
1268
|
+
this.map.delete(key);
|
|
1269
|
+
}
|
|
1270
|
+
keys() {
|
|
1271
|
+
return this.map.keys();
|
|
1272
|
+
}
|
|
1273
|
+
detach(node) {
|
|
1274
|
+
if (node.prev) node.prev.next = node.next;
|
|
1275
|
+
if (node.next) node.next.prev = node.prev;
|
|
1276
|
+
if (this.head === node) this.head = node.next;
|
|
1277
|
+
if (this.tail === node) this.tail = node.prev;
|
|
1278
|
+
node.prev = null;
|
|
1279
|
+
node.next = null;
|
|
1280
|
+
}
|
|
1281
|
+
moveToHead(node) {
|
|
1282
|
+
this.detach(node);
|
|
1283
|
+
node.next = this.head;
|
|
1284
|
+
if (this.head) this.head.prev = node;
|
|
1285
|
+
this.head = node;
|
|
1286
|
+
if (!this.tail) this.tail = node;
|
|
1287
|
+
}
|
|
1288
|
+
evict() {
|
|
1289
|
+
const node = this.tail;
|
|
1290
|
+
if (!node) return;
|
|
1291
|
+
this.detach(node);
|
|
1292
|
+
this.map.delete(node.key);
|
|
1293
|
+
if (this.onEvict) try {
|
|
1294
|
+
this.onEvict(node.key, node.value);
|
|
1295
|
+
} catch {}
|
|
1296
|
+
}
|
|
1297
|
+
clear() {
|
|
1298
|
+
this.map.clear();
|
|
1299
|
+
this.head = this.tail = null;
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
//#endregion
|
|
1881
1303
|
//#region src/parser/tokenizer.ts
|
|
1882
1304
|
const isWhitespace = (ch) => ch === " " || ch === "\n" || ch === " " || ch === "\r" || ch === "\f";
|
|
1883
1305
|
function scan(src, cb) {
|
|
@@ -2059,17 +1481,127 @@ var StyleParser = class {
|
|
|
2059
1481
|
//#endregion
|
|
2060
1482
|
//#region src/utils/is-dev-env.ts
|
|
2061
1483
|
/**
|
|
2062
|
-
* Check if we're in a development environment at runtime
|
|
2063
|
-
* Uses bracket notation to avoid bundler compilation
|
|
2064
|
-
* Also checks for TASTY_DEBUG localStorage setting
|
|
1484
|
+
* Check if we're in a development environment at runtime
|
|
1485
|
+
* Uses bracket notation to avoid bundler compilation
|
|
1486
|
+
* Also checks for TASTY_DEBUG localStorage setting
|
|
1487
|
+
*/
|
|
1488
|
+
function isDevEnv() {
|
|
1489
|
+
if (typeof window !== "undefined" && window.localStorage) try {
|
|
1490
|
+
const forceTastyDebug = window.localStorage.getItem("TASTY_DEBUG");
|
|
1491
|
+
if (forceTastyDebug !== null && forceTastyDebug.toLowerCase() === "true") return true;
|
|
1492
|
+
} catch {}
|
|
1493
|
+
if (typeof process === "undefined") return false;
|
|
1494
|
+
return true;
|
|
1495
|
+
}
|
|
1496
|
+
//#endregion
|
|
1497
|
+
//#region src/styles/shared.ts
|
|
1498
|
+
/**
|
|
1499
|
+
* If the group contains exactly one value that is a CSS-wide keyword
|
|
1500
|
+
* and no colors, return the keyword. Otherwise null.
|
|
1501
|
+
*
|
|
1502
|
+
* Direction mods (top/right/bottom/left) may coexist with the keyword
|
|
1503
|
+
* for directional application like `padding="inherit top"`.
|
|
1504
|
+
*/
|
|
1505
|
+
function extractCSSWideKeyword(group) {
|
|
1506
|
+
if (group.values.length !== 1 || group.colors.length > 0) return null;
|
|
1507
|
+
return CSS_WIDE_KEYWORDS.has(group.values[0]) ? group.values[0] : null;
|
|
1508
|
+
}
|
|
1509
|
+
/** A resolved custom-property reference, i.e. `var(--name)` or `var(--name, …)`. */
|
|
1510
|
+
const RE_VAR_REFERENCE = /^var\(/;
|
|
1511
|
+
/**
|
|
1512
|
+
* Assign custom-property references to the style and color slots of a
|
|
1513
|
+
* `<line-width> <line-style> <line-color>` shorthand (`border`, `outline`).
|
|
1514
|
+
*
|
|
1515
|
+
* The parser cannot type a reference, so it buckets `$name` as a plain value and
|
|
1516
|
+
* the handler has to place it. A reference fills the first slot still free, in
|
|
1517
|
+
* shorthand order: the width takes `values[0]`, then the style, then the color.
|
|
1518
|
+
* The style would otherwise arrive as a keyword (`solid`, `dashed`, …) that a
|
|
1519
|
+
* reference has no way to match, and the color as `#name` — the `$name-color`
|
|
1520
|
+
* form the parser buckets as a color exists to reference a raw CSS custom
|
|
1521
|
+
* property, not as the way colors are written, so a reference should not reach
|
|
1522
|
+
* for the color slot until the style slot is taken.
|
|
1523
|
+
*
|
|
1524
|
+
* Lengths are left alone: a second length is not valid in these shorthands, and
|
|
1525
|
+
* promoting one would emit an invalid declaration instead of ignoring an extra
|
|
1526
|
+
* value. Callers supply their own slot defaults.
|
|
1527
|
+
*/
|
|
1528
|
+
function assignLineSlots(values, styleKeyword, colorToken) {
|
|
1529
|
+
if (styleKeyword && colorToken) return {
|
|
1530
|
+
style: styleKeyword,
|
|
1531
|
+
color: colorToken
|
|
1532
|
+
};
|
|
1533
|
+
const spare = values.slice(1).filter((value) => RE_VAR_REFERENCE.test(value) && value !== colorToken);
|
|
1534
|
+
return {
|
|
1535
|
+
style: styleKeyword || spare.shift(),
|
|
1536
|
+
color: colorToken || spare.shift()
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
/** Warning keys already emitted, so each distinct offending value warns once. */
|
|
1540
|
+
const emittedWarnings$2 = /* @__PURE__ */ new Set();
|
|
1541
|
+
/** A resolved custom-property reference anywhere in a token. */
|
|
1542
|
+
const RE_HAS_VAR_REFERENCE = /var\(/;
|
|
1543
|
+
/**
|
|
1544
|
+
* Reject a custom-property reference used where a *token name* is expected.
|
|
1545
|
+
*
|
|
1546
|
+
* `preset` and `transition` take the name of a design token (`t3`, `fill`) and
|
|
1547
|
+
* interpolate it into a CSS custom property — `var(--t3-font-size)`. A reference
|
|
1548
|
+
* substituted into that position builds `var(--var(--x)-font-size)`, which is not
|
|
1549
|
+
* a valid custom-property name, so the browser drops the declaration and the
|
|
1550
|
+
* style silently does nothing. The DSL has no way to indirect a token name
|
|
1551
|
+
* through a custom property: the name is needed at build time, and a reference
|
|
1552
|
+
* only resolves in the browser.
|
|
1553
|
+
*
|
|
1554
|
+
* Returns true (warning once per value in dev) so the caller can fall back
|
|
1555
|
+
* instead of emitting a declaration that cannot work.
|
|
1556
|
+
*/
|
|
1557
|
+
function isTokenNameReference(property, name) {
|
|
1558
|
+
if (!RE_HAS_VAR_REFERENCE.test(name)) return false;
|
|
1559
|
+
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.`);
|
|
1560
|
+
return true;
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Emit a style-level warning at most once per `key`. No-op outside dev mode.
|
|
1564
|
+
*
|
|
1565
|
+
* Style handlers run once per state combination and their results are cached,
|
|
1566
|
+
* but the same value can arrive from many components, so dedupe is required.
|
|
1567
|
+
*
|
|
1568
|
+
* `isDevEnv()` is called lazily rather than captured at module load (the pattern
|
|
1569
|
+
* used in `config.ts` and `states/index.ts`) so that tests can enable it with
|
|
1570
|
+
* `vi.stubEnv('NODE_ENV', 'development')` — `isDevEnv()` returns `false` for
|
|
1571
|
+
* `NODE_ENV=test`, which is why every module-load-gated warning in this repo is
|
|
1572
|
+
* currently untestable. The key is registered *before* the dev check, so
|
|
1573
|
+
* production pays at most one `isDevEnv()` call per distinct offending value and
|
|
1574
|
+
* never touches the console.
|
|
1575
|
+
*/
|
|
1576
|
+
function warnOnceDev(key, message) {
|
|
1577
|
+
if (emittedWarnings$2.has(key)) return;
|
|
1578
|
+
emittedWarnings$2.add(key);
|
|
1579
|
+
if (!isDevEnv()) return;
|
|
1580
|
+
console.warn(`[Tasty] ${message}`);
|
|
1581
|
+
}
|
|
1582
|
+
/** Forget emitted style warnings. Called by `resetConfig()`; test isolation. */
|
|
1583
|
+
function resetStyleWarnings() {
|
|
1584
|
+
emittedWarnings$2.clear();
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Report a comma group that names direction modifiers together with more values
|
|
1588
|
+
* than the group can use.
|
|
1589
|
+
*
|
|
1590
|
+
* The parser buckets values and modifiers into separate arrays per comma group,
|
|
1591
|
+
* so `padding: '2x 4x top right'`, `padding: '2x top 4x right'` and
|
|
1592
|
+
* `padding: 'top 2x right 4x'` all reach a handler identically — the pairing a
|
|
1593
|
+
* reader infers from source order does not survive parsing. Such a group
|
|
1594
|
+
* therefore carries a single value, applied to every direction it names.
|
|
1595
|
+
*
|
|
1596
|
+
* `maxValues` is 2 only for a span modifier (`inset: '2x 4x bottom dock'`),
|
|
1597
|
+
* where the second value insets the sides the dock spans.
|
|
1598
|
+
*
|
|
1599
|
+
* Callers must guard on the count themselves so the valid path costs one integer
|
|
1600
|
+
* comparison; everything expensive happens here, on the misuse path only.
|
|
2065
1601
|
*/
|
|
2066
|
-
function
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
if (forceTastyDebug !== null && forceTastyDebug.toLowerCase() === "true") return true;
|
|
2070
|
-
} catch {}
|
|
2071
|
-
if (typeof process === "undefined") return false;
|
|
2072
|
-
return true;
|
|
1602
|
+
function warnExtraGroupValues(property, input, maxValues) {
|
|
1603
|
+
const message = maxValues === 2 ? `${property}="${input}": with a span modifier a group takes at most two values — one for the named edge and one for the spanned sides. The extra values are ignored.` : `${property}="${input}": a group that names directions takes a single value, applied to every direction it names. The extra values are ignored — use comma-separated groups instead, e.g. ${property}="2x top, 4x right".`;
|
|
1604
|
+
warnOnceDev(`extra-values:${property}:${input}`, message);
|
|
2073
1605
|
}
|
|
2074
1606
|
//#endregion
|
|
2075
1607
|
//#region src/plugins/color-func.ts
|
|
@@ -2089,7 +1621,9 @@ const parseAngle = (value) => {
|
|
|
2089
1621
|
}
|
|
2090
1622
|
};
|
|
2091
1623
|
/**
|
|
2092
|
-
* Parse a percentage value (e.g., "50%") to a 0-1 range.
|
|
1624
|
+
* Parse a percentage value (e.g., "50%") to a 0-1 range. A unitless number is
|
|
1625
|
+
* read as the factor it already looks like, so `okhsl(280 .8 .52)` and
|
|
1626
|
+
* `okhsl(280 80% 52%)` are the same color.
|
|
2093
1627
|
*/
|
|
2094
1628
|
const parsePercentage = (value) => {
|
|
2095
1629
|
const match = value.match(/^([+-]?\d*\.?\d+)%?$/);
|
|
@@ -2128,6 +1662,8 @@ function createColorFunc(name, convert, label) {
|
|
|
2128
1662
|
const h = parseAngle(tokens[0]);
|
|
2129
1663
|
const c2 = parsePercentage(tokens[1]);
|
|
2130
1664
|
const c3 = parsePercentage(tokens[2]);
|
|
1665
|
+
const misscaled = [tokens[1], tokens[2]].filter((raw, i) => !raw.includes("%") && (i === 0 ? c2 : c3) > 1);
|
|
1666
|
+
if (misscaled.length) warnOnceDev(`${name}:percent-scale`, `${name}(): channels are factors (0-1) or percentages, so ${misscaled.map((v) => `"${v}"`).join(" and ")} ${misscaled.length > 1 ? "clamp" : "clamps"} to 1 — add the missing '%', or write the value as a 0-1 number.`);
|
|
2131
1667
|
const [r, g, b] = convert(h, clamp(c2, 0, 1), clamp(c3, 0, 1));
|
|
2132
1668
|
const format = (n) => {
|
|
2133
1669
|
const pct = n * 100;
|
|
@@ -2264,22 +1800,35 @@ function normalizeColorTokenValue(value) {
|
|
|
2264
1800
|
return value;
|
|
2265
1801
|
}
|
|
2266
1802
|
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)[,)]/;
|
|
2268
1803
|
const RGB_ALPHA_PATTERN = /\/\s*([0-9.]+)\)/;
|
|
2269
1804
|
const RE_HEX_COLOR = /^#[0-9a-fA-F]{3,8}$/;
|
|
2270
1805
|
const RE_VAR_COLOR = /^var\(--[a-z0-9-]+-color/;
|
|
2271
1806
|
function isSimpleColorFast(val) {
|
|
2272
1807
|
switch (val.charCodeAt(0)) {
|
|
2273
1808
|
case 35: return RE_HEX_COLOR.test(val);
|
|
2274
|
-
case 114:
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
case
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
case
|
|
2281
|
-
|
|
1809
|
+
case 114:
|
|
1810
|
+
if (val.charCodeAt(1) === 103 && val.charCodeAt(2) === 98) return true;
|
|
1811
|
+
break;
|
|
1812
|
+
case 104:
|
|
1813
|
+
if (val.charCodeAt(1) === 115 && val.charCodeAt(2) === 108) return true;
|
|
1814
|
+
break;
|
|
1815
|
+
case 108:
|
|
1816
|
+
if (val.charCodeAt(1) === 99 && val.charCodeAt(2) === 104) return true;
|
|
1817
|
+
break;
|
|
1818
|
+
case 111:
|
|
1819
|
+
if (val.startsWith("oklch(")) return true;
|
|
1820
|
+
break;
|
|
1821
|
+
case 118:
|
|
1822
|
+
if (RE_VAR_COLOR.test(val)) return true;
|
|
1823
|
+
break;
|
|
1824
|
+
case 99:
|
|
1825
|
+
if (val === "currentColor" || val === "currentcolor") return true;
|
|
1826
|
+
break;
|
|
1827
|
+
case 116:
|
|
1828
|
+
if (val === "transparent") return true;
|
|
1829
|
+
break;
|
|
2282
1830
|
}
|
|
1831
|
+
return getNamedColorHex().has(val.toLowerCase());
|
|
2283
1832
|
}
|
|
2284
1833
|
let colorWarningCount = 0;
|
|
2285
1834
|
const MAX_COLOR_WARNINGS = 10;
|
|
@@ -2456,8 +2005,7 @@ function parseColor(val, ignoreError = false) {
|
|
|
2456
2005
|
}
|
|
2457
2006
|
const faded = parseAlphaOverride(firstColor);
|
|
2458
2007
|
const baseColor = faded ? faded.color : firstColor;
|
|
2459
|
-
|
|
2460
|
-
if (!nameMatch) nameMatch = baseColor.match(COLOR_VAR_COMPONENTS_PATTERN);
|
|
2008
|
+
const nameMatch = baseColor.match(COLOR_VAR_PATTERN);
|
|
2461
2009
|
let opacity;
|
|
2462
2010
|
if (faded) {
|
|
2463
2011
|
const { alpha } = faded;
|
|
@@ -3224,7 +2772,6 @@ function getEffectiveDefinition(token, userDefinition) {
|
|
|
3224
2772
|
if (!parsed.isValid) return {
|
|
3225
2773
|
cssName: "",
|
|
3226
2774
|
definition: userDefinition,
|
|
3227
|
-
isColor: false,
|
|
3228
2775
|
isValid: false,
|
|
3229
2776
|
error: parsed.error
|
|
3230
2777
|
};
|
|
@@ -3235,13 +2782,11 @@ function getEffectiveDefinition(token, userDefinition) {
|
|
|
3235
2782
|
inherits: userDefinition.inherits,
|
|
3236
2783
|
initialValue: userDefinition.initialValue ?? "transparent"
|
|
3237
2784
|
},
|
|
3238
|
-
isColor: true,
|
|
3239
2785
|
isValid: true
|
|
3240
2786
|
};
|
|
3241
2787
|
return {
|
|
3242
2788
|
cssName: parsed.cssName,
|
|
3243
2789
|
definition: userDefinition,
|
|
3244
|
-
isColor: false,
|
|
3245
2790
|
isValid: true
|
|
3246
2791
|
};
|
|
3247
2792
|
}
|
|
@@ -3643,10 +3188,6 @@ function resetStyleBatch() {
|
|
|
3643
3188
|
*/
|
|
3644
3189
|
const CUSTOM_PROP_DECL = /^\s*(--[a-z0-9_-]+)\s*:\s*(.+?)\s*$/i;
|
|
3645
3190
|
const SINGLE_VAR_REF = /^var\((--[a-z0-9_-]+)\)$/i;
|
|
3646
|
-
/** A `--name-color-{space}` companion holding a color's channel components. */
|
|
3647
|
-
const COLOR_COMPONENTS_DECL = /^\s*(--[a-z0-9_-]+-color-(?:rgb|hsl|oklch))\s*:\s*(.+?)\s*$/i;
|
|
3648
|
-
/** A component list the browser can type as `<number>+`. */
|
|
3649
|
-
const NUMERIC_COMPONENTS = /^[\d\s.+-]+$/;
|
|
3650
3191
|
var PropertyTypeResolver = class {
|
|
3651
3192
|
/** propName → the prop it depends on */
|
|
3652
3193
|
pendingDeps = /* @__PURE__ */ new Map();
|
|
@@ -3659,15 +3200,6 @@ var PropertyTypeResolver = class {
|
|
|
3659
3200
|
scanDeclarations(declarations, isPropertyDefined, registerProperty) {
|
|
3660
3201
|
if (!declarations.includes("--")) return;
|
|
3661
3202
|
const parts = declarations.split(/;+/);
|
|
3662
|
-
for (const part of parts) {
|
|
3663
|
-
const match = COLOR_COMPONENTS_DECL.exec(part);
|
|
3664
|
-
if (!match) continue;
|
|
3665
|
-
const propName = match[1];
|
|
3666
|
-
if (isPropertyDefined(propName)) continue;
|
|
3667
|
-
if (NUMERIC_COMPONENTS.test(match[2])) continue;
|
|
3668
|
-
if (isPropertyDefined(propName.slice(0, propName.lastIndexOf("-")))) continue;
|
|
3669
|
-
registerProperty(propName, "*", getDefaultComponents());
|
|
3670
|
-
}
|
|
3671
3203
|
for (const part of parts) {
|
|
3672
3204
|
if (!part.trim()) continue;
|
|
3673
3205
|
const match = CUSTOM_PROP_DECL.exec(part);
|
|
@@ -3747,116 +3279,6 @@ const BORDER_STYLES = [
|
|
|
3747
3279
|
"outset"
|
|
3748
3280
|
];
|
|
3749
3281
|
//#endregion
|
|
3750
|
-
//#region src/styles/shared.ts
|
|
3751
|
-
/**
|
|
3752
|
-
* If the group contains exactly one value that is a CSS-wide keyword
|
|
3753
|
-
* and no colors, return the keyword. Otherwise null.
|
|
3754
|
-
*
|
|
3755
|
-
* Direction mods (top/right/bottom/left) may coexist with the keyword
|
|
3756
|
-
* for directional application like `padding="inherit top"`.
|
|
3757
|
-
*/
|
|
3758
|
-
function extractCSSWideKeyword(group) {
|
|
3759
|
-
if (group.values.length !== 1 || group.colors.length > 0) return null;
|
|
3760
|
-
return CSS_WIDE_KEYWORDS.has(group.values[0]) ? group.values[0] : null;
|
|
3761
|
-
}
|
|
3762
|
-
/** A resolved custom-property reference, i.e. `var(--name)` or `var(--name, …)`. */
|
|
3763
|
-
const RE_VAR_REFERENCE = /^var\(/;
|
|
3764
|
-
/**
|
|
3765
|
-
* Assign custom-property references to the style and color slots of a
|
|
3766
|
-
* `<line-width> <line-style> <line-color>` shorthand (`border`, `outline`).
|
|
3767
|
-
*
|
|
3768
|
-
* The parser cannot type a reference, so it buckets `$name` as a plain value and
|
|
3769
|
-
* the handler has to place it. A reference fills the first slot still free, in
|
|
3770
|
-
* shorthand order: the width takes `values[0]`, then the style, then the color.
|
|
3771
|
-
* The style would otherwise arrive as a keyword (`solid`, `dashed`, …) that a
|
|
3772
|
-
* reference has no way to match, and the color as `#name` — the `$name-color`
|
|
3773
|
-
* form the parser buckets as a color exists to reference a raw CSS custom
|
|
3774
|
-
* property, not as the way colors are written, so a reference should not reach
|
|
3775
|
-
* for the color slot until the style slot is taken.
|
|
3776
|
-
*
|
|
3777
|
-
* Lengths are left alone: a second length is not valid in these shorthands, and
|
|
3778
|
-
* promoting one would emit an invalid declaration instead of ignoring an extra
|
|
3779
|
-
* value. Callers supply their own slot defaults.
|
|
3780
|
-
*/
|
|
3781
|
-
function assignLineSlots(values, styleKeyword, colorToken) {
|
|
3782
|
-
if (styleKeyword && colorToken) return {
|
|
3783
|
-
style: styleKeyword,
|
|
3784
|
-
color: colorToken
|
|
3785
|
-
};
|
|
3786
|
-
const spare = values.slice(1).filter((value) => RE_VAR_REFERENCE.test(value) && value !== colorToken);
|
|
3787
|
-
return {
|
|
3788
|
-
style: styleKeyword || spare.shift(),
|
|
3789
|
-
color: colorToken || spare.shift()
|
|
3790
|
-
};
|
|
3791
|
-
}
|
|
3792
|
-
/** Warning keys already emitted, so each distinct offending value warns once. */
|
|
3793
|
-
const emittedWarnings$2 = /* @__PURE__ */ new Set();
|
|
3794
|
-
/** A resolved custom-property reference anywhere in a token. */
|
|
3795
|
-
const RE_HAS_VAR_REFERENCE = /var\(/;
|
|
3796
|
-
/**
|
|
3797
|
-
* Reject a custom-property reference used where a *token name* is expected.
|
|
3798
|
-
*
|
|
3799
|
-
* `preset` and `transition` take the name of a design token (`t3`, `fill`) and
|
|
3800
|
-
* interpolate it into a CSS custom property — `var(--t3-font-size)`. A reference
|
|
3801
|
-
* substituted into that position builds `var(--var(--x)-font-size)`, which is not
|
|
3802
|
-
* a valid custom-property name, so the browser drops the declaration and the
|
|
3803
|
-
* style silently does nothing. The DSL has no way to indirect a token name
|
|
3804
|
-
* through a custom property: the name is needed at build time, and a reference
|
|
3805
|
-
* only resolves in the browser.
|
|
3806
|
-
*
|
|
3807
|
-
* Returns true (warning once per value in dev) so the caller can fall back
|
|
3808
|
-
* instead of emitting a declaration that cannot work.
|
|
3809
|
-
*/
|
|
3810
|
-
function isTokenNameReference(property, name) {
|
|
3811
|
-
if (!RE_HAS_VAR_REFERENCE.test(name)) return false;
|
|
3812
|
-
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.`);
|
|
3813
|
-
return true;
|
|
3814
|
-
}
|
|
3815
|
-
/**
|
|
3816
|
-
* Emit a style-level warning at most once per `key`. No-op outside dev mode.
|
|
3817
|
-
*
|
|
3818
|
-
* Style handlers run once per state combination and their results are cached,
|
|
3819
|
-
* but the same value can arrive from many components, so dedupe is required.
|
|
3820
|
-
*
|
|
3821
|
-
* `isDevEnv()` is called lazily rather than captured at module load (the pattern
|
|
3822
|
-
* used in `config.ts` and `states/index.ts`) so that tests can enable it with
|
|
3823
|
-
* `vi.stubEnv('NODE_ENV', 'development')` — `isDevEnv()` returns `false` for
|
|
3824
|
-
* `NODE_ENV=test`, which is why every module-load-gated warning in this repo is
|
|
3825
|
-
* currently untestable. The key is registered *before* the dev check, so
|
|
3826
|
-
* production pays at most one `isDevEnv()` call per distinct offending value and
|
|
3827
|
-
* never touches the console.
|
|
3828
|
-
*/
|
|
3829
|
-
function warnOnceDev(key, message) {
|
|
3830
|
-
if (emittedWarnings$2.has(key)) return;
|
|
3831
|
-
emittedWarnings$2.add(key);
|
|
3832
|
-
if (!isDevEnv()) return;
|
|
3833
|
-
console.warn(`[Tasty] ${message}`);
|
|
3834
|
-
}
|
|
3835
|
-
/** Forget emitted style warnings. Called by `resetConfig()`; test isolation. */
|
|
3836
|
-
function resetStyleWarnings() {
|
|
3837
|
-
emittedWarnings$2.clear();
|
|
3838
|
-
}
|
|
3839
|
-
/**
|
|
3840
|
-
* Report a comma group that names direction modifiers together with more values
|
|
3841
|
-
* than the group can use.
|
|
3842
|
-
*
|
|
3843
|
-
* The parser buckets values and modifiers into separate arrays per comma group,
|
|
3844
|
-
* so `padding: '2x 4x top right'`, `padding: '2x top 4x right'` and
|
|
3845
|
-
* `padding: 'top 2x right 4x'` all reach a handler identically — the pairing a
|
|
3846
|
-
* reader infers from source order does not survive parsing. Such a group
|
|
3847
|
-
* therefore carries a single value, applied to every direction it names.
|
|
3848
|
-
*
|
|
3849
|
-
* `maxValues` is 2 only for a span modifier (`inset: '2x 4x bottom dock'`),
|
|
3850
|
-
* where the second value insets the sides the dock spans.
|
|
3851
|
-
*
|
|
3852
|
-
* Callers must guard on the count themselves so the valid path costs one integer
|
|
3853
|
-
* comparison; everything expensive happens here, on the misuse path only.
|
|
3854
|
-
*/
|
|
3855
|
-
function warnExtraGroupValues(property, input, maxValues) {
|
|
3856
|
-
const message = maxValues === 2 ? `${property}="${input}": with a span modifier a group takes at most two values — one for the named edge and one for the spanned sides. The extra values are ignored.` : `${property}="${input}": a group that names directions takes a single value, applied to every direction it names. The extra values are ignored — use comma-separated groups instead, e.g. ${property}="2x top, 4x right".`;
|
|
3857
|
-
warnOnceDev(`extra-values:${property}:${input}`, message);
|
|
3858
|
-
}
|
|
3859
|
-
//#endregion
|
|
3860
3282
|
//#region src/styles/border.ts
|
|
3861
3283
|
/**
|
|
3862
3284
|
* Process a single group and return border values for its directions.
|
|
@@ -3971,21 +3393,19 @@ function borderStyle({ border }) {
|
|
|
3971
3393
|
borderStyle.__lookupStyles = ["border"];
|
|
3972
3394
|
//#endregion
|
|
3973
3395
|
//#region src/styles/color.ts
|
|
3396
|
+
/**
|
|
3397
|
+
* A color that already resolves against the color the element inherits, and so
|
|
3398
|
+
* must not be republished as `--current-color`: a descendant reading the
|
|
3399
|
+
* variable would resolve it a second time against its own color. Covers the
|
|
3400
|
+
* keyword and the variable alike — the latter would also be a self-reference.
|
|
3401
|
+
*/
|
|
3402
|
+
const RE_READS_CURRENT = /var\(--current-color[,)]|currentcolor/i;
|
|
3974
3403
|
function colorStyle({ color }) {
|
|
3975
3404
|
if (!color) return null;
|
|
3976
3405
|
if (color === true) color = "currentColor";
|
|
3977
3406
|
color = parseColor(color, true).color || resolveCustomProperties(color);
|
|
3978
|
-
const match = color.match(/var\(--(.+?)-color/);
|
|
3979
|
-
let name = "";
|
|
3980
|
-
if (match) name = match[1];
|
|
3981
3407
|
const styles = { color };
|
|
3982
|
-
if (
|
|
3983
|
-
const suffix = getColorSpaceSuffix();
|
|
3984
|
-
Object.assign(styles, {
|
|
3985
|
-
"--current-color": color,
|
|
3986
|
-
[`--current-color-${suffix}`]: convertColorChainToComponentChain(color)
|
|
3987
|
-
});
|
|
3988
|
-
}
|
|
3408
|
+
if (!RE_READS_CURRENT.test(color)) styles["--current-color"] = color;
|
|
3989
3409
|
return styles;
|
|
3990
3410
|
}
|
|
3991
3411
|
colorStyle.__lookupStyles = ["color"];
|
|
@@ -4015,31 +3435,7 @@ function createStyle(styleName, cssStyle, converter) {
|
|
|
4015
3435
|
}
|
|
4016
3436
|
if (typeof styleValue === "string" && finalCssStyle.startsWith("--") && finalCssStyle.endsWith("-color")) {
|
|
4017
3437
|
styleValue = styleValue.trim();
|
|
4018
|
-
|
|
4019
|
-
const colorSpaceStr = strToColorSpace(styleValue);
|
|
4020
|
-
const { color, name } = parseColor(styleValue);
|
|
4021
|
-
if (name && colorSpaceStr) return {
|
|
4022
|
-
[finalCssStyle]: `var(--${name}-color, ${colorSpaceStr})`,
|
|
4023
|
-
[`${finalCssStyle}-${suffix}`]: `var(--${name}-color-${suffix}, ${getColorSpaceComponents(colorSpaceStr)})`
|
|
4024
|
-
};
|
|
4025
|
-
else if (name) {
|
|
4026
|
-
if (color) return {
|
|
4027
|
-
[finalCssStyle]: color,
|
|
4028
|
-
[`${finalCssStyle}-${suffix}`]: convertColorChainToComponentChain(color)
|
|
4029
|
-
};
|
|
4030
|
-
return {
|
|
4031
|
-
[finalCssStyle]: `var(--${name}-color)`,
|
|
4032
|
-
[`${finalCssStyle}-${suffix}`]: `var(--${name}-color-${suffix})`
|
|
4033
|
-
};
|
|
4034
|
-
} else if (colorSpaceStr) return {
|
|
4035
|
-
[finalCssStyle]: colorSpaceStr,
|
|
4036
|
-
[`${finalCssStyle}-${suffix}`]: getColorSpaceComponents(colorSpaceStr)
|
|
4037
|
-
};
|
|
4038
|
-
if (color && colorFuncName(color)) return {
|
|
4039
|
-
[finalCssStyle]: color,
|
|
4040
|
-
[`${finalCssStyle}-${suffix}`]: convertColorChainToComponentChain(color)
|
|
4041
|
-
};
|
|
4042
|
-
return { [finalCssStyle]: color ?? "" };
|
|
3438
|
+
return { [finalCssStyle]: parseColor(styleValue).color ?? "" };
|
|
4043
3439
|
}
|
|
4044
3440
|
const processed = parseStyle(styleValue);
|
|
4045
3441
|
return { [finalCssStyle]: processed.output };
|
|
@@ -5644,7 +5040,7 @@ var SheetManager = class {
|
|
|
5644
5040
|
} : void 0;
|
|
5645
5041
|
registry = {
|
|
5646
5042
|
sheets: [],
|
|
5647
|
-
|
|
5043
|
+
pinCounts: /* @__PURE__ */ new Map(),
|
|
5648
5044
|
rules: /* @__PURE__ */ new Map(),
|
|
5649
5045
|
cacheKeyToClassName: /* @__PURE__ */ new Map(),
|
|
5650
5046
|
ruleTextSet: /* @__PURE__ */ new Set(),
|
|
@@ -5658,10 +5054,9 @@ var SheetManager = class {
|
|
|
5658
5054
|
injectedFunctions: /* @__PURE__ */ new Map(),
|
|
5659
5055
|
globalRules: /* @__PURE__ */ new Map(),
|
|
5660
5056
|
propertyTypeResolver: new PropertyTypeResolver(),
|
|
5661
|
-
|
|
5057
|
+
unusedSince: /* @__PURE__ */ new Map(),
|
|
5058
|
+
localKeyframes: /* @__PURE__ */ new Map(),
|
|
5662
5059
|
touchCount: 0,
|
|
5663
|
-
touchTick: -1,
|
|
5664
|
-
touchedTick: /* @__PURE__ */ new Set(),
|
|
5665
5060
|
serverClassSyncIndex: 0,
|
|
5666
5061
|
rscStylesScanned: false,
|
|
5667
5062
|
injectionMode: this.detectInjectionMode(root)
|
|
@@ -6043,25 +5438,26 @@ var SheetManager = class {
|
|
|
6043
5438
|
return registry.atPropertySupported;
|
|
6044
5439
|
}
|
|
6045
5440
|
/**
|
|
6046
|
-
*
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
*
|
|
5441
|
+
* Delete the given classes: their rules leave the sheets and every registry
|
|
5442
|
+
* entry pointing at them is dropped.
|
|
5443
|
+
*
|
|
5444
|
+
* Deciding *what* is unused belongs to `StyleInjector.gc()`, which owns the
|
|
5445
|
+
* DOM scan and the capacity policy. This only re-checks that each class is
|
|
5446
|
+
* still safe to delete, and reports how many were.
|
|
5447
|
+
*
|
|
5448
|
+
* @returns Number of classes actually deleted.
|
|
6053
5449
|
*/
|
|
6054
|
-
|
|
5450
|
+
deleteClasses(registry, classNames) {
|
|
6055
5451
|
const cleanupStartTime = Date.now();
|
|
6056
|
-
const
|
|
6057
|
-
if (unusedClassNames.length === 0) return;
|
|
6058
|
-
const selected = unusedClassNames.map((className) => {
|
|
5452
|
+
const selected = Array.from(classNames).map((className) => {
|
|
6059
5453
|
const ruleInfo = registry.rules.get(className);
|
|
6060
5454
|
return ruleInfo ? {
|
|
6061
5455
|
className,
|
|
6062
5456
|
ruleInfo
|
|
6063
5457
|
} : null;
|
|
6064
5458
|
}).filter((entry) => entry != null);
|
|
5459
|
+
if (selected.length === 0) return 0;
|
|
5460
|
+
const deleted = /* @__PURE__ */ new Set();
|
|
6065
5461
|
let cleanedUpCount = 0;
|
|
6066
5462
|
let totalCssSize = 0;
|
|
6067
5463
|
let totalRulesDeleted = 0;
|
|
@@ -6082,7 +5478,7 @@ var SheetManager = class {
|
|
|
6082
5478
|
for (const [_sheetIndex, rulesInSheet] of rulesBySheet) {
|
|
6083
5479
|
rulesInSheet.sort((a, b) => b.ruleInfo.ruleIndex - a.ruleInfo.ruleIndex);
|
|
6084
5480
|
for (const { className, ruleInfo } of rulesInSheet) {
|
|
6085
|
-
if ((registry.
|
|
5481
|
+
if ((registry.pinCounts.get(className) ?? 0) > 0) continue;
|
|
6086
5482
|
if (registry.rules.get(className) !== ruleInfo) continue;
|
|
6087
5483
|
const sheetInfo = registry.sheets[ruleInfo.sheetIndex];
|
|
6088
5484
|
if (!sheetInfo || !sheetInfo.sheet && !sheetInfo.constructableSheet) continue;
|
|
@@ -6094,13 +5490,22 @@ var SheetManager = class {
|
|
|
6094
5490
|
if (startIdx < 0 || endIdx > maxRuleIndex || startIdx > endIdx) continue;
|
|
6095
5491
|
this.deleteRule(registry, ruleInfo);
|
|
6096
5492
|
registry.rules.delete(className);
|
|
6097
|
-
registry.
|
|
6098
|
-
|
|
6099
|
-
for (const [key,
|
|
6100
|
-
|
|
5493
|
+
registry.pinCounts.delete(className);
|
|
5494
|
+
registry.unusedSince.delete(className);
|
|
5495
|
+
for (const [key, entry] of registry.localKeyframes) {
|
|
5496
|
+
if (!entry.owners.delete(className)) continue;
|
|
5497
|
+
if (entry.owners.size === 0) {
|
|
5498
|
+
entry.dispose();
|
|
5499
|
+
registry.localKeyframes.delete(key);
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
deleted.add(className);
|
|
6101
5503
|
cleanedUpCount++;
|
|
6102
5504
|
}
|
|
6103
5505
|
}
|
|
5506
|
+
if (deleted.size > 0) {
|
|
5507
|
+
for (const [key, mappedClassName] of registry.cacheKeyToClassName) if (deleted.has(mappedClassName)) registry.cacheKeyToClassName.delete(key);
|
|
5508
|
+
}
|
|
6104
5509
|
if (registry.metrics) {
|
|
6105
5510
|
registry.metrics.bulkCleanups++;
|
|
6106
5511
|
registry.metrics.stylesCleanedUp += cleanedUpCount;
|
|
@@ -6111,6 +5516,7 @@ var SheetManager = class {
|
|
|
6111
5516
|
rulesDeleted: totalRulesDeleted
|
|
6112
5517
|
});
|
|
6113
5518
|
}
|
|
5519
|
+
return cleanedUpCount;
|
|
6114
5520
|
}
|
|
6115
5521
|
/**
|
|
6116
5522
|
* Get total number of rules across all sheets
|
|
@@ -6145,10 +5551,9 @@ var SheetManager = class {
|
|
|
6145
5551
|
*/
|
|
6146
5552
|
getMetrics(registry) {
|
|
6147
5553
|
if (!registry.metrics) return null;
|
|
6148
|
-
const unusedRulesCount = Array.from(registry.refCounts.values()).filter((count) => count === 0).length;
|
|
6149
5554
|
return {
|
|
6150
5555
|
...registry.metrics,
|
|
6151
|
-
unusedHits:
|
|
5556
|
+
unusedHits: 0
|
|
6152
5557
|
};
|
|
6153
5558
|
}
|
|
6154
5559
|
/**
|
|
@@ -6572,6 +5977,13 @@ function formatCounterStyleRule(name, descriptors) {
|
|
|
6572
5977
|
//#endregion
|
|
6573
5978
|
//#region src/injector/injector.ts
|
|
6574
5979
|
/**
|
|
5980
|
+
* How long a class is left alone after it was last known to be wanted.
|
|
5981
|
+
* Long enough that a render cannot plausibly still be waiting to commit one.
|
|
5982
|
+
*/
|
|
5983
|
+
const DEFAULT_GC_GRACE = 1e4;
|
|
5984
|
+
/** Dispose handle handed back for injections that took no pin. */
|
|
5985
|
+
const noop = () => {};
|
|
5986
|
+
/**
|
|
6575
5987
|
* Placeholder `KeyframesInfo` for a cache entry reserved by a batched write and
|
|
6576
5988
|
* not yet backed by a real rule. Only ever read through `entry.pending`, which
|
|
6577
5989
|
* is checked before the info is used.
|
|
@@ -6628,13 +6040,14 @@ function registerHydratedClass(registry, className) {
|
|
|
6628
6040
|
ruleIndex: -2,
|
|
6629
6041
|
sheetIndex: -2
|
|
6630
6042
|
});
|
|
6631
|
-
registry.
|
|
6043
|
+
registry.pinCounts.set(className, 0);
|
|
6632
6044
|
}
|
|
6633
6045
|
var StyleInjector = class {
|
|
6634
6046
|
sheetManager;
|
|
6635
6047
|
config;
|
|
6636
6048
|
globalRuleCounter = 0;
|
|
6637
|
-
|
|
6049
|
+
/** Cancels the scheduled sweep, whichever timer scheduled it. */
|
|
6050
|
+
cancelPendingGC = null;
|
|
6638
6051
|
namePrefix;
|
|
6639
6052
|
classRegex;
|
|
6640
6053
|
rscClassRegex;
|
|
@@ -6763,6 +6176,7 @@ var StyleInjector = class {
|
|
|
6763
6176
|
inject(rules, options) {
|
|
6764
6177
|
const root = options?.root || document;
|
|
6765
6178
|
const registry = this.sheetManager.getRegistry(root);
|
|
6179
|
+
const pin = options?.pin ?? true;
|
|
6766
6180
|
if (rules.length === 0) return {
|
|
6767
6181
|
className: "",
|
|
6768
6182
|
dispose: () => {}
|
|
@@ -6773,30 +6187,34 @@ var StyleInjector = class {
|
|
|
6773
6187
|
className = registry.cacheKeyToClassName.get(cacheKey);
|
|
6774
6188
|
const existingRuleInfo = registry.rules.get(className);
|
|
6775
6189
|
if (existingRuleInfo.ruleIndex === -3) {
|
|
6776
|
-
registry.
|
|
6190
|
+
registry.unusedSince.delete(className);
|
|
6191
|
+
if (pin) registry.pinCounts.set(className, (registry.pinCounts.get(className) || 0) + 1);
|
|
6777
6192
|
if (registry.metrics) registry.metrics.hits++;
|
|
6778
6193
|
return {
|
|
6779
6194
|
className,
|
|
6780
|
-
dispose: () => this.
|
|
6195
|
+
dispose: pin ? () => this.unpin(className, registry) : noop
|
|
6781
6196
|
};
|
|
6782
6197
|
}
|
|
6783
6198
|
if (!(existingRuleInfo.ruleIndex === -1 && existingRuleInfo.sheetIndex === -1)) {
|
|
6784
|
-
|
|
6785
|
-
|
|
6199
|
+
registry.unusedSince.delete(className);
|
|
6200
|
+
if (pin) {
|
|
6201
|
+
const pins = registry.pinCounts.get(className) || 0;
|
|
6202
|
+
registry.pinCounts.set(className, pins + 1);
|
|
6203
|
+
}
|
|
6786
6204
|
if (registry.metrics) registry.metrics.hits++;
|
|
6787
6205
|
return {
|
|
6788
6206
|
className,
|
|
6789
|
-
dispose: () => this.
|
|
6207
|
+
dispose: pin ? () => this.unpin(className, registry) : noop
|
|
6790
6208
|
};
|
|
6791
6209
|
}
|
|
6792
6210
|
} else if (cacheKey) {
|
|
6793
6211
|
className = this.generateClassName(cacheKey);
|
|
6794
6212
|
if (this.tryHydratedHit(registry, cacheKey, className)) {
|
|
6795
|
-
registry.
|
|
6213
|
+
if (pin) registry.pinCounts.set(className, (registry.pinCounts.get(className) || 0) + 1);
|
|
6796
6214
|
if (registry.metrics) registry.metrics.hits++;
|
|
6797
6215
|
return {
|
|
6798
6216
|
className,
|
|
6799
|
-
dispose: () => this.
|
|
6217
|
+
dispose: pin ? () => this.unpin(className, registry) : noop
|
|
6800
6218
|
};
|
|
6801
6219
|
}
|
|
6802
6220
|
} else {
|
|
@@ -6857,7 +6275,8 @@ var StyleInjector = class {
|
|
|
6857
6275
|
sheetIndex: -3
|
|
6858
6276
|
});
|
|
6859
6277
|
if (cacheKey) registry.cacheKeyToClassName.set(cacheKey, className);
|
|
6860
|
-
registry.
|
|
6278
|
+
if (pin) registry.pinCounts.set(className, 1);
|
|
6279
|
+
registry.unusedSince.set(className, Date.now());
|
|
6861
6280
|
const queued = enqueueStyleWrite(() => {
|
|
6862
6281
|
if (applySheetWrite()) return;
|
|
6863
6282
|
registry.rules.set(className, {
|
|
@@ -6868,26 +6287,27 @@ var StyleInjector = class {
|
|
|
6868
6287
|
});
|
|
6869
6288
|
return {
|
|
6870
6289
|
className,
|
|
6871
|
-
dispose: () => {
|
|
6872
|
-
if (!queued.done && registry.
|
|
6290
|
+
dispose: pin ? () => {
|
|
6291
|
+
if (!queued.done && registry.pinCounts.get(className) === 1 && registry.rules.get(className)?.ruleIndex === -3) {
|
|
6873
6292
|
queued.cancelled = true;
|
|
6874
6293
|
registry.rules.delete(className);
|
|
6875
6294
|
if (cacheKey) registry.cacheKeyToClassName.delete(cacheKey);
|
|
6876
|
-
registry.
|
|
6295
|
+
registry.pinCounts.set(className, 0);
|
|
6877
6296
|
return;
|
|
6878
6297
|
}
|
|
6879
|
-
this.
|
|
6880
|
-
}
|
|
6298
|
+
this.unpin(className, registry);
|
|
6299
|
+
} : noop
|
|
6881
6300
|
};
|
|
6882
6301
|
}
|
|
6883
6302
|
if (!applySheetWrite()) return {
|
|
6884
6303
|
className,
|
|
6885
6304
|
dispose: () => {}
|
|
6886
6305
|
};
|
|
6887
|
-
registry.
|
|
6306
|
+
if (pin) registry.pinCounts.set(className, 1);
|
|
6307
|
+
registry.unusedSince.set(className, Date.now());
|
|
6888
6308
|
return {
|
|
6889
6309
|
className,
|
|
6890
|
-
dispose: () => this.
|
|
6310
|
+
dispose: pin ? () => this.unpin(className, registry) : noop
|
|
6891
6311
|
};
|
|
6892
6312
|
}
|
|
6893
6313
|
/**
|
|
@@ -6967,41 +6387,95 @@ var StyleInjector = class {
|
|
|
6967
6387
|
return this.sheetManager.getRawCSSText(root);
|
|
6968
6388
|
}
|
|
6969
6389
|
/**
|
|
6970
|
-
*
|
|
6971
|
-
*
|
|
6972
|
-
*
|
|
6973
|
-
*
|
|
6390
|
+
* Take a reference on local `@keyframes` and report what they ended up being
|
|
6391
|
+
* called, without deciding yet which classes own them.
|
|
6392
|
+
*
|
|
6393
|
+
* Names have to be resolved before the rules that animate them are written:
|
|
6394
|
+
* an injected name can differ from the authored one, and a rule written
|
|
6395
|
+
* first cannot be rewritten afterwards — its cache key is already claimed,
|
|
6396
|
+
* so the second write is a hit and the corrected declarations are dropped.
|
|
6397
|
+
*
|
|
6398
|
+
* One reference per distinct set of steps, shared by every class that ends up
|
|
6399
|
+
* animating it, so a repeat render takes nothing further. Ownership is
|
|
6400
|
+
* assigned by `ownKeyframes()` once the rules exist to be inspected.
|
|
6401
|
+
*/
|
|
6402
|
+
holdKeyframes(steps, options) {
|
|
6403
|
+
const root = options?.root || document;
|
|
6404
|
+
const registry = this.sheetManager.getRegistry(root);
|
|
6405
|
+
const names = /* @__PURE__ */ new Map();
|
|
6406
|
+
const keys = /* @__PURE__ */ new Map();
|
|
6407
|
+
for (const [authored, definition] of Object.entries(steps)) {
|
|
6408
|
+
const key = `${authored}\u0000${JSON.stringify(definition)}`;
|
|
6409
|
+
let entry = registry.localKeyframes.get(key);
|
|
6410
|
+
if (!entry) {
|
|
6411
|
+
const injected = this.keyframes(definition, {
|
|
6412
|
+
name: authored,
|
|
6413
|
+
root
|
|
6414
|
+
});
|
|
6415
|
+
entry = {
|
|
6416
|
+
name: injected.toString(),
|
|
6417
|
+
dispose: injected.dispose,
|
|
6418
|
+
owners: /* @__PURE__ */ new Set()
|
|
6419
|
+
};
|
|
6420
|
+
registry.localKeyframes.set(key, entry);
|
|
6421
|
+
}
|
|
6422
|
+
keys.set(authored, key);
|
|
6423
|
+
names.set(authored, entry.name);
|
|
6424
|
+
}
|
|
6425
|
+
return {
|
|
6426
|
+
names,
|
|
6427
|
+
keys
|
|
6428
|
+
};
|
|
6429
|
+
}
|
|
6430
|
+
/**
|
|
6431
|
+
* Record that `className` animates these keyframes, so the reference is
|
|
6432
|
+
* released when the last such class is collected.
|
|
6433
|
+
*
|
|
6434
|
+
* Only classes whose rules actually reference the animation should be here:
|
|
6435
|
+
* a class that merely rendered alongside one would otherwise keep the
|
|
6436
|
+
* keyframes alive for as long as it lives.
|
|
6437
|
+
*/
|
|
6438
|
+
ownKeyframes(key, className, options) {
|
|
6439
|
+
this.sheetManager.getRegistry(options?.root || document).localKeyframes.get(key)?.owners.add(className);
|
|
6440
|
+
}
|
|
6441
|
+
/**
|
|
6442
|
+
* Pin an already-injected cacheKey and return the handle that releases it.
|
|
6443
|
+
* For callers that skipped the pipeline on a cache hit but still need the
|
|
6444
|
+
* class held. Returns null if the cacheKey is not found.
|
|
6974
6445
|
*/
|
|
6975
6446
|
trackRef(cacheKey, options) {
|
|
6976
6447
|
const root = options?.root || document;
|
|
6977
6448
|
const registry = this.sheetManager.getRegistry(root);
|
|
6978
6449
|
if (!registry.cacheKeyToClassName.has(cacheKey)) return null;
|
|
6979
6450
|
const className = registry.cacheKeyToClassName.get(cacheKey);
|
|
6980
|
-
const
|
|
6981
|
-
registry.
|
|
6451
|
+
const pins = registry.pinCounts.get(className) || 0;
|
|
6452
|
+
registry.pinCounts.set(className, pins + 1);
|
|
6982
6453
|
if (registry.metrics) registry.metrics.hits++;
|
|
6983
6454
|
return {
|
|
6984
6455
|
className,
|
|
6985
|
-
dispose: () => this.
|
|
6456
|
+
dispose: () => this.unpin(className, registry)
|
|
6986
6457
|
};
|
|
6987
6458
|
}
|
|
6988
6459
|
/**
|
|
6989
|
-
*
|
|
6460
|
+
* Release one pin on a className. At zero pins the class is not deleted — it
|
|
6461
|
+
* stays cached and collectible, and `gc()` decides when it actually goes.
|
|
6990
6462
|
*/
|
|
6991
|
-
|
|
6992
|
-
const
|
|
6993
|
-
if (
|
|
6994
|
-
const
|
|
6995
|
-
registry.
|
|
6996
|
-
if (
|
|
6463
|
+
unpin(className, registry) {
|
|
6464
|
+
const pins = registry.pinCounts.get(className);
|
|
6465
|
+
if (pins == null || pins <= 0) return;
|
|
6466
|
+
const remaining = pins - 1;
|
|
6467
|
+
registry.pinCounts.set(className, remaining);
|
|
6468
|
+
if (remaining === 0 && registry.metrics) registry.metrics.totalUnused++;
|
|
6997
6469
|
}
|
|
6998
6470
|
/**
|
|
6999
|
-
*
|
|
6471
|
+
* Remove every style that is neither in the DOM nor referenced by an
|
|
6472
|
+
* outstanding `inject()` handle, ignoring the GC capacity threshold.
|
|
7000
6473
|
*/
|
|
7001
6474
|
cleanup(root) {
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
6475
|
+
this.gc({
|
|
6476
|
+
root,
|
|
6477
|
+
force: true
|
|
6478
|
+
});
|
|
7005
6479
|
}
|
|
7006
6480
|
/**
|
|
7007
6481
|
* Get CSS text from all sheets (for SSR)
|
|
@@ -7044,7 +6518,9 @@ var StyleInjector = class {
|
|
|
7044
6518
|
flushStyles();
|
|
7045
6519
|
const root = options?.root || document;
|
|
7046
6520
|
const registry = this.sheetManager.getRegistry(root);
|
|
7047
|
-
|
|
6521
|
+
const metrics = this.sheetManager.getMetrics(registry);
|
|
6522
|
+
if (metrics && typeof document !== "undefined") metrics.unusedHits = this.collectUnused(registry, root).length;
|
|
6523
|
+
return metrics;
|
|
7048
6524
|
}
|
|
7049
6525
|
/**
|
|
7050
6526
|
* Reset cache performance metrics
|
|
@@ -7085,15 +6561,6 @@ var StyleInjector = class {
|
|
|
7085
6561
|
const cssName = effectiveResult.cssName;
|
|
7086
6562
|
const definition = effectiveResult.definition;
|
|
7087
6563
|
this.insertPropertyRule(registry, root, cssName, definition, name);
|
|
7088
|
-
if (effectiveResult.isColor) {
|
|
7089
|
-
const companionCssName = `${cssName}-${getColorSpaceSuffix()}`;
|
|
7090
|
-
const companionDefinition = {
|
|
7091
|
-
syntax: getComponentPropertySyntax(),
|
|
7092
|
-
inherits: definition.inherits,
|
|
7093
|
-
initialValue: colorInitialValueToComponents(definition.initialValue)
|
|
7094
|
-
};
|
|
7095
|
-
this.insertPropertyRule(registry, root, companionCssName, companionDefinition, `${name}:components`);
|
|
7096
|
-
}
|
|
7097
6564
|
}
|
|
7098
6565
|
/**
|
|
7099
6566
|
* Build and insert a single `@property` rule into the given registry.
|
|
@@ -7325,108 +6792,132 @@ var StyleInjector = class {
|
|
|
7325
6792
|
}
|
|
7326
6793
|
}
|
|
7327
6794
|
/**
|
|
7328
|
-
*
|
|
7329
|
-
*
|
|
7330
|
-
*
|
|
7331
|
-
*
|
|
7332
|
-
*
|
|
6795
|
+
* Count a render, and schedule a collection pass every `touchInterval` of
|
|
6796
|
+
* them. Nothing else: what a class is worth keeping is decided by the sweep's
|
|
6797
|
+
* own DOM scan, so rendering does not track usage at all.
|
|
6798
|
+
*
|
|
6799
|
+
* @deprecated The class name is ignored — pass anything, or stop calling it.
|
|
6800
|
+
* Collection no longer records per-class usage, and scheduling does not need
|
|
6801
|
+
* to know which class was rendered. A class handed back by `inject()` is
|
|
6802
|
+
* marked wanted there, which is what reuse actually goes through.
|
|
7333
6803
|
*/
|
|
7334
|
-
touch(
|
|
6804
|
+
touch(_className, options) {
|
|
7335
6805
|
if (typeof document === "undefined") return;
|
|
7336
6806
|
if (!this.config.gc) return;
|
|
7337
|
-
const
|
|
7338
|
-
|
|
7339
|
-
const now = Date.now();
|
|
7340
|
-
if (registry.touchTick !== now) {
|
|
7341
|
-
registry.touchTick = now;
|
|
7342
|
-
registry.touchedTick.clear();
|
|
7343
|
-
} else if (registry.touchedTick.has(className)) return;
|
|
7344
|
-
registry.touchedTick.add(className);
|
|
7345
|
-
const parts = className.indexOf(" ") === -1 ? [className] : className.split(" ");
|
|
7346
|
-
for (const cls of parts) {
|
|
7347
|
-
if (!this.classRegex.test(cls)) continue;
|
|
7348
|
-
if (!registry.rules.has(cls)) continue;
|
|
7349
|
-
const entry = registry.usageMap.get(cls);
|
|
7350
|
-
if (entry) entry.lastTouchedAt = now;
|
|
7351
|
-
else registry.usageMap.set(cls, { lastTouchedAt: now });
|
|
7352
|
-
registry.touchCount++;
|
|
7353
|
-
}
|
|
7354
|
-
const touchInterval = this.config.gc.touchInterval ?? 1e3;
|
|
7355
|
-
if (registry.touchCount >= touchInterval) {
|
|
6807
|
+
const registry = this.sheetManager.getRegistry(options?.root || document);
|
|
6808
|
+
if (++registry.touchCount >= (this.config.gc.touchInterval ?? 1e3)) {
|
|
7356
6809
|
registry.touchCount = 0;
|
|
7357
6810
|
this.scheduleGC();
|
|
7358
6811
|
}
|
|
7359
6812
|
}
|
|
7360
6813
|
/**
|
|
7361
|
-
* Schedule a GC
|
|
7362
|
-
*
|
|
6814
|
+
* Schedule a GC in idle time. Runs GC on all active roots, and avoids
|
|
6815
|
+
* double-scheduling.
|
|
6816
|
+
*
|
|
6817
|
+
* Idle only. Without `requestIdleCallback` nothing is collected
|
|
6818
|
+
* automatically: running the sweep inline here would put it inside the render
|
|
6819
|
+
* that touched the class, and collection is never urgent enough for that.
|
|
7363
6820
|
*/
|
|
7364
6821
|
scheduleGC() {
|
|
7365
|
-
if (this.
|
|
6822
|
+
if (this.cancelPendingGC) return;
|
|
7366
6823
|
const runGC = () => {
|
|
7367
|
-
this.
|
|
6824
|
+
this.cancelPendingGC = null;
|
|
7368
6825
|
this.sheetManager.pruneDisconnectedRoots();
|
|
7369
6826
|
for (const root of this.sheetManager.getActiveRoots()) this.gc({ root });
|
|
7370
6827
|
};
|
|
7371
|
-
if (typeof requestIdleCallback !== "undefined")
|
|
7372
|
-
|
|
6828
|
+
if (typeof requestIdleCallback !== "undefined") {
|
|
6829
|
+
const handle = requestIdleCallback(() => runGC());
|
|
6830
|
+
this.cancelPendingGC = () => cancelIdleCallback(handle);
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
/**
|
|
6834
|
+
* The one definition of "unused": this injector owns the class's rules, no
|
|
6835
|
+
* element in `root` carries it, and nobody pinned it.
|
|
6836
|
+
*
|
|
6837
|
+
* `gc()` evicts from this set, `getMetrics()` counts it, and `tastyDebug`
|
|
6838
|
+
* reports it — all through here, so the three can never disagree about what
|
|
6839
|
+
* "unused" means. Entries carry their last `touch()` so callers can drop the
|
|
6840
|
+
* oldest first; a class that was never touched sorts as oldest.
|
|
6841
|
+
*/
|
|
6842
|
+
/**
|
|
6843
|
+
* Everything the injector holds falls into one of five bands, and only the
|
|
6844
|
+
* last of them is ever deleted:
|
|
6845
|
+
*
|
|
6846
|
+
* 1. rendered — some element carries the class right now
|
|
6847
|
+
* 2. not ours — queued for a batched write, pre-allocated, or server-rendered
|
|
6848
|
+
* 3. hot — nothing carries it, but that was noticed less than `grace` ago
|
|
6849
|
+
* 4. cached — cold, but within `capacity` when ordered by when it went cold
|
|
6850
|
+
* 5. the rest
|
|
6851
|
+
*
|
|
6852
|
+
* This returns bands 4 and 5 together, most recently cold first; `gc()` draws
|
|
6853
|
+
* the capacity line through them. Band 3 is what makes collection safe
|
|
6854
|
+
* without a commit signal: a render can resolve a class and commit it a
|
|
6855
|
+
* little later, and during that gap nothing on the page carries it.
|
|
6856
|
+
*/
|
|
6857
|
+
collectUnused(registry, root) {
|
|
6858
|
+
const now = Date.now();
|
|
6859
|
+
const grace = this.config.gc?.grace ?? DEFAULT_GC_GRACE;
|
|
6860
|
+
const liveClasses = /* @__PURE__ */ new Set();
|
|
6861
|
+
for (const el of root.querySelectorAll("[class]")) for (const token of el.classList) if (this.classRegex.test(token)) liveClasses.add(token);
|
|
6862
|
+
const unused = [];
|
|
6863
|
+
for (const [className, ruleInfo] of registry.rules) {
|
|
6864
|
+
if (ruleInfo.sheetIndex < 0) continue;
|
|
6865
|
+
if (liveClasses.has(className)) {
|
|
6866
|
+
registry.unusedSince.delete(className);
|
|
6867
|
+
continue;
|
|
6868
|
+
}
|
|
6869
|
+
if ((registry.pinCounts.get(className) ?? 0) > 0) continue;
|
|
6870
|
+
let since = registry.unusedSince.get(className);
|
|
6871
|
+
if (since === void 0) {
|
|
6872
|
+
since = now;
|
|
6873
|
+
registry.unusedSince.set(className, now);
|
|
6874
|
+
}
|
|
6875
|
+
if (now - since < grace) continue;
|
|
6876
|
+
unused.push(className);
|
|
6877
|
+
}
|
|
6878
|
+
unused.sort((a, b) => (registry.unusedSince.get(b) ?? 0) - (registry.unusedSince.get(a) ?? 0));
|
|
6879
|
+
return unused;
|
|
6880
|
+
}
|
|
6881
|
+
/**
|
|
6882
|
+
* Class names this injector holds CSS for that nothing renders and nobody
|
|
6883
|
+
* pinned — exactly what `gc({ force: true })` would delete. Unordered.
|
|
6884
|
+
*/
|
|
6885
|
+
getUnusedClasses(options) {
|
|
6886
|
+
flushStyles();
|
|
6887
|
+
if (typeof document === "undefined") return [];
|
|
6888
|
+
const root = options?.root || document;
|
|
6889
|
+
const registry = this.sheetManager.getRegistry(root);
|
|
6890
|
+
return this.collectUnused(registry, root);
|
|
7373
6891
|
}
|
|
7374
6892
|
/**
|
|
7375
6893
|
* Synchronous garbage collection.
|
|
7376
6894
|
*
|
|
7377
|
-
* 1. Quick upper-bound check: skip if
|
|
7378
|
-
* 2. Scans the DOM for live tasty classNames
|
|
7379
|
-
*
|
|
7380
|
-
*
|
|
6895
|
+
* 1. Quick upper-bound check: skip if the registry is smaller than capacity.
|
|
6896
|
+
* 2. Scans the DOM for live tasty classNames — the DOM, not a ref count, is
|
|
6897
|
+
* what says a class rendered by a component is still in use.
|
|
6898
|
+
* 3. With `force: true`: deletes every unused class.
|
|
6899
|
+
* Without `force`: keeps the `capacity` most recently touched and deletes
|
|
6900
|
+
* the rest, oldest first.
|
|
7381
6901
|
*
|
|
7382
6902
|
* @returns Number of styles evicted.
|
|
7383
6903
|
*/
|
|
7384
6904
|
gc(options) {
|
|
7385
6905
|
flushStyles();
|
|
7386
6906
|
if (typeof document === "undefined") return 0;
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
this.pendingGCHandle = null;
|
|
7390
|
-
}
|
|
6907
|
+
this.cancelPendingGC?.();
|
|
6908
|
+
this.cancelPendingGC = null;
|
|
7391
6909
|
const root = options?.root || document;
|
|
7392
|
-
const force = options?.force
|
|
6910
|
+
const force = options?.force;
|
|
7393
6911
|
const registry = this.sheetManager.getRegistry(root);
|
|
7394
6912
|
const capacity = this.config.gc?.capacity ?? 1e3;
|
|
7395
|
-
if (!force)
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
if (force) for (const [className] of registry.usageMap) {
|
|
7404
|
-
if (liveClasses.has(className)) continue;
|
|
7405
|
-
if ((registry.refCounts.get(className) ?? 0) > 0) continue;
|
|
7406
|
-
registry.usageMap.delete(className);
|
|
7407
|
-
swept++;
|
|
7408
|
-
}
|
|
7409
|
-
else {
|
|
7410
|
-
const unused = [];
|
|
7411
|
-
for (const [className, usage] of registry.usageMap) {
|
|
7412
|
-
if (liveClasses.has(className)) continue;
|
|
7413
|
-
if ((registry.refCounts.get(className) ?? 0) > 0) continue;
|
|
7414
|
-
unused.push({
|
|
7415
|
-
className,
|
|
7416
|
-
lastTouchedAt: usage.lastTouchedAt
|
|
7417
|
-
});
|
|
7418
|
-
}
|
|
7419
|
-
if (unused.length > capacity) {
|
|
7420
|
-
unused.sort((a, b) => a.lastTouchedAt - b.lastTouchedAt);
|
|
7421
|
-
const toEvict = unused.length - capacity;
|
|
7422
|
-
for (let i = 0; i < toEvict; i++) {
|
|
7423
|
-
registry.usageMap.delete(unused[i].className);
|
|
7424
|
-
swept++;
|
|
7425
|
-
}
|
|
7426
|
-
}
|
|
7427
|
-
}
|
|
7428
|
-
if (swept > 0) this.sheetManager.forceCleanup(registry);
|
|
7429
|
-
return swept;
|
|
6913
|
+
if (!force && registry.rules.size <= capacity) return 0;
|
|
6914
|
+
const unused = this.collectUnused(registry, root);
|
|
6915
|
+
let doomed;
|
|
6916
|
+
if (force) doomed = unused;
|
|
6917
|
+
else if (unused.length > capacity) doomed = unused.slice(capacity);
|
|
6918
|
+
else return 0;
|
|
6919
|
+
if (doomed.length === 0) return 0;
|
|
6920
|
+
return this.sheetManager.deleteClasses(registry, doomed);
|
|
7430
6921
|
}
|
|
7431
6922
|
/**
|
|
7432
6923
|
* Destroy all resources for a root
|
|
@@ -7435,9 +6926,9 @@ var StyleInjector = class {
|
|
|
7435
6926
|
flushStyles();
|
|
7436
6927
|
const targetRoot = root || document;
|
|
7437
6928
|
this.sheetManager.cleanup(targetRoot);
|
|
7438
|
-
if (this.
|
|
7439
|
-
|
|
7440
|
-
this.
|
|
6929
|
+
if (this.cancelPendingGC && !this.sheetManager.hasActiveRoots()) {
|
|
6930
|
+
this.cancelPendingGC();
|
|
6931
|
+
this.cancelPendingGC = null;
|
|
7441
6932
|
}
|
|
7442
6933
|
}
|
|
7443
6934
|
};
|
|
@@ -12208,7 +11699,7 @@ const DEFAULT_PROPERTIES = {
|
|
|
12208
11699
|
},
|
|
12209
11700
|
"#current": {
|
|
12210
11701
|
inherits: true,
|
|
12211
|
-
initialValue: "
|
|
11702
|
+
initialValue: "currentcolor"
|
|
12212
11703
|
},
|
|
12213
11704
|
"#white": {
|
|
12214
11705
|
inherits: true,
|
|
@@ -12758,10 +12249,7 @@ function configure(config = {}) {
|
|
|
12758
12249
|
const tokenKeys = new Set(Object.keys(mergedConfigTokens));
|
|
12759
12250
|
for (const key of Object.keys(mergedReplaceTokens)) if (tokenKeys.has(key)) warnOnce(`token-conflict-${key}`, `[Tasty] Token "${key}" is defined in both \`tokens\` and \`replaceTokens\`. \`replaceTokens\` performs parse-time substitution, so the \`tokens\` CSS custom property will be injected but never used by Tasty styles. Remove it from one of the two.`);
|
|
12760
12251
|
}
|
|
12761
|
-
if (config.colorSpace) {
|
|
12762
|
-
setColorSpace(config.colorSpace);
|
|
12763
|
-
getGlobalParser().clearCache();
|
|
12764
|
-
}
|
|
12252
|
+
if (config.colorSpace) warnOnce("colorSpace-deprecated", "[Tasty] configure({ colorSpace }) no longer has any effect and will be removed in the next major. Colors are emitted as authored, and opacity is applied with relative color syntax, which reads a color's channels in the browser. To address channels yourself, write `oklch(from var(--name-color) l c h)` against the token.");
|
|
12765
12253
|
if (Object.keys(mergedStates).length > 0) setGlobalPredefinedStates(mergedStates);
|
|
12766
12254
|
const parser = getGlobalParser();
|
|
12767
12255
|
if (config.parserCacheSize !== void 0) parser.updateOptions({ cacheSize: config.parserCacheSize });
|
|
@@ -12873,7 +12361,6 @@ function resetConfig() {
|
|
|
12873
12361
|
resetStyleChunks();
|
|
12874
12362
|
resetPropHandlers();
|
|
12875
12363
|
resetBaseStyleProps();
|
|
12876
|
-
resetColorSpace();
|
|
12877
12364
|
clearPipelineCache();
|
|
12878
12365
|
emittedWarnings.clear();
|
|
12879
12366
|
resetStyleWarnings();
|
|
@@ -12881,6 +12368,6 @@ function resetConfig() {
|
|
|
12881
12368
|
delete storage[GLOBAL_INJECTOR_KEY];
|
|
12882
12369
|
}
|
|
12883
12370
|
//#endregion
|
|
12884
|
-
export { SheetManager as $,
|
|
12371
|
+
export { SheetManager as $, StyleParser as $t, FLOW_STYLES as A, STYLE_TO_CHUNK as At, createStateParserContext as B, getGlobalParseFunctions as Bt, BASE_STYLES as C, APPEARANCE_CHUNK_STYLES as Ct, COLOR_STYLES as D, FONT_CHUNK_STYLES as Dt, BLOCK_STYLES as E, DISPLAY_CHUNK_STYLES as Et, hasPipelineCacheEntry as F, registerFunctionPolyfill as Ft, StyleInjector as G, parseStyle as Gt, extractPredefinedStateRefs as H, getGlobalPredefinedTokens as Ht, isSelector as I, registerLocalFunctionPolyfills as It, hasLocalCounterStyle as J, okhstPlugin as Jt, extractLocalCounterStyle as K, stringifyStyles as Kt, renderStyles as L, CUSTOM_UNITS as Lt, OUTER_STYLES as M, formatFunctionRule as Mt, POSITION_STYLES as N, hasLocalFunctions as Nt, CONTAINER_STYLES as O, LAYOUT_CHUNK_STYLES as Ot, TEXT_STYLES as P, parseFunctionName as Pt, hasLocalFontFace as Q, isDevEnv as Qt, parseStateKey as R, DIRECTIONS as Rt, baseStylePropsRegistry as S, propHandlerRegistry as St, BLOCK_OUTER_STYLES as T, DIMENSION_CHUNK_STYLES as Tt, getGlobalPredefinedStates as U, normalizeColorTokenValue as Ut, extractLocalPredefinedStates as V, getGlobalParser as Vt, setGlobalPredefinedStates as W, parseColor as Wt, fontFaceContentHash as X, okhslPlugin as Xt, extractLocalFontFace as Y, okhslFunction as Yt, formatFontFaceRule as Z, createColorFunc as Zt, isFunctionsPolyfillEnabled as _, hashString as _t, getGlobalCounterStyles as a, hslToRgbValues as an, closeBatchWindow as at, resetConfig as b, hasLocalProperties as bt, getGlobalInjector as c, openBatchWindow as ct, getGlobalStyles as d, DEFAULT_ZERO_NAME_PREFIX as dt, Lru as en, STYLE_HANDLER_MAP as et, getNamePrefix as f, makeClassName as ft, isConfigLocked as g, validateNamePrefix as gt, hasStylesGenerated as h, tastyClassRegex as ht, getGlobalConfigTokens as i, hexToRgb as in, PropertyTypeResolver as it, INNER_STYLES as j, extractLocalFunctions as jt, DIMENSION_STYLES as k, POSITION_CHUNK_STYLES as kt, getGlobalKeyframes as l, resetStyleBatch as lt, hasGlobalRecipes as m, makeKeyframeName as mt, getConfig as n, getNamedColorHex as nn, styleHandlers as nt, getGlobalFontFaces as o, strToRgb as on, flushStyles as ot, hasGlobalKeyframes as p, makeCounterStyleName as pt, formatCounterStyleRule as q, okhstFunction as qt, getEffectiveProperties as r, getRgbValuesFromRgbaString as rn, createStyle as rt, getGlobalFunctions as s, normalizeDslName as sn, hasPendingStyleWrites as st, configure as t, overrideColorAlpha as tn, defineHandler as tt, getGlobalRecipes as u, DEFAULT_NAME_PREFIX as ut, isTestEnvironment as v, extractLocalProperties as vt, BLOCK_INNER_STYLES as w, CHUNK_NAMES as wt, generateTypographyTokens as x, parsePropertyToken as xt, markStylesGenerated as y, getEffectiveDefinition as yt, camelToKebab as z, filterMods as zt };
|
|
12885
12372
|
|
|
12886
|
-
//# sourceMappingURL=config-
|
|
12373
|
+
//# sourceMappingURL=config-DsqqkmUs.js.map
|