unocss-preset-magicolor 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/color-variable-Dd9ag2au.js +237 -0
  2. package/dist/helper.js +90 -39
  3. package/dist/index.js +1046 -375
  4. package/dist/types/color-variable-DL1w3SBY.d.ts +22 -0
  5. package/dist/types/helper.d.ts +34 -5
  6. package/dist/types/index-DKupNIgs.d.ts +13 -0
  7. package/dist/types/index-nfSJL16M.d.ts +41 -0
  8. package/dist/types/index.d.ts +11 -5
  9. package/dist/types/preflights/index.d.ts +8 -3
  10. package/dist/types/rules/color-style-rule.d.ts +9 -0
  11. package/dist/types/rules/index.d.ts +11 -2
  12. package/dist/types/rules/mc-lr-rule.d.ts +8 -0
  13. package/dist/types/rules/mc-variable-rule.d.ts +8 -0
  14. package/dist/types/rules/unocss-utils/bg-gradient.d.ts +8 -0
  15. package/dist/types/rules/unocss-utils/border.d.ts +8 -0
  16. package/dist/types/rules/unocss-utils/index.d.ts +6 -0
  17. package/dist/types/rules/unocss-utils/mask.d.ts +8 -0
  18. package/dist/types/rules/unocss-utils/shadow.d.ts +8 -0
  19. package/dist/types/rules/unocss-utils/utilities.d.ts +20 -0
  20. package/dist/types/test/helpers.d.ts +32 -0
  21. package/dist/types/types-BAC-LRjs.d.ts +31 -0
  22. package/dist/types/types-BXcRfLw_.d.ts +6 -0
  23. package/dist/types/types.d.ts +2 -5
  24. package/dist/types/typing-CBKHz6jA.d.ts +13 -0
  25. package/dist/types/typing.d.ts +2 -2
  26. package/dist/types/usages/cache.d.ts +34 -0
  27. package/dist/types/usages/index.d.ts +3 -0
  28. package/dist/types/usages/scanner.d.ts +14 -0
  29. package/dist/types/usages/shortcuts.d.ts +11 -0
  30. package/dist/types/usages/types.d.ts +2 -0
  31. package/dist/types/utils/color-config.d.ts +18 -0
  32. package/dist/types/utils/color-references.d.ts +18 -0
  33. package/dist/types/utils/color-variable.d.ts +2 -0
  34. package/dist/types/utils/dev-cache-token.d.ts +16 -0
  35. package/dist/types/utils/theme-colors.d.ts +17 -0
  36. package/package.json +7 -4
  37. package/dist/common-Dv0krm1V.js +0 -59
  38. package/dist/types/rules/color-style.d.ts +0 -3
  39. package/dist/types/rules/color-variable.d.ts +0 -2
  40. package/dist/types/rules/utils/bg-gradient.d.ts +0 -3
  41. package/dist/types/rules/utils/border.d.ts +0 -3
  42. package/dist/types/rules/utils/index.d.ts +0 -6
  43. package/dist/types/rules/utils/mask.d.ts +0 -3
  44. package/dist/types/rules/utils/shadow.d.ts +0 -3
  45. package/dist/types/rules/utils/theme-colors.d.ts +0 -10
  46. package/dist/types/rules/utils/utilities.d.ts +0 -16
  47. package/dist/types/utils/common.d.ts +0 -20
  48. package/dist/types/utils/index.d.ts +0 -2
  49. package/dist/types/utils/transforms.d.ts +0 -7
@@ -0,0 +1,237 @@
1
+ import { SpecialColorKey } from "@unocss/preset-wind4/utils";
2
+ import { mc } from "magic-color";
3
+ //#region ../utils/src/color.ts
4
+ const specialColorValueMap = new Map(Object.entries(SpecialColorKey).flatMap(([key, value]) => [[key.toLowerCase(), value], [value.toLowerCase(), value]]));
5
+ const depthColorRE = /^(?:(.*)-|(.+\D))(\d+)$/;
6
+ const bracketColorRE = /^\[(.*)\]$/;
7
+ const numericBodyRE = /^-?\d+$/;
8
+ function emptyColorParts() {
9
+ return {
10
+ originColor: void 0,
11
+ originDepth: void 0
12
+ };
13
+ }
14
+ function getBodyColorEnd(color) {
15
+ let bracketDepth = 0;
16
+ let parenDepth = 0;
17
+ let escaped = false;
18
+ for (let i = 0; i < color.length; i++) {
19
+ const char = color[i];
20
+ if (escaped) {
21
+ escaped = false;
22
+ continue;
23
+ }
24
+ if (char === "\\") {
25
+ escaped = true;
26
+ continue;
27
+ }
28
+ if (char === "[") bracketDepth++;
29
+ else if (char === "]") bracketDepth = Math.max(bracketDepth - 1, 0);
30
+ else if (char === "(" && bracketDepth === 0) parenDepth++;
31
+ else if (char === ")" && bracketDepth === 0) parenDepth = Math.max(parenDepth - 1, 0);
32
+ if ((char === ":" || char === "/") && bracketDepth === 0 && parenDepth === 0) return i;
33
+ }
34
+ return color.length;
35
+ }
36
+ function resolveBodyColorDepth(color) {
37
+ if (color.startsWith("#") && !color.includes("-")) return {
38
+ originColor: color,
39
+ originDepth: void 0
40
+ };
41
+ const depthMatch = color.match(depthColorRE);
42
+ const rawOriginColor = depthMatch?.[1] ?? depthMatch?.[2] ?? color;
43
+ const originDepth = depthMatch?.[3];
44
+ const originColor = rawOriginColor.match(bracketColorRE)?.[1] ?? rawOriginColor;
45
+ if (!originColor || numericBodyRE.test(originColor)) return emptyColorParts();
46
+ return {
47
+ originColor,
48
+ originDepth
49
+ };
50
+ }
51
+ /**
52
+ * Resolves a token body into its source color and optional depth,
53
+ * ignoring opacity (`/`) and modifier (`:`) suffixes outside brackets/functions.
54
+ */
55
+ function resolveBodyColor(body) {
56
+ if (!body) return emptyColorParts();
57
+ const color = body.trim();
58
+ const bodyColor = color.slice(0, getBodyColorEnd(color));
59
+ if (!bodyColor || numericBodyRE.test(bodyColor)) return emptyColorParts();
60
+ return resolveBodyColorDepth(bodyColor);
61
+ }
62
+ /** Resolves UnoCSS special color keywords to their canonical CSS values. */
63
+ function resolveSpecialColor(color) {
64
+ if (!color) return;
65
+ return specialColorValueMap.get(color.trim().toLowerCase());
66
+ }
67
+ /** Checks whether a raw selector contains the `dark:` variant. */
68
+ function hasDarkVariant(rawSelector) {
69
+ return rawSelector?.split(":").includes("dark") === true;
70
+ }
71
+ //#endregion
72
+ //#region ../utils/src/transforms.ts
73
+ /** Converts a string or number to a numeric value, falling back to 0. */
74
+ function toNum(value) {
75
+ if (!value) return 0;
76
+ return Number.parseFloat(value.toString()) || 0;
77
+ }
78
+ /** Normalizes a parsed CSS color into numeric OKLCH components. */
79
+ function toOklch(cssColor) {
80
+ if (!cssColor) return;
81
+ if (cssColor.type === "oklch") {
82
+ let components = cssColor.components;
83
+ if (components.length === 1 && typeof components[0] === "string") components = components[0].split(/\s*,\s*|\s+/).filter(Boolean);
84
+ if (components.length < 3) return;
85
+ const numericComponents = components.map((value, index) => index === 0 && value.toString().includes("%") ? toNum(value) / 100 : toNum(value));
86
+ return {
87
+ ...cssColor,
88
+ components: numericComponents
89
+ };
90
+ }
91
+ const oklchColor = mc(cssColor.type === "hex" ? cssColor.components[0].toString() : cssColor.components, cssColor.type).toOklch().values;
92
+ if (!oklchColor) return;
93
+ return {
94
+ type: "oklch",
95
+ components: [
96
+ oklchColor[0] / 100,
97
+ oklchColor[1],
98
+ oklchColor[2]
99
+ ],
100
+ alpha: cssColor.alpha
101
+ };
102
+ }
103
+ /** Rounds a number to three decimal places. */
104
+ function roundNum(num) {
105
+ return Math.round(num * 1e3) / 1e3;
106
+ }
107
+ /** Narrows away null and undefined values in array filters. */
108
+ function notNull(value) {
109
+ return value != null;
110
+ }
111
+ //#endregion
112
+ //#region ../utils/src/theme.ts
113
+ const themeMetaList = [
114
+ 50,
115
+ 100,
116
+ 200,
117
+ 300,
118
+ 400,
119
+ 500,
120
+ 600,
121
+ 700,
122
+ 800,
123
+ 900,
124
+ 950
125
+ ];
126
+ /**
127
+ * Builds a partial theme-depth color map from a valid source color.
128
+ *
129
+ * Invalid colors return an empty map so generation can continue safely.
130
+ */
131
+ function getMcThemeMetaColors(originColor) {
132
+ const themeMetaColors = {};
133
+ if (!originColor || !mc.valid(originColor)) return themeMetaColors;
134
+ try {
135
+ const themeColor = mc.theme(originColor, { type: "hex" });
136
+ for (const themeMeta of themeMetaList) {
137
+ const hex = themeColor[themeMeta];
138
+ if (!hex) continue;
139
+ const cssColor = toOklch({
140
+ type: "hex",
141
+ components: [hex],
142
+ alpha: 1
143
+ });
144
+ if (cssColor) themeMetaColors[themeMeta] = cssColor;
145
+ }
146
+ } catch {
147
+ console.error("[magic-color] Failed to generate themeMeta colors for", originColor);
148
+ }
149
+ return themeMetaColors;
150
+ }
151
+ function stringifyOklchColor(cssColor) {
152
+ const color = toOklch(cssColor);
153
+ if (!color) return;
154
+ const components = color.components.map((value) => roundNum(toNum(value)));
155
+ const alpha = color.alpha != null && color.alpha !== 1 ? ` / ${color.alpha}` : "";
156
+ return `oklch(${components.join(" ")}${alpha})`;
157
+ }
158
+ function resolveThemeDepth(options = {}) {
159
+ const { defaultValue, depth, lightnessReverse } = options;
160
+ const originDepth = Number(depth);
161
+ if (!Number.isFinite(originDepth)) return defaultValue;
162
+ if (lightnessReverse) return 1e3 - originDepth;
163
+ return originDepth;
164
+ }
165
+ function resolveDepth(no, options = {}) {
166
+ let originDepth = resolveThemeDepth({
167
+ depth: no,
168
+ ...options
169
+ });
170
+ if (typeof originDepth !== "number") return;
171
+ originDepth = originDepth <= 50 ? 50 : originDepth;
172
+ originDepth = originDepth >= 950 ? 950 : originDepth;
173
+ let beforeDepth = Math.floor(originDepth / 100) * 100;
174
+ beforeDepth = beforeDepth <= 50 ? 50 : beforeDepth;
175
+ let afterDepth = Math.floor((originDepth + 100) / 100) * 100;
176
+ afterDepth = afterDepth >= 950 ? 950 : afterDepth;
177
+ return {
178
+ originDepth,
179
+ beforeDepth,
180
+ afterDepth
181
+ };
182
+ }
183
+ /** Resolves or interpolates the OKLCH color for a requested theme depth. */
184
+ function getThemeDepthColor(themeMetaColors, no, options = {}) {
185
+ const depth = resolveDepth(no, options);
186
+ if (!depth) return;
187
+ const { originDepth, beforeDepth, afterDepth } = depth;
188
+ const originColor = themeMetaColors[originDepth];
189
+ if (originColor) return stringifyOklchColor(originColor);
190
+ const beforeColor = themeMetaColors[beforeDepth];
191
+ const afterColor = themeMetaColors[afterDepth];
192
+ if (!beforeColor || !afterColor) return;
193
+ const beforeComponents = beforeColor.components;
194
+ const afterComponents = afterColor.components;
195
+ if (beforeComponents.length < 3 || afterComponents.length < 3) return;
196
+ const transitionRatio = (originDepth - beforeDepth) / (originDepth < 100 || originDepth > 900 ? 50 : 100);
197
+ return `oklch(${Array.from({ length: 3 }).map((_, i) => {
198
+ return roundNum(toNum(beforeComponents[i]) + (toNum(afterComponents[i]) - toNum(beforeComponents[i])) * transitionRatio);
199
+ }).join(" ")})`;
200
+ }
201
+ //#endregion
202
+ //#region src/utils/color-variable.ts
203
+ const BASE_COLOR_DEPTH = "DEFAULT";
204
+ /** Builds the public target CSS custom property name for a magic color depth. */
205
+ function createTargetColorVariableName(name, depth = BASE_COLOR_DEPTH) {
206
+ return `--mc-colors-${name}-${depth}`;
207
+ }
208
+ /** Builds the internal source CSS custom property name for a magic color depth. */
209
+ function createSourceColorVariableName(name, depth = BASE_COLOR_DEPTH) {
210
+ return `--mc-source-colors-${name}-${depth}`;
211
+ }
212
+ /** Wraps a CSS custom property name in a var() reference. */
213
+ function toVar(variableName) {
214
+ return `var(${variableName})`;
215
+ }
216
+ /** Creates a single target CSS custom property declaration. */
217
+ function createTargetColorVariableDeclaration(name, color, depth) {
218
+ return { [createTargetColorVariableName(name, depth)]: color };
219
+ }
220
+ /** Parses definition bodies in the `name_source` format used by `mc-*` rules. */
221
+ function parseColorVariableDefinition(body) {
222
+ const firstUnderscoreIndex = body.indexOf("_");
223
+ if (firstUnderscoreIndex < 0) return;
224
+ const name = body.substring(0, firstUnderscoreIndex);
225
+ const hue = body.substring(firstUnderscoreIndex + 1);
226
+ if (!name || !hue) return;
227
+ return {
228
+ name,
229
+ hue
230
+ };
231
+ }
232
+ /** Checks whether a color body is a literal CSS color instead of a theme alias. */
233
+ function isLiteralColor(color) {
234
+ return color.startsWith("#") || /^[a-z][\w-]*\(/i.test(color);
235
+ }
236
+ //#endregion
237
+ export { isLiteralColor as a, getMcThemeMetaColors as c, themeMetaList as d, notNull as f, resolveSpecialColor as g, resolveBodyColor as h, createTargetColorVariableName as i, getThemeDepthColor as l, hasDarkVariant as m, createSourceColorVariableName as n, parseColorVariableDefinition as o, toOklch as p, createTargetColorVariableDeclaration as r, toVar as s, BASE_COLOR_DEPTH as t, resolveThemeDepth as u };
package/dist/helper.js CHANGED
@@ -1,40 +1,91 @@
1
- import { mc as m } from "magic-color";
2
- import { i as h, t as C, a as g, c as d, g as u, r as b } from "./common-Dv0krm1V.js";
3
- function M(p) {
4
- const { name: c, color: a, dom: i } = p;
5
- if (!i)
6
- return;
7
- const s = a?.split(/-\d+-?/)[0];
8
- if (h(s))
9
- return;
10
- const e = {}, t = {};
11
- try {
12
- if (m.valid(s)) {
13
- e[`--mc-${c}-color`] = s;
14
- const o = m.theme(s, { type: "hex" });
15
- for (const r of C) {
16
- const n = g({ type: "hex", components: [o[r]], alpha: 1 });
17
- t[r] = n;
18
- }
19
- }
20
- } catch (o) {
21
- console.error(`[updateMagicColor] get ${s} theme fail, please use another color.`), console.error(o);
22
- }
23
- const l = a.match(/.*-(\d+)/)?.[1];
24
- if (l) {
25
- const { originDepth: o, beforeDepth: r, afterDepth: n } = b(l);
26
- t[r] && t[n] && (e[`--mc-${c}-color`] = d({
27
- originDepth: o,
28
- beforeDepth: r,
29
- beforeComponents: t[r].components,
30
- afterComponents: t[n].components
31
- }));
32
- }
33
- const f = u(c, t);
34
- Object.assign(e, f);
35
- for (const o in e)
36
- e[o] && i.style.setProperty(o, e[o].toString());
1
+ import { c as getMcThemeMetaColors, g as resolveSpecialColor, h as resolveBodyColor, l as getThemeDepthColor, r as createTargetColorVariableDeclaration, t as BASE_COLOR_DEPTH } from "./color-variable-Dd9ag2au.js";
2
+ import { mc } from "magic-color";
3
+ //#region src/helper.ts
4
+ /** Escapes a color name before it is interpolated into a CSS variable regex. */
5
+ function escapeRegExp(value) {
6
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
37
7
  }
38
- export {
39
- M as updateMagicColor
40
- };
8
+ /** Collects the base and depth variables already present in one style object. */
9
+ function collectStyleVariables(name, style, usage) {
10
+ const colorVariableRE = new RegExp(`^--mc-colors-${escapeRegExp(name)}-(${BASE_COLOR_DEPTH}|\\d+)$`);
11
+ for (let i = 0; i < style.length; i++) {
12
+ const match = style.item(i).match(colorVariableRE);
13
+ if (!match) continue;
14
+ const [, depth] = match;
15
+ if (depth === "DEFAULT") usage.hasBase = true;
16
+ else if (depth) usage.depths.add(depth);
17
+ }
18
+ }
19
+ /** Reads inline and computed styles so runtime updates only touch variables that exist. */
20
+ function collectDefinedColorVariables(name, dom) {
21
+ const usage = {
22
+ hasBase: false,
23
+ depths: /* @__PURE__ */ new Set()
24
+ };
25
+ const window = dom.ownerDocument.defaultView;
26
+ collectStyleVariables(name, dom.style, usage);
27
+ if (window) collectStyleVariables(name, window.getComputedStyle(dom), usage);
28
+ return usage;
29
+ }
30
+ /**
31
+ * Generate CSS color variables for a magic color.
32
+ * @param params params Parameter object
33
+ * @param params.name Color name
34
+ * @param params.color Color value, supports a color depth suffix like `#9c1d1e-457`
35
+ * @param params.hasBase Whether to generate the base color variable
36
+ * @param params.depths Color depths that need depth-specific variables
37
+ * @returns CSS variables for the requested magic color usage
38
+ */
39
+ function getMagicColorStyle(params) {
40
+ const { name, color, hasBase, depths, lightnessReverse } = params;
41
+ const { originColor, originDepth } = resolveBodyColor(color);
42
+ if (!originColor) return {};
43
+ const css = {};
44
+ const specialColor = resolveSpecialColor(originColor);
45
+ if (specialColor) {
46
+ if (hasBase) Object.assign(css, createTargetColorVariableDeclaration(name, specialColor));
47
+ for (const depth of depths) Object.assign(css, createTargetColorVariableDeclaration(name, specialColor, depth));
48
+ return css;
49
+ }
50
+ const themeMetaColors = getMcThemeMetaColors(originColor);
51
+ if (hasBase) {
52
+ if (originDepth) {
53
+ const baseColor = getThemeDepthColor(themeMetaColors, originDepth, { lightnessReverse });
54
+ baseColor && Object.assign(css, createTargetColorVariableDeclaration(name, baseColor));
55
+ } else if (mc.valid(originColor)) {
56
+ const baseColor = mc(originColor).css("oklch");
57
+ Object.assign(css, createTargetColorVariableDeclaration(name, baseColor));
58
+ }
59
+ }
60
+ for (const depth of depths) {
61
+ const depthColor = getThemeDepthColor(themeMetaColors, depth, { lightnessReverse });
62
+ if (depthColor) Object.assign(css, createTargetColorVariableDeclaration(name, depthColor, depth));
63
+ }
64
+ return css;
65
+ }
66
+ /**
67
+ * Updates already-defined CSS variables for a magic color on a DOM element.
68
+ *
69
+ * The helper intentionally does not infer usage from class names at runtime;
70
+ * it only rewrites variables that were emitted by UnoCSS or declared by the app.
71
+ * @param params params Parameter object
72
+ * @param params.name Color name
73
+ * @param params.color Color
74
+ * @param params.lightnessReverse Reverse numeric lightness depths before resolving colors
75
+ * @param params.dom params.dom Target element, modifying the entire page theme when passing `document.documentElement`
76
+ */
77
+ function updateMagicColor(params) {
78
+ const { name, color, lightnessReverse, dom } = params;
79
+ if (!dom) return;
80
+ const { hasBase, depths } = collectDefinedColorVariables(name, dom);
81
+ const css = getMagicColorStyle({
82
+ name,
83
+ color,
84
+ hasBase,
85
+ depths,
86
+ lightnessReverse
87
+ });
88
+ for (const [variable, value] of Object.entries(css)) if (value) dom.style.setProperty(variable, value.toString());
89
+ }
90
+ //#endregion
91
+ export { getMagicColorStyle, updateMagicColor };