@weapp-tailwindcss/postcss 2.2.1-next.2 → 2.2.1-next.4

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.
@@ -2,4 +2,13 @@ export interface DynamicColorMixAlphaProtection {
2
2
  css: string;
3
3
  restore: (css: string) => string;
4
4
  }
5
- export declare function protectDynamicColorMixAlpha(css: string): DynamicColorMixAlphaProtection;
5
+ export interface DynamicColorMixAlphaProtectionOptions {
6
+ customPropertyValues?: ReadonlyMap<string, string> | undefined;
7
+ }
8
+ export interface ModernColorValueNormalization {
9
+ value: string;
10
+ changed: boolean;
11
+ hasUnsupported: boolean;
12
+ }
13
+ export declare function normalizeModernColorValue(value: string, customPropertyValues?: ReadonlyMap<string, string>): ModernColorValueNormalization;
14
+ export declare function protectDynamicColorMixAlpha(css: string, options?: DynamicColorMixAlphaProtectionOptions): DynamicColorMixAlphaProtection;
@@ -1,9 +1,13 @@
1
- import type { AtRule, Declaration, Rule } from 'postcss';
1
+ import type { AtRule, Root, Rule } from 'postcss';
2
+ import { Declaration } from 'postcss';
2
3
  export declare function isTailwindcssV4(options?: {
3
4
  majorVersion?: number;
4
5
  }): boolean;
5
6
  export declare function testIfRootHostForV4(node: Rule): boolean;
6
7
  export declare const cssVarsV4Nodes: Declaration[];
8
+ export declare function collectUsedTailwindcssV4Variables(root: Root): Set<string>;
9
+ export declare function usesTailwindcssV4ContentVariable(root: Root): boolean;
10
+ export declare function createUsedCssVarsV4Nodes(usedProps: ReadonlySet<string>): Declaration[];
7
11
  export declare function isTailwindcssV4ModernCheck(atRule: AtRule): boolean;
8
12
  export declare function isTailwindcssV4LinearGradientSupports(atRule: AtRule): boolean;
9
13
  export declare function isTailwindcssV4DisplayP3Supports(atRule: AtRule): boolean;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { type DynamicColorMixAlphaProtection, protectDynamicColorMixAlpha } from './compat/color-mix';
1
+ export { type DynamicColorMixAlphaProtection, type DynamicColorMixAlphaProtectionOptions, type ModernColorValueNormalization, normalizeModernColorValue, protectDynamicColorMixAlpha, } from './compat/color-mix';
2
2
  export * from './handler';
3
3
  export { default as postcssHtmlTransform, type IOptions as PostcssHtmlTransformOptions } from './html-transform';
4
4
  export { createStylePipeline, type PipelineNodeContext, type PipelineNodeCursor, type PipelineStage, type ResolvedPipelineNode, type StyleProcessingPipeline, } from './pipeline';
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_html_transform = require("./html-transform-DuSRw6IH.js");
3
3
  require("./types.js");
4
+ let _csstools_css_color_parser = require("@csstools/css-color-parser");
5
+ let _csstools_css_parser_algorithms = require("@csstools/css-parser-algorithms");
6
+ let _csstools_css_tokenizer = require("@csstools/css-tokenizer");
4
7
  let postcss = require("postcss");
5
8
  postcss = require_html_transform.__toESM(postcss);
6
9
  let postcss_value_parser = require("postcss-value-parser");
@@ -24,9 +27,19 @@ postcss_rule_unit_converter = require_html_transform.__toESM(postcss_rule_unit_c
24
27
  let _weapp_core_escape = require("@weapp-core/escape");
25
28
  //#region src/compat/color-mix.ts
26
29
  const COLOR_MIX_NAME = "color-mix";
27
- const PLACEHOLDER_PREFIX = "__weapp_tw_dynamic_color_mix_";
30
+ const MODERN_COLOR_FUNCTION_NAMES = new Set([
31
+ "oklch",
32
+ "oklab",
33
+ "lch",
34
+ "lab"
35
+ ]);
36
+ const PLACEHOLDER_PREFIX = "__weapp_tw_color_mix_";
28
37
  const DYNAMIC_ALPHA_RE = /\b(?:var|env)\(|--[\w-]+\b/;
29
38
  const INTERNAL_TAILWIND_ALPHA_RE = /var\(\s*--tw-[^)]+-alpha\s*\)/;
39
+ const TRANSPARENT_COLOR_RE = /^transparent$/i;
40
+ const CURRENT_COLOR_RE = /^currentcolor$/i;
41
+ const CSS_WIDE_KEYWORD_RE = /^(?:inherit|initial|unset|revert|revert-layer)$/i;
42
+ const CUSTOM_PROPERTY_RE = /^--[\w-]+$/;
30
43
  function splitArguments(nodes) {
31
44
  const args = [];
32
45
  let current = [];
@@ -57,15 +70,147 @@ function splitStopSegments(nodes) {
57
70
  if (current.length > 0) segments.push(current);
58
71
  return segments;
59
72
  }
60
- function hasDynamicStopAlpha(nodes) {
61
- const segments = splitStopSegments(nodes);
62
- if (segments.length < 2) return false;
63
- const alpha = postcss_value_parser.default.stringify(segments[segments.length - 1]).trim();
64
- if (INTERNAL_TAILWIND_ALPHA_RE.test(alpha)) return false;
65
- return DYNAMIC_ALPHA_RE.test(alpha);
73
+ function trimNodes$1(nodes) {
74
+ let start = 0;
75
+ let end = nodes.length;
76
+ while (start < end && nodes[start]?.type === "space") start += 1;
77
+ while (end > start && nodes[end - 1]?.type === "space") end -= 1;
78
+ return nodes.slice(start, end);
79
+ }
80
+ function getParsedColorData(colorSource) {
81
+ try {
82
+ return (0, _csstools_css_color_parser.color)((0, _csstools_css_parser_algorithms.parseComponentValue)((0, _csstools_css_tokenizer.tokenize)({ css: colorSource })));
83
+ } catch {
84
+ return false;
85
+ }
86
+ }
87
+ function parseAlphaValue(alphaSource) {
88
+ const parsed = Number.parseFloat(alphaSource);
89
+ if (Number.isFinite(parsed)) return alphaSource.trim().endsWith("%") ? parsed / 100 : parsed;
90
+ }
91
+ function resolveVarColor(colorSource, customPropertyValues, depth = 0) {
92
+ if (depth > 5) return;
93
+ const parsed = (0, postcss_value_parser.default)(colorSource.trim());
94
+ const node = parsed.nodes.length === 1 ? parsed.nodes[0] : void 0;
95
+ if (node?.type !== "function" || node.value.toLowerCase() !== "var") return;
96
+ const args = splitArguments(node.nodes);
97
+ const propertyName = postcss_value_parser.default.stringify(trimNodes$1(args[0] ?? [])).trim();
98
+ if (!CUSTOM_PROPERTY_RE.test(propertyName)) return;
99
+ const resolved = customPropertyValues.get(propertyName);
100
+ if (!resolved) {
101
+ const fallback = args[1] ? postcss_value_parser.default.stringify(trimNodes$1(args[1])).trim() : void 0;
102
+ return fallback ? resolveColorData(fallback, customPropertyValues, depth + 1) : void 0;
103
+ }
104
+ return resolveColorData(resolved, customPropertyValues, depth + 1);
105
+ }
106
+ function resolveColorData(colorSource, customPropertyValues, depth = 0) {
107
+ if (typeof colorSource !== "string") return;
108
+ const trimmed = colorSource.trim();
109
+ if (TRANSPARENT_COLOR_RE.test(trimmed)) return getParsedColorData(trimmed) || void 0;
110
+ if (CURRENT_COLOR_RE.test(trimmed) || CSS_WIDE_KEYWORD_RE.test(trimmed)) return;
111
+ const resolvedVar = resolveVarColor(trimmed, customPropertyValues, depth);
112
+ if (resolvedVar) return resolvedVar;
113
+ return getParsedColorData(trimmed) || void 0;
114
+ }
115
+ function normalizeColorFunctionName(colorSource, alpha, customPropertyValues) {
116
+ const resolvedColor = resolveColorData(colorSource, customPropertyValues);
117
+ if (!resolvedColor) return;
118
+ resolvedColor.alpha = alpha;
119
+ return (0, _csstools_css_color_parser.serializeRGB)(resolvedColor).toString();
120
+ }
121
+ function normalizeStandaloneColorFunction(colorSource) {
122
+ const resolvedColor = getParsedColorData(colorSource);
123
+ return resolvedColor ? (0, _csstools_css_color_parser.serializeRGB)(resolvedColor).toString() : void 0;
124
+ }
125
+ function isDisplayP3ColorFunction(colorSource) {
126
+ return /^color\(\s*display-p3\b/i.test(colorSource.trim());
127
+ }
128
+ function hasUnsupportedModernColorFunction(value) {
129
+ const parsed = (0, postcss_value_parser.default)(value);
130
+ let hasUnsupported = false;
131
+ parsed.walk((node) => {
132
+ if (node.type !== "function") return;
133
+ const name = node.value.toLowerCase();
134
+ if (name === COLOR_MIX_NAME || MODERN_COLOR_FUNCTION_NAMES.has(name) || name === "color" && isDisplayP3ColorFunction(postcss_value_parser.default.stringify(node))) {
135
+ hasUnsupported = true;
136
+ return false;
137
+ }
138
+ });
139
+ return hasUnsupported;
140
+ }
141
+ function normalizeModernColorValue(value, customPropertyValues = /* @__PURE__ */ new Map()) {
142
+ if (!hasUnsupportedModernColorFunction(value)) return {
143
+ value,
144
+ changed: false,
145
+ hasUnsupported: false
146
+ };
147
+ const parsed = (0, postcss_value_parser.default)(value);
148
+ let changed = false;
149
+ parsed.walk((node) => {
150
+ if (node.type !== "function") return;
151
+ const name = node.value.toLowerCase();
152
+ const source = postcss_value_parser.default.stringify(node);
153
+ let normalized;
154
+ if (MODERN_COLOR_FUNCTION_NAMES.has(name) || name === "color" && isDisplayP3ColorFunction(source)) normalized = normalizeStandaloneColorFunction(source);
155
+ else if (name === COLOR_MIX_NAME) normalized = tryResolveColorMix(node, customPropertyValues)?.value;
156
+ if (!normalized) return;
157
+ const mutableNode = node;
158
+ mutableNode.type = "word";
159
+ mutableNode.value = normalized;
160
+ delete mutableNode.nodes;
161
+ changed = true;
162
+ });
163
+ const nextValue = changed ? parsed.toString() : value;
164
+ return {
165
+ value: nextValue,
166
+ changed,
167
+ hasUnsupported: hasUnsupportedModernColorFunction(nextValue)
168
+ };
66
169
  }
67
- function shouldProtectColorMix(node) {
68
- return splitArguments(node.nodes).slice(1).some(hasDynamicStopAlpha);
170
+ function createRgbaWithAlpha(colorSource, alphaSource, customPropertyValues) {
171
+ const resolvedColor = resolveColorData(colorSource, customPropertyValues);
172
+ if (!resolvedColor) return;
173
+ const [red, green, blue] = resolvedColor.channels.map((channel) => Math.round(Math.min(1, Math.max(0, channel)) * 255));
174
+ const alpha = alphaSource.trim();
175
+ return `rgba(${red}, ${green}, ${blue}, ${CUSTOM_PROPERTY_RE.test(alpha) ? `var(${alpha})` : alpha})`;
176
+ }
177
+ function tryResolveColorMix(node, customPropertyValues) {
178
+ const args = splitArguments(node.nodes);
179
+ if (args.length < 3) return;
180
+ const colorStopNodes = splitStopSegments(args[1] ?? []);
181
+ if (colorStopNodes.length < 2) return;
182
+ const colorNodes = trimNodes$1(colorStopNodes[0] ?? []);
183
+ const alphaNodes = trimNodes$1(colorStopNodes[1] ?? []);
184
+ const trailingNodes = trimNodes$1(args[2] ?? []);
185
+ if (!colorNodes.length || !alphaNodes.length || postcss_value_parser.default.stringify(trailingNodes).trim().toLowerCase() !== "transparent") return;
186
+ const colorSource = postcss_value_parser.default.stringify(colorNodes).trim();
187
+ const alphaSource = postcss_value_parser.default.stringify(alphaNodes).trim();
188
+ if (!colorSource || !alphaSource || INTERNAL_TAILWIND_ALPHA_RE.test(alphaSource)) return;
189
+ if (CURRENT_COLOR_RE.test(colorSource)) return {
190
+ value: colorSource,
191
+ deferred: false
192
+ };
193
+ if (DYNAMIC_ALPHA_RE.test(alphaSource)) {
194
+ const normalized = createRgbaWithAlpha(colorSource, alphaSource, customPropertyValues);
195
+ return normalized ? {
196
+ value: normalized,
197
+ deferred: true
198
+ } : {
199
+ value: colorSource,
200
+ deferred: true
201
+ };
202
+ }
203
+ const alpha = parseAlphaValue(alphaSource);
204
+ if (alpha === void 0) return;
205
+ const normalized = normalizeColorFunctionName(colorSource, alpha, customPropertyValues);
206
+ if (normalized) return {
207
+ value: normalized,
208
+ deferred: false
209
+ };
210
+ return {
211
+ value: colorSource,
212
+ deferred: false
213
+ };
69
214
  }
70
215
  function createPlaceholder(index) {
71
216
  return `${PLACEHOLDER_PREFIX}${index}__`;
@@ -76,40 +221,54 @@ function unwrapProtectedSupports(cssRoot) {
76
221
  atRule.replaceWith(atRule.nodes);
77
222
  });
78
223
  }
79
- function protectDynamicColorMixAlpha(css) {
224
+ function protectDynamicColorMixAlpha(css, options = {}) {
80
225
  if (!css.includes(COLOR_MIX_NAME)) return {
81
226
  css,
82
227
  restore: (value) => value
83
228
  };
84
229
  const replacements = /* @__PURE__ */ new Map();
85
230
  const root = postcss.default.parse(css);
231
+ const customPropertyValues = new Map(options.customPropertyValues);
232
+ let changed = false;
233
+ root.walkDecls((decl) => {
234
+ if (decl.prop.startsWith("--") && !decl.value.includes(COLOR_MIX_NAME)) customPropertyValues.set(decl.prop, decl.value.trim());
235
+ });
86
236
  root.walkDecls((decl) => {
87
237
  if (!decl.value.includes(COLOR_MIX_NAME)) return;
88
238
  const parsed = (0, postcss_value_parser.default)(decl.value);
89
239
  let mutated = false;
90
240
  parsed.walk((node) => {
91
241
  if (node.type !== "function" || node.value.toLowerCase() !== COLOR_MIX_NAME) return;
92
- if (!shouldProtectColorMix(node)) return;
93
- const placeholder = createPlaceholder(replacements.size);
94
- replacements.set(placeholder, postcss_value_parser.default.stringify(node));
95
- const mutableNode = node;
96
- mutableNode.type = "word";
97
- mutableNode.value = placeholder;
98
- delete mutableNode.nodes;
99
- mutated = true;
242
+ const resolved = tryResolveColorMix(node, customPropertyValues);
243
+ if (resolved) {
244
+ if (resolved.deferred) {
245
+ const placeholder = createPlaceholder(replacements.size);
246
+ replacements.set(placeholder, resolved.value);
247
+ const mutableNode = node;
248
+ mutableNode.type = "word";
249
+ mutableNode.value = placeholder;
250
+ delete mutableNode.nodes;
251
+ mutated = true;
252
+ return;
253
+ }
254
+ const mutableNode = node;
255
+ mutableNode.type = "word";
256
+ mutableNode.value = resolved.value;
257
+ delete mutableNode.nodes;
258
+ mutated = true;
259
+ }
100
260
  });
101
- if (mutated) decl.value = parsed.toString();
261
+ if (mutated) {
262
+ decl.value = parsed.toString();
263
+ changed = true;
264
+ }
102
265
  });
103
- if (replacements.size === 0) return {
104
- css,
105
- restore: (value) => value
106
- };
107
- unwrapProtectedSupports(root);
266
+ if (replacements.size > 0) unwrapProtectedSupports(root);
108
267
  return {
109
- css: root.toString(),
268
+ css: changed ? root.toString() : css,
110
269
  restore(value) {
111
270
  let restored = value;
112
- for (const [placeholder, original] of replacements) restored = restored.split(placeholder).join(original);
271
+ for (const [placeholder, replacement] of replacements) restored = restored.split(placeholder).join(replacement);
113
272
  return restored;
114
273
  }
115
274
  };
@@ -141,7 +300,7 @@ function isBaseCarrierSelector(selector) {
141
300
  function isBaseCarrierRule(rule) {
142
301
  return Array.isArray(rule.selectors) && rule.selectors.length > 0 && rule.selectors.every(isBaseCarrierSelector);
143
302
  }
144
- function hasClassSelector(rule) {
303
+ function hasClassSelector$1(rule) {
145
304
  return Array.isArray(rule.selectors) && rule.selectors.some((selector) => CLASS_SELECTOR_RE.test(selector));
146
305
  }
147
306
  function collectRequiredTwVars(value) {
@@ -171,7 +330,7 @@ function extractUniAppXBaseDefaults(result) {
171
330
  function injectUniAppXBaseDefaults(result, defaults) {
172
331
  if (defaults.size === 0) return;
173
332
  result.root.walkRules((rule) => {
174
- if (!hasClassSelector(rule)) return;
333
+ if (!hasClassSelector$1(rule)) return;
175
334
  const declaredProps = /* @__PURE__ */ new Set();
176
335
  const requiredProps = /* @__PURE__ */ new Set();
177
336
  rule.walkDecls((decl) => {
@@ -532,6 +691,7 @@ const WEAPP_AUTOPREFIXER_BROWSERS = [
532
691
  "Android >= 4.4",
533
692
  "ChromeAndroid >= 37"
534
693
  ];
694
+ const WEAPP_AUTOPREFIXER_DEFAULT_OPTIONS = { flexbox: false };
535
695
  const AUTOPREFIXER_PLUGIN_NAME = "autoprefixer";
536
696
  function isAutoprefixerPlugin(plugin) {
537
697
  return plugin?.postcssPlugin === AUTOPREFIXER_PLUGIN_NAME;
@@ -540,6 +700,7 @@ function resolveAutoprefixerPlugin(option) {
540
700
  if (option === false) return;
541
701
  const userOptions = option === true || option === void 0 ? {} : option;
542
702
  return (0, autoprefixer.default)({
703
+ ...WEAPP_AUTOPREFIXER_DEFAULT_OPTIONS,
543
704
  ...userOptions,
544
705
  overrideBrowserslist: userOptions.overrideBrowserslist ?? WEAPP_AUTOPREFIXER_BROWSERS
545
706
  });
@@ -821,6 +982,8 @@ const nodes = [
821
982
  property("--tw-scroll-snap-strictness", "proximity", "*"),
822
983
  property("--tw-space-x-reverse", "0"),
823
984
  property("--tw-space-y-reverse", "0"),
985
+ property("--tw-scrollbar-thumb", "#0000", "<color>"),
986
+ property("--tw-scrollbar-track", "#0000", "<color>"),
824
987
  property("--tw-border-style", "solid"),
825
988
  property("--tw-divide-x-reverse", "0"),
826
989
  property("--tw-divide-y-reverse", "0"),
@@ -945,13 +1108,46 @@ const DISPLAY_P3_VALUE_RE = /color\(\s*display-p3\b/i;
945
1108
  const COLOR_GAMUT_P3_RE = /\(\s*color-gamut\s*:\s*p3\s*\)/i;
946
1109
  const RADIUS_VALUE_RE = /\b([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)\s*(r?px)\b/gi;
947
1110
  const SCIENTIFIC_NOTATION_RE = /e/i;
1111
+ const TW_VAR_FUNCTION_RE = /var\(\s*(--tw-[\w-]+)\b/g;
1112
+ const TW_CONTENT_VAR_RE = /var\(\s*--tw-content\b/;
948
1113
  function isTailwindcssV4(options) {
949
1114
  return options?.majorVersion === 4;
950
1115
  }
951
1116
  function testIfRootHostForV4(node) {
952
1117
  return node.type === "rule" && node.selector.includes(":root") && node.selector.includes(":host");
953
1118
  }
954
- const cssVarsV4Nodes = createCssVarNodes(nodes);
1119
+ createCssVarNodes(nodes);
1120
+ function collectUsedTailwindcssV4Variables(root) {
1121
+ const props = /* @__PURE__ */ new Set();
1122
+ root.walkDecls((decl) => {
1123
+ if (decl.prop.startsWith("--tw-")) props.add(decl.prop);
1124
+ TW_VAR_FUNCTION_RE.lastIndex = 0;
1125
+ let match = TW_VAR_FUNCTION_RE.exec(decl.value);
1126
+ while (match !== null) {
1127
+ const prop = match[1];
1128
+ if (prop) props.add(prop);
1129
+ match = TW_VAR_FUNCTION_RE.exec(decl.value);
1130
+ }
1131
+ });
1132
+ root.walkAtRules("property", (atRule) => {
1133
+ const prop = atRule.params.trim();
1134
+ if (prop.startsWith("--tw-")) props.add(prop);
1135
+ });
1136
+ return props;
1137
+ }
1138
+ function usesTailwindcssV4ContentVariable(root) {
1139
+ let used = false;
1140
+ root.walkDecls((decl) => {
1141
+ if (TW_CONTENT_VAR_RE.test(decl.value)) used = true;
1142
+ });
1143
+ return used;
1144
+ }
1145
+ function createUsedCssVarsV4Nodes(usedProps) {
1146
+ return nodes.filter((def) => usedProps.has(def.prop)).map((def) => new postcss.Declaration({
1147
+ prop: def.prop,
1148
+ value: def.value
1149
+ }));
1150
+ }
955
1151
  function isTailwindcssV4ModernCheck(atRule) {
956
1152
  return atRule.name === "supports" && [
957
1153
  MODERN_CHECK_WEBKIT_HYPHENS_RE,
@@ -1772,6 +1968,21 @@ const DEFAULT_ROOT_SELECTORS$1 = [
1772
1968
  ".tw-root",
1773
1969
  "wx-root-portal-content"
1774
1970
  ];
1971
+ const LEGACY_FLEXBOX_DECLARATION_PROPS = new Set([
1972
+ "-webkit-align-content",
1973
+ "-webkit-align-items",
1974
+ "-webkit-align-self",
1975
+ "-webkit-flex",
1976
+ "-webkit-flex-basis",
1977
+ "-webkit-flex-direction",
1978
+ "-webkit-flex-flow",
1979
+ "-webkit-flex-grow",
1980
+ "-webkit-flex-shrink",
1981
+ "-webkit-flex-wrap",
1982
+ "-webkit-justify-content",
1983
+ "-webkit-order"
1984
+ ]);
1985
+ const LEGACY_FLEXBOX_DISPLAY_VALUES = new Set(["-webkit-flex", "-webkit-inline-flex"]);
1775
1986
  function normalizeRootSelectors(value) {
1776
1987
  if (value === void 0 || value === false) return [];
1777
1988
  return Array.isArray(value) ? value.filter(Boolean) : [value];
@@ -1785,6 +1996,13 @@ function createHostSelectorAppender(options) {
1785
1996
  return DEFAULT_ROOT_SELECTORS$1.every((selector) => selectors.includes(selector));
1786
1997
  };
1787
1998
  }
1999
+ function removeLegacyFlexboxPrefix(decl) {
2000
+ if (decl.prop === "display" && LEGACY_FLEXBOX_DISPLAY_VALUES.has(decl.value)) {
2001
+ decl.remove();
2002
+ return;
2003
+ }
2004
+ if (LEGACY_FLEXBOX_DECLARATION_PROPS.has(decl.prop)) decl.remove();
2005
+ }
1788
2006
  const postcssWeappTailwindcssPostPlugin = (options) => {
1789
2007
  const opts = (0, _weapp_tailwindcss_shared.defu)(options, { isMainChunk: true });
1790
2008
  const p = { postcssPlugin };
@@ -1813,6 +2031,7 @@ const postcssWeappTailwindcssPostPlugin = (options) => {
1813
2031
  if (opts.majorVersion === void 0) normalizeTailwindcssRpxDeclaration(decl);
1814
2032
  else normalizeTailwindcssRpxDeclaration(decl, { majorVersion: opts.majorVersion });
1815
2033
  if (enableMainChunkTransforms) normalizeTailwindcssV4Declaration(decl);
2034
+ removeLegacyFlexboxPrefix(decl);
1816
2035
  };
1817
2036
  if (enableMainChunkTransforms) p.AtRuleExit = (atRule) => {
1818
2037
  /**
@@ -2091,6 +2310,20 @@ function makePseudoVarRule() {
2091
2310
  }));
2092
2311
  return pseudoVarRule;
2093
2312
  }
2313
+ function isEmptyContentInitDeclaration(decl) {
2314
+ return decl.prop === "--tw-content" && (decl.value === "\"\"" || decl.value === "''");
2315
+ }
2316
+ function removeTailwindV4EmptyContentInit(node) {
2317
+ node.walkDecls((decl) => {
2318
+ if (isEmptyContentInitDeclaration(decl)) decl.remove();
2319
+ });
2320
+ }
2321
+ function hasClassSelector(node) {
2322
+ return node.selectors.some((selector) => selector.includes("."));
2323
+ }
2324
+ function isRootThemeScopeRule(node) {
2325
+ return node.selectors.length > 0 && node.selectors.every((selector) => selector === ":root" || selector === ":host" || DEFAULT_ROOT_SELECTORS.includes(selector));
2326
+ }
2094
2327
  function remakeCssVarSelector(selectors, options) {
2095
2328
  const { cssPreflightRange, cssSelectorReplacement } = options;
2096
2329
  if (cssPreflightRange === "all" && !selectors.includes(":not(not)")) selectors.push(":not(not)");
@@ -2112,6 +2345,7 @@ function resolveUniAppXVariableScopeSelectors(options) {
2112
2345
  function commonChunkPreflight(node, options) {
2113
2346
  const { ctx, cssInjectPreflight, injectAdditionalCssVarScope } = options;
2114
2347
  const uniAppXEnabled = isUniAppXEnabled(options);
2348
+ const isTailwindcss4 = isTailwindcssV4(options);
2115
2349
  const rootOption = options.cssSelectorReplacement?.root;
2116
2350
  const rootSelectors = rootOption === false || rootOption === void 0 ? [] : Array.isArray(rootOption) ? rootOption.filter(Boolean) : [rootOption];
2117
2351
  const hasHostSelector = node.selectors.some((selector) => selector.includes(":host"));
@@ -2121,31 +2355,33 @@ function commonChunkPreflight(node, options) {
2121
2355
  phase: "pre",
2122
2356
  reason: "append-host-selector"
2123
2357
  });
2358
+ if (isTailwindcss4 && !usesTailwindcssV4ContentVariable(node.root()) && (!hasClassSelector(node) || isRootThemeScopeRule(node))) removeTailwindV4EmptyContentInit(node);
2124
2359
  if (testIfVariablesScope(node) || uniAppXEnabled && node.selectors.includes("*") && hasTwVars(node, 2)) {
2125
2360
  ctx?.markVariablesScope(node);
2126
2361
  assignRuleSelectors(node, uniAppXEnabled ? resolveUniAppXVariableScopeSelectors(options) : remakeCssVarSelector(node.selectors, options), {
2127
2362
  phase: "pre",
2128
2363
  reason: "rewrite-variable-scope"
2129
2364
  });
2130
- if (!uniAppXEnabled) node.before(makePseudoVarRule());
2365
+ if (!uniAppXEnabled && !isTailwindcss4) node.before(makePseudoVarRule());
2131
2366
  if (typeof cssInjectPreflight === "function") node.append(...cssInjectPreflight());
2132
2367
  }
2133
- const isTailwindcss4 = isTailwindcssV4(options);
2134
2368
  if (injectAdditionalCssVarScope && (isTailwindcss4 ? testIfRootHostForV4(node) : testIfTwBackdrop(node))) {
2369
+ const nodes = isTailwindcss4 ? createUsedCssVarsV4Nodes(collectUsedTailwindcssV4Variables(node.root())) : cssVarsV3Nodes;
2370
+ if (nodes.length === 0) return;
2135
2371
  const syntheticRule = new postcss.Rule({
2136
2372
  selectors: uniAppXEnabled ? resolveUniAppXVariableScopeSelectors(options) : [
2137
2373
  "*",
2138
2374
  "::after",
2139
2375
  "::before"
2140
2376
  ],
2141
- nodes: isTailwindcss4 ? cssVarsV4Nodes : cssVarsV3Nodes
2377
+ nodes
2142
2378
  });
2143
2379
  if (!uniAppXEnabled) assignRuleSelectors(syntheticRule, remakeCssVarSelector(syntheticRule.selectors, options), {
2144
2380
  phase: "pre",
2145
2381
  reason: "rewrite-synthetic-variable-scope"
2146
2382
  });
2147
2383
  node.before(syntheticRule);
2148
- if (!uniAppXEnabled) node.before(makePseudoVarRule());
2384
+ if (!uniAppXEnabled && !isTailwindcss4) node.before(makePseudoVarRule());
2149
2385
  if (typeof cssInjectPreflight === "function") syntheticRule.append(...cssInjectPreflight());
2150
2386
  }
2151
2387
  }
@@ -2253,7 +2489,7 @@ function shouldUseDefaultAutoprefixer(options, userPlugins) {
2253
2489
  if (options.autoprefixer === false) return false;
2254
2490
  if (hasUserAutoprefixerPlugin(options.postcssOptions?.plugins, userPlugins)) return false;
2255
2491
  if (options.autoprefixer === true || typeof options.autoprefixer === "object") return true;
2256
- return options.majorVersion === 4;
2492
+ return options.majorVersion === 3 || options.majorVersion === 4;
2257
2493
  }
2258
2494
  function createPreparedNodes(options, signal) {
2259
2495
  const preparedNodes = [];
@@ -2480,19 +2716,31 @@ function createStyleHandler(options) {
2480
2716
  const hasUserPlugins = Boolean(cachedOptions.postcssOptions?.plugins && (Array.isArray(cachedOptions.postcssOptions.plugins) ? cachedOptions.postcssOptions.plugins.length > 0 : typeof cachedOptions.postcssOptions.plugins === "object" && Object.keys(cachedOptions.postcssOptions.plugins).length > 0));
2481
2717
  const handler = ((rawSource, opt) => {
2482
2718
  const resolvedOptions = resolver.resolve(opt);
2719
+ const protectedColorMix = resolvedOptions.majorVersion === 4 ? protectDynamicColorMixAlpha(rawSource) : void 0;
2720
+ const source = protectedColorMix?.css ?? rawSource;
2483
2721
  let signal;
2484
2722
  if (!hasUserPlugins) try {
2485
- signal = probeFeatures(rawSource);
2723
+ signal = probeFeatures(source);
2486
2724
  } catch {
2487
2725
  signal = void 0;
2488
2726
  }
2489
- const cacheKey = `${getOptionsFingerprint(resolvedOptions)}|${signal ? signalToCacheKey(signal) : ""}|${simpleHash(rawSource)}`;
2727
+ const cacheKey = `${getOptionsFingerprint(resolvedOptions)}|${signal ? signalToCacheKey(signal) : ""}|${simpleHash(source)}`;
2490
2728
  const cachedResult = resultCache.get(cacheKey);
2491
2729
  if (cachedResult) return Promise.resolve(cachedResult);
2492
2730
  const processor = processorCache.getProcessor(resolvedOptions, signal);
2493
2731
  const processOptions = processorCache.getProcessOptions(resolvedOptions);
2494
- return processor.process(rawSource, processOptions).async().then((result) => {
2495
- const finalResult = applyUniAppXUvueCompatibility(applyUniAppXBaseCompatibility(result, resolvedOptions), resolvedOptions);
2732
+ return processor.process(source, processOptions).async().then((result) => {
2733
+ let finalResult = applyUniAppXUvueCompatibility(applyUniAppXBaseCompatibility(result, resolvedOptions), resolvedOptions);
2734
+ if (protectedColorMix) {
2735
+ const restoredCss = protectedColorMix.restore(finalResult.css);
2736
+ if (restoredCss !== finalResult.css) {
2737
+ const nextResult = finalResult.root.clone().toResult(finalResult.opts);
2738
+ nextResult.css = restoredCss;
2739
+ nextResult.root = postcss.default.parse(restoredCss, finalResult.opts);
2740
+ nextResult.messages.push(...finalResult.messages);
2741
+ finalResult = nextResult;
2742
+ }
2743
+ }
2496
2744
  resultCache.set(cacheKey, finalResult);
2497
2745
  return finalResult;
2498
2746
  });
@@ -2509,5 +2757,6 @@ exports.createInjectPreflight = createInjectPreflight;
2509
2757
  exports.createStyleHandler = createStyleHandler;
2510
2758
  exports.createStylePipeline = createStylePipeline;
2511
2759
  exports.internalCssSelectorReplacer = internalCssSelectorReplacer;
2760
+ exports.normalizeModernColorValue = normalizeModernColorValue;
2512
2761
  exports.postcssHtmlTransform = require_html_transform.postcssHtmlTransform;
2513
2762
  exports.protectDynamicColorMixAlpha = protectDynamicColorMixAlpha;
package/dist/index.mjs CHANGED
@@ -1,5 +1,8 @@
1
1
  import postcssHtmlTransform from "./html-transform.mjs";
2
2
  import "./types.mjs";
3
+ import { color, serializeRGB } from "@csstools/css-color-parser";
4
+ import { parseComponentValue } from "@csstools/css-parser-algorithms";
5
+ import { tokenize } from "@csstools/css-tokenizer";
3
6
  import postcss, { Declaration, Rule } from "postcss";
4
7
  import valueParser from "postcss-value-parser";
5
8
  import { defu, defuOverrideArray, regExpTest } from "@weapp-tailwindcss/shared";
@@ -14,9 +17,19 @@ import postcssUnitConverter, { presets } from "postcss-rule-unit-converter";
14
17
  import { MappingChars2String, escape } from "@weapp-core/escape";
15
18
  //#region src/compat/color-mix.ts
16
19
  const COLOR_MIX_NAME = "color-mix";
17
- const PLACEHOLDER_PREFIX = "__weapp_tw_dynamic_color_mix_";
20
+ const MODERN_COLOR_FUNCTION_NAMES = new Set([
21
+ "oklch",
22
+ "oklab",
23
+ "lch",
24
+ "lab"
25
+ ]);
26
+ const PLACEHOLDER_PREFIX = "__weapp_tw_color_mix_";
18
27
  const DYNAMIC_ALPHA_RE = /\b(?:var|env)\(|--[\w-]+\b/;
19
28
  const INTERNAL_TAILWIND_ALPHA_RE = /var\(\s*--tw-[^)]+-alpha\s*\)/;
29
+ const TRANSPARENT_COLOR_RE = /^transparent$/i;
30
+ const CURRENT_COLOR_RE = /^currentcolor$/i;
31
+ const CSS_WIDE_KEYWORD_RE = /^(?:inherit|initial|unset|revert|revert-layer)$/i;
32
+ const CUSTOM_PROPERTY_RE = /^--[\w-]+$/;
20
33
  function splitArguments(nodes) {
21
34
  const args = [];
22
35
  let current = [];
@@ -47,15 +60,147 @@ function splitStopSegments(nodes) {
47
60
  if (current.length > 0) segments.push(current);
48
61
  return segments;
49
62
  }
50
- function hasDynamicStopAlpha(nodes) {
51
- const segments = splitStopSegments(nodes);
52
- if (segments.length < 2) return false;
53
- const alpha = valueParser.stringify(segments[segments.length - 1]).trim();
54
- if (INTERNAL_TAILWIND_ALPHA_RE.test(alpha)) return false;
55
- return DYNAMIC_ALPHA_RE.test(alpha);
63
+ function trimNodes$1(nodes) {
64
+ let start = 0;
65
+ let end = nodes.length;
66
+ while (start < end && nodes[start]?.type === "space") start += 1;
67
+ while (end > start && nodes[end - 1]?.type === "space") end -= 1;
68
+ return nodes.slice(start, end);
69
+ }
70
+ function getParsedColorData(colorSource) {
71
+ try {
72
+ return color(parseComponentValue(tokenize({ css: colorSource })));
73
+ } catch {
74
+ return false;
75
+ }
76
+ }
77
+ function parseAlphaValue(alphaSource) {
78
+ const parsed = Number.parseFloat(alphaSource);
79
+ if (Number.isFinite(parsed)) return alphaSource.trim().endsWith("%") ? parsed / 100 : parsed;
80
+ }
81
+ function resolveVarColor(colorSource, customPropertyValues, depth = 0) {
82
+ if (depth > 5) return;
83
+ const parsed = valueParser(colorSource.trim());
84
+ const node = parsed.nodes.length === 1 ? parsed.nodes[0] : void 0;
85
+ if (node?.type !== "function" || node.value.toLowerCase() !== "var") return;
86
+ const args = splitArguments(node.nodes);
87
+ const propertyName = valueParser.stringify(trimNodes$1(args[0] ?? [])).trim();
88
+ if (!CUSTOM_PROPERTY_RE.test(propertyName)) return;
89
+ const resolved = customPropertyValues.get(propertyName);
90
+ if (!resolved) {
91
+ const fallback = args[1] ? valueParser.stringify(trimNodes$1(args[1])).trim() : void 0;
92
+ return fallback ? resolveColorData(fallback, customPropertyValues, depth + 1) : void 0;
93
+ }
94
+ return resolveColorData(resolved, customPropertyValues, depth + 1);
95
+ }
96
+ function resolveColorData(colorSource, customPropertyValues, depth = 0) {
97
+ if (typeof colorSource !== "string") return;
98
+ const trimmed = colorSource.trim();
99
+ if (TRANSPARENT_COLOR_RE.test(trimmed)) return getParsedColorData(trimmed) || void 0;
100
+ if (CURRENT_COLOR_RE.test(trimmed) || CSS_WIDE_KEYWORD_RE.test(trimmed)) return;
101
+ const resolvedVar = resolveVarColor(trimmed, customPropertyValues, depth);
102
+ if (resolvedVar) return resolvedVar;
103
+ return getParsedColorData(trimmed) || void 0;
104
+ }
105
+ function normalizeColorFunctionName(colorSource, alpha, customPropertyValues) {
106
+ const resolvedColor = resolveColorData(colorSource, customPropertyValues);
107
+ if (!resolvedColor) return;
108
+ resolvedColor.alpha = alpha;
109
+ return serializeRGB(resolvedColor).toString();
110
+ }
111
+ function normalizeStandaloneColorFunction(colorSource) {
112
+ const resolvedColor = getParsedColorData(colorSource);
113
+ return resolvedColor ? serializeRGB(resolvedColor).toString() : void 0;
114
+ }
115
+ function isDisplayP3ColorFunction(colorSource) {
116
+ return /^color\(\s*display-p3\b/i.test(colorSource.trim());
117
+ }
118
+ function hasUnsupportedModernColorFunction(value) {
119
+ const parsed = valueParser(value);
120
+ let hasUnsupported = false;
121
+ parsed.walk((node) => {
122
+ if (node.type !== "function") return;
123
+ const name = node.value.toLowerCase();
124
+ if (name === COLOR_MIX_NAME || MODERN_COLOR_FUNCTION_NAMES.has(name) || name === "color" && isDisplayP3ColorFunction(valueParser.stringify(node))) {
125
+ hasUnsupported = true;
126
+ return false;
127
+ }
128
+ });
129
+ return hasUnsupported;
130
+ }
131
+ function normalizeModernColorValue(value, customPropertyValues = /* @__PURE__ */ new Map()) {
132
+ if (!hasUnsupportedModernColorFunction(value)) return {
133
+ value,
134
+ changed: false,
135
+ hasUnsupported: false
136
+ };
137
+ const parsed = valueParser(value);
138
+ let changed = false;
139
+ parsed.walk((node) => {
140
+ if (node.type !== "function") return;
141
+ const name = node.value.toLowerCase();
142
+ const source = valueParser.stringify(node);
143
+ let normalized;
144
+ if (MODERN_COLOR_FUNCTION_NAMES.has(name) || name === "color" && isDisplayP3ColorFunction(source)) normalized = normalizeStandaloneColorFunction(source);
145
+ else if (name === COLOR_MIX_NAME) normalized = tryResolveColorMix(node, customPropertyValues)?.value;
146
+ if (!normalized) return;
147
+ const mutableNode = node;
148
+ mutableNode.type = "word";
149
+ mutableNode.value = normalized;
150
+ delete mutableNode.nodes;
151
+ changed = true;
152
+ });
153
+ const nextValue = changed ? parsed.toString() : value;
154
+ return {
155
+ value: nextValue,
156
+ changed,
157
+ hasUnsupported: hasUnsupportedModernColorFunction(nextValue)
158
+ };
56
159
  }
57
- function shouldProtectColorMix(node) {
58
- return splitArguments(node.nodes).slice(1).some(hasDynamicStopAlpha);
160
+ function createRgbaWithAlpha(colorSource, alphaSource, customPropertyValues) {
161
+ const resolvedColor = resolveColorData(colorSource, customPropertyValues);
162
+ if (!resolvedColor) return;
163
+ const [red, green, blue] = resolvedColor.channels.map((channel) => Math.round(Math.min(1, Math.max(0, channel)) * 255));
164
+ const alpha = alphaSource.trim();
165
+ return `rgba(${red}, ${green}, ${blue}, ${CUSTOM_PROPERTY_RE.test(alpha) ? `var(${alpha})` : alpha})`;
166
+ }
167
+ function tryResolveColorMix(node, customPropertyValues) {
168
+ const args = splitArguments(node.nodes);
169
+ if (args.length < 3) return;
170
+ const colorStopNodes = splitStopSegments(args[1] ?? []);
171
+ if (colorStopNodes.length < 2) return;
172
+ const colorNodes = trimNodes$1(colorStopNodes[0] ?? []);
173
+ const alphaNodes = trimNodes$1(colorStopNodes[1] ?? []);
174
+ const trailingNodes = trimNodes$1(args[2] ?? []);
175
+ if (!colorNodes.length || !alphaNodes.length || valueParser.stringify(trailingNodes).trim().toLowerCase() !== "transparent") return;
176
+ const colorSource = valueParser.stringify(colorNodes).trim();
177
+ const alphaSource = valueParser.stringify(alphaNodes).trim();
178
+ if (!colorSource || !alphaSource || INTERNAL_TAILWIND_ALPHA_RE.test(alphaSource)) return;
179
+ if (CURRENT_COLOR_RE.test(colorSource)) return {
180
+ value: colorSource,
181
+ deferred: false
182
+ };
183
+ if (DYNAMIC_ALPHA_RE.test(alphaSource)) {
184
+ const normalized = createRgbaWithAlpha(colorSource, alphaSource, customPropertyValues);
185
+ return normalized ? {
186
+ value: normalized,
187
+ deferred: true
188
+ } : {
189
+ value: colorSource,
190
+ deferred: true
191
+ };
192
+ }
193
+ const alpha = parseAlphaValue(alphaSource);
194
+ if (alpha === void 0) return;
195
+ const normalized = normalizeColorFunctionName(colorSource, alpha, customPropertyValues);
196
+ if (normalized) return {
197
+ value: normalized,
198
+ deferred: false
199
+ };
200
+ return {
201
+ value: colorSource,
202
+ deferred: false
203
+ };
59
204
  }
60
205
  function createPlaceholder(index) {
61
206
  return `${PLACEHOLDER_PREFIX}${index}__`;
@@ -66,40 +211,54 @@ function unwrapProtectedSupports(cssRoot) {
66
211
  atRule.replaceWith(atRule.nodes);
67
212
  });
68
213
  }
69
- function protectDynamicColorMixAlpha(css) {
214
+ function protectDynamicColorMixAlpha(css, options = {}) {
70
215
  if (!css.includes(COLOR_MIX_NAME)) return {
71
216
  css,
72
217
  restore: (value) => value
73
218
  };
74
219
  const replacements = /* @__PURE__ */ new Map();
75
220
  const root = postcss.parse(css);
221
+ const customPropertyValues = new Map(options.customPropertyValues);
222
+ let changed = false;
223
+ root.walkDecls((decl) => {
224
+ if (decl.prop.startsWith("--") && !decl.value.includes(COLOR_MIX_NAME)) customPropertyValues.set(decl.prop, decl.value.trim());
225
+ });
76
226
  root.walkDecls((decl) => {
77
227
  if (!decl.value.includes(COLOR_MIX_NAME)) return;
78
228
  const parsed = valueParser(decl.value);
79
229
  let mutated = false;
80
230
  parsed.walk((node) => {
81
231
  if (node.type !== "function" || node.value.toLowerCase() !== COLOR_MIX_NAME) return;
82
- if (!shouldProtectColorMix(node)) return;
83
- const placeholder = createPlaceholder(replacements.size);
84
- replacements.set(placeholder, valueParser.stringify(node));
85
- const mutableNode = node;
86
- mutableNode.type = "word";
87
- mutableNode.value = placeholder;
88
- delete mutableNode.nodes;
89
- mutated = true;
232
+ const resolved = tryResolveColorMix(node, customPropertyValues);
233
+ if (resolved) {
234
+ if (resolved.deferred) {
235
+ const placeholder = createPlaceholder(replacements.size);
236
+ replacements.set(placeholder, resolved.value);
237
+ const mutableNode = node;
238
+ mutableNode.type = "word";
239
+ mutableNode.value = placeholder;
240
+ delete mutableNode.nodes;
241
+ mutated = true;
242
+ return;
243
+ }
244
+ const mutableNode = node;
245
+ mutableNode.type = "word";
246
+ mutableNode.value = resolved.value;
247
+ delete mutableNode.nodes;
248
+ mutated = true;
249
+ }
90
250
  });
91
- if (mutated) decl.value = parsed.toString();
251
+ if (mutated) {
252
+ decl.value = parsed.toString();
253
+ changed = true;
254
+ }
92
255
  });
93
- if (replacements.size === 0) return {
94
- css,
95
- restore: (value) => value
96
- };
97
- unwrapProtectedSupports(root);
256
+ if (replacements.size > 0) unwrapProtectedSupports(root);
98
257
  return {
99
- css: root.toString(),
258
+ css: changed ? root.toString() : css,
100
259
  restore(value) {
101
260
  let restored = value;
102
- for (const [placeholder, original] of replacements) restored = restored.split(placeholder).join(original);
261
+ for (const [placeholder, replacement] of replacements) restored = restored.split(placeholder).join(replacement);
103
262
  return restored;
104
263
  }
105
264
  };
@@ -131,7 +290,7 @@ function isBaseCarrierSelector(selector) {
131
290
  function isBaseCarrierRule(rule) {
132
291
  return Array.isArray(rule.selectors) && rule.selectors.length > 0 && rule.selectors.every(isBaseCarrierSelector);
133
292
  }
134
- function hasClassSelector(rule) {
293
+ function hasClassSelector$1(rule) {
135
294
  return Array.isArray(rule.selectors) && rule.selectors.some((selector) => CLASS_SELECTOR_RE.test(selector));
136
295
  }
137
296
  function collectRequiredTwVars(value) {
@@ -161,7 +320,7 @@ function extractUniAppXBaseDefaults(result) {
161
320
  function injectUniAppXBaseDefaults(result, defaults) {
162
321
  if (defaults.size === 0) return;
163
322
  result.root.walkRules((rule) => {
164
- if (!hasClassSelector(rule)) return;
323
+ if (!hasClassSelector$1(rule)) return;
165
324
  const declaredProps = /* @__PURE__ */ new Set();
166
325
  const requiredProps = /* @__PURE__ */ new Set();
167
326
  rule.walkDecls((decl) => {
@@ -522,6 +681,7 @@ const WEAPP_AUTOPREFIXER_BROWSERS = [
522
681
  "Android >= 4.4",
523
682
  "ChromeAndroid >= 37"
524
683
  ];
684
+ const WEAPP_AUTOPREFIXER_DEFAULT_OPTIONS = { flexbox: false };
525
685
  const AUTOPREFIXER_PLUGIN_NAME = "autoprefixer";
526
686
  function isAutoprefixerPlugin(plugin) {
527
687
  return plugin?.postcssPlugin === AUTOPREFIXER_PLUGIN_NAME;
@@ -530,6 +690,7 @@ function resolveAutoprefixerPlugin(option) {
530
690
  if (option === false) return;
531
691
  const userOptions = option === true || option === void 0 ? {} : option;
532
692
  return autoprefixerPlugin({
693
+ ...WEAPP_AUTOPREFIXER_DEFAULT_OPTIONS,
533
694
  ...userOptions,
534
695
  overrideBrowserslist: userOptions.overrideBrowserslist ?? WEAPP_AUTOPREFIXER_BROWSERS
535
696
  });
@@ -811,6 +972,8 @@ const nodes = [
811
972
  property("--tw-scroll-snap-strictness", "proximity", "*"),
812
973
  property("--tw-space-x-reverse", "0"),
813
974
  property("--tw-space-y-reverse", "0"),
975
+ property("--tw-scrollbar-thumb", "#0000", "<color>"),
976
+ property("--tw-scrollbar-track", "#0000", "<color>"),
814
977
  property("--tw-border-style", "solid"),
815
978
  property("--tw-divide-x-reverse", "0"),
816
979
  property("--tw-divide-y-reverse", "0"),
@@ -935,13 +1098,46 @@ const DISPLAY_P3_VALUE_RE = /color\(\s*display-p3\b/i;
935
1098
  const COLOR_GAMUT_P3_RE = /\(\s*color-gamut\s*:\s*p3\s*\)/i;
936
1099
  const RADIUS_VALUE_RE = /\b([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)\s*(r?px)\b/gi;
937
1100
  const SCIENTIFIC_NOTATION_RE = /e/i;
1101
+ const TW_VAR_FUNCTION_RE = /var\(\s*(--tw-[\w-]+)\b/g;
1102
+ const TW_CONTENT_VAR_RE = /var\(\s*--tw-content\b/;
938
1103
  function isTailwindcssV4(options) {
939
1104
  return options?.majorVersion === 4;
940
1105
  }
941
1106
  function testIfRootHostForV4(node) {
942
1107
  return node.type === "rule" && node.selector.includes(":root") && node.selector.includes(":host");
943
1108
  }
944
- const cssVarsV4Nodes = createCssVarNodes(nodes);
1109
+ createCssVarNodes(nodes);
1110
+ function collectUsedTailwindcssV4Variables(root) {
1111
+ const props = /* @__PURE__ */ new Set();
1112
+ root.walkDecls((decl) => {
1113
+ if (decl.prop.startsWith("--tw-")) props.add(decl.prop);
1114
+ TW_VAR_FUNCTION_RE.lastIndex = 0;
1115
+ let match = TW_VAR_FUNCTION_RE.exec(decl.value);
1116
+ while (match !== null) {
1117
+ const prop = match[1];
1118
+ if (prop) props.add(prop);
1119
+ match = TW_VAR_FUNCTION_RE.exec(decl.value);
1120
+ }
1121
+ });
1122
+ root.walkAtRules("property", (atRule) => {
1123
+ const prop = atRule.params.trim();
1124
+ if (prop.startsWith("--tw-")) props.add(prop);
1125
+ });
1126
+ return props;
1127
+ }
1128
+ function usesTailwindcssV4ContentVariable(root) {
1129
+ let used = false;
1130
+ root.walkDecls((decl) => {
1131
+ if (TW_CONTENT_VAR_RE.test(decl.value)) used = true;
1132
+ });
1133
+ return used;
1134
+ }
1135
+ function createUsedCssVarsV4Nodes(usedProps) {
1136
+ return nodes.filter((def) => usedProps.has(def.prop)).map((def) => new Declaration({
1137
+ prop: def.prop,
1138
+ value: def.value
1139
+ }));
1140
+ }
945
1141
  function isTailwindcssV4ModernCheck(atRule) {
946
1142
  return atRule.name === "supports" && [
947
1143
  MODERN_CHECK_WEBKIT_HYPHENS_RE,
@@ -1762,6 +1958,21 @@ const DEFAULT_ROOT_SELECTORS$1 = [
1762
1958
  ".tw-root",
1763
1959
  "wx-root-portal-content"
1764
1960
  ];
1961
+ const LEGACY_FLEXBOX_DECLARATION_PROPS = new Set([
1962
+ "-webkit-align-content",
1963
+ "-webkit-align-items",
1964
+ "-webkit-align-self",
1965
+ "-webkit-flex",
1966
+ "-webkit-flex-basis",
1967
+ "-webkit-flex-direction",
1968
+ "-webkit-flex-flow",
1969
+ "-webkit-flex-grow",
1970
+ "-webkit-flex-shrink",
1971
+ "-webkit-flex-wrap",
1972
+ "-webkit-justify-content",
1973
+ "-webkit-order"
1974
+ ]);
1975
+ const LEGACY_FLEXBOX_DISPLAY_VALUES = new Set(["-webkit-flex", "-webkit-inline-flex"]);
1765
1976
  function normalizeRootSelectors(value) {
1766
1977
  if (value === void 0 || value === false) return [];
1767
1978
  return Array.isArray(value) ? value.filter(Boolean) : [value];
@@ -1775,6 +1986,13 @@ function createHostSelectorAppender(options) {
1775
1986
  return DEFAULT_ROOT_SELECTORS$1.every((selector) => selectors.includes(selector));
1776
1987
  };
1777
1988
  }
1989
+ function removeLegacyFlexboxPrefix(decl) {
1990
+ if (decl.prop === "display" && LEGACY_FLEXBOX_DISPLAY_VALUES.has(decl.value)) {
1991
+ decl.remove();
1992
+ return;
1993
+ }
1994
+ if (LEGACY_FLEXBOX_DECLARATION_PROPS.has(decl.prop)) decl.remove();
1995
+ }
1778
1996
  const postcssWeappTailwindcssPostPlugin = (options) => {
1779
1997
  const opts = defu(options, { isMainChunk: true });
1780
1998
  const p = { postcssPlugin };
@@ -1803,6 +2021,7 @@ const postcssWeappTailwindcssPostPlugin = (options) => {
1803
2021
  if (opts.majorVersion === void 0) normalizeTailwindcssRpxDeclaration(decl);
1804
2022
  else normalizeTailwindcssRpxDeclaration(decl, { majorVersion: opts.majorVersion });
1805
2023
  if (enableMainChunkTransforms) normalizeTailwindcssV4Declaration(decl);
2024
+ removeLegacyFlexboxPrefix(decl);
1806
2025
  };
1807
2026
  if (enableMainChunkTransforms) p.AtRuleExit = (atRule) => {
1808
2027
  /**
@@ -2081,6 +2300,20 @@ function makePseudoVarRule() {
2081
2300
  }));
2082
2301
  return pseudoVarRule;
2083
2302
  }
2303
+ function isEmptyContentInitDeclaration(decl) {
2304
+ return decl.prop === "--tw-content" && (decl.value === "\"\"" || decl.value === "''");
2305
+ }
2306
+ function removeTailwindV4EmptyContentInit(node) {
2307
+ node.walkDecls((decl) => {
2308
+ if (isEmptyContentInitDeclaration(decl)) decl.remove();
2309
+ });
2310
+ }
2311
+ function hasClassSelector(node) {
2312
+ return node.selectors.some((selector) => selector.includes("."));
2313
+ }
2314
+ function isRootThemeScopeRule(node) {
2315
+ return node.selectors.length > 0 && node.selectors.every((selector) => selector === ":root" || selector === ":host" || DEFAULT_ROOT_SELECTORS.includes(selector));
2316
+ }
2084
2317
  function remakeCssVarSelector(selectors, options) {
2085
2318
  const { cssPreflightRange, cssSelectorReplacement } = options;
2086
2319
  if (cssPreflightRange === "all" && !selectors.includes(":not(not)")) selectors.push(":not(not)");
@@ -2102,6 +2335,7 @@ function resolveUniAppXVariableScopeSelectors(options) {
2102
2335
  function commonChunkPreflight(node, options) {
2103
2336
  const { ctx, cssInjectPreflight, injectAdditionalCssVarScope } = options;
2104
2337
  const uniAppXEnabled = isUniAppXEnabled(options);
2338
+ const isTailwindcss4 = isTailwindcssV4(options);
2105
2339
  const rootOption = options.cssSelectorReplacement?.root;
2106
2340
  const rootSelectors = rootOption === false || rootOption === void 0 ? [] : Array.isArray(rootOption) ? rootOption.filter(Boolean) : [rootOption];
2107
2341
  const hasHostSelector = node.selectors.some((selector) => selector.includes(":host"));
@@ -2111,31 +2345,33 @@ function commonChunkPreflight(node, options) {
2111
2345
  phase: "pre",
2112
2346
  reason: "append-host-selector"
2113
2347
  });
2348
+ if (isTailwindcss4 && !usesTailwindcssV4ContentVariable(node.root()) && (!hasClassSelector(node) || isRootThemeScopeRule(node))) removeTailwindV4EmptyContentInit(node);
2114
2349
  if (testIfVariablesScope(node) || uniAppXEnabled && node.selectors.includes("*") && hasTwVars(node, 2)) {
2115
2350
  ctx?.markVariablesScope(node);
2116
2351
  assignRuleSelectors(node, uniAppXEnabled ? resolveUniAppXVariableScopeSelectors(options) : remakeCssVarSelector(node.selectors, options), {
2117
2352
  phase: "pre",
2118
2353
  reason: "rewrite-variable-scope"
2119
2354
  });
2120
- if (!uniAppXEnabled) node.before(makePseudoVarRule());
2355
+ if (!uniAppXEnabled && !isTailwindcss4) node.before(makePseudoVarRule());
2121
2356
  if (typeof cssInjectPreflight === "function") node.append(...cssInjectPreflight());
2122
2357
  }
2123
- const isTailwindcss4 = isTailwindcssV4(options);
2124
2358
  if (injectAdditionalCssVarScope && (isTailwindcss4 ? testIfRootHostForV4(node) : testIfTwBackdrop(node))) {
2359
+ const nodes = isTailwindcss4 ? createUsedCssVarsV4Nodes(collectUsedTailwindcssV4Variables(node.root())) : cssVarsV3Nodes;
2360
+ if (nodes.length === 0) return;
2125
2361
  const syntheticRule = new Rule({
2126
2362
  selectors: uniAppXEnabled ? resolveUniAppXVariableScopeSelectors(options) : [
2127
2363
  "*",
2128
2364
  "::after",
2129
2365
  "::before"
2130
2366
  ],
2131
- nodes: isTailwindcss4 ? cssVarsV4Nodes : cssVarsV3Nodes
2367
+ nodes
2132
2368
  });
2133
2369
  if (!uniAppXEnabled) assignRuleSelectors(syntheticRule, remakeCssVarSelector(syntheticRule.selectors, options), {
2134
2370
  phase: "pre",
2135
2371
  reason: "rewrite-synthetic-variable-scope"
2136
2372
  });
2137
2373
  node.before(syntheticRule);
2138
- if (!uniAppXEnabled) node.before(makePseudoVarRule());
2374
+ if (!uniAppXEnabled && !isTailwindcss4) node.before(makePseudoVarRule());
2139
2375
  if (typeof cssInjectPreflight === "function") syntheticRule.append(...cssInjectPreflight());
2140
2376
  }
2141
2377
  }
@@ -2243,7 +2479,7 @@ function shouldUseDefaultAutoprefixer(options, userPlugins) {
2243
2479
  if (options.autoprefixer === false) return false;
2244
2480
  if (hasUserAutoprefixerPlugin(options.postcssOptions?.plugins, userPlugins)) return false;
2245
2481
  if (options.autoprefixer === true || typeof options.autoprefixer === "object") return true;
2246
- return options.majorVersion === 4;
2482
+ return options.majorVersion === 3 || options.majorVersion === 4;
2247
2483
  }
2248
2484
  function createPreparedNodes(options, signal) {
2249
2485
  const preparedNodes = [];
@@ -2470,19 +2706,31 @@ function createStyleHandler(options) {
2470
2706
  const hasUserPlugins = Boolean(cachedOptions.postcssOptions?.plugins && (Array.isArray(cachedOptions.postcssOptions.plugins) ? cachedOptions.postcssOptions.plugins.length > 0 : typeof cachedOptions.postcssOptions.plugins === "object" && Object.keys(cachedOptions.postcssOptions.plugins).length > 0));
2471
2707
  const handler = ((rawSource, opt) => {
2472
2708
  const resolvedOptions = resolver.resolve(opt);
2709
+ const protectedColorMix = resolvedOptions.majorVersion === 4 ? protectDynamicColorMixAlpha(rawSource) : void 0;
2710
+ const source = protectedColorMix?.css ?? rawSource;
2473
2711
  let signal;
2474
2712
  if (!hasUserPlugins) try {
2475
- signal = probeFeatures(rawSource);
2713
+ signal = probeFeatures(source);
2476
2714
  } catch {
2477
2715
  signal = void 0;
2478
2716
  }
2479
- const cacheKey = `${getOptionsFingerprint(resolvedOptions)}|${signal ? signalToCacheKey(signal) : ""}|${simpleHash(rawSource)}`;
2717
+ const cacheKey = `${getOptionsFingerprint(resolvedOptions)}|${signal ? signalToCacheKey(signal) : ""}|${simpleHash(source)}`;
2480
2718
  const cachedResult = resultCache.get(cacheKey);
2481
2719
  if (cachedResult) return Promise.resolve(cachedResult);
2482
2720
  const processor = processorCache.getProcessor(resolvedOptions, signal);
2483
2721
  const processOptions = processorCache.getProcessOptions(resolvedOptions);
2484
- return processor.process(rawSource, processOptions).async().then((result) => {
2485
- const finalResult = applyUniAppXUvueCompatibility(applyUniAppXBaseCompatibility(result, resolvedOptions), resolvedOptions);
2722
+ return processor.process(source, processOptions).async().then((result) => {
2723
+ let finalResult = applyUniAppXUvueCompatibility(applyUniAppXBaseCompatibility(result, resolvedOptions), resolvedOptions);
2724
+ if (protectedColorMix) {
2725
+ const restoredCss = protectedColorMix.restore(finalResult.css);
2726
+ if (restoredCss !== finalResult.css) {
2727
+ const nextResult = finalResult.root.clone().toResult(finalResult.opts);
2728
+ nextResult.css = restoredCss;
2729
+ nextResult.root = postcss.parse(restoredCss, finalResult.opts);
2730
+ nextResult.messages.push(...finalResult.messages);
2731
+ finalResult = nextResult;
2732
+ }
2733
+ }
2486
2734
  resultCache.set(cacheKey, finalResult);
2487
2735
  return finalResult;
2488
2736
  });
@@ -2494,4 +2742,4 @@ function createStyleHandler(options) {
2494
2742
  return handler;
2495
2743
  }
2496
2744
  //#endregion
2497
- export { createFallbackPlaceholderReplacer, createInjectPreflight, createStyleHandler, createStylePipeline, internalCssSelectorReplacer, postcssHtmlTransform, protectDynamicColorMixAlpha };
2745
+ export { createFallbackPlaceholderReplacer, createInjectPreflight, createStyleHandler, createStylePipeline, internalCssSelectorReplacer, normalizeModernColorValue, postcssHtmlTransform, protectDynamicColorMixAlpha };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weapp-tailwindcss/postcss",
3
- "version": "2.2.1-next.2",
3
+ "version": "2.2.1-next.4",
4
4
  "description": "@weapp-tailwindcss/postcss",
5
5
  "author": "ice breaker <1324318532@qq.com>",
6
6
  "license": "MIT",
@@ -56,11 +56,14 @@
56
56
  "node": "^20.19.0 || >=22.12.0"
57
57
  },
58
58
  "dependencies": {
59
+ "@csstools/css-color-parser": "^4.1.1",
60
+ "@csstools/css-parser-algorithms": "^4.0.0",
61
+ "@csstools/css-tokenizer": "^4.0.0",
59
62
  "@weapp-core/escape": "~7.0.0",
60
63
  "@weapp-tailwindcss/postcss-calc": "^1.0.0",
61
64
  "autoprefixer": "^10.5.0",
62
65
  "lru-cache": "10.4.3",
63
- "postcss": "^8.5.14",
66
+ "postcss": "^8.5.15",
64
67
  "postcss-preset-env": "^10.6.1",
65
68
  "postcss-pxtrans": "^1.0.4",
66
69
  "postcss-rem-to-responsive-pixel": "^7.0.4",