@onereach/styles 27.0.2-beta.6103.0 → 27.0.2-beta.6105.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION_TAILWIND_V4.md +149 -0
- package/README.md +14 -0
- package/compat/tailwind-v3-utilities.css +1 -0
- package/main-v3.css +1 -1
- package/main-v4.css +3 -0
- package/package.json +17 -6
- package/postcss/tailwind-v4-compat.cjs +816 -0
- package/rollup-plugin-tailwindcss-cli.css +2 -1
- package/tailwind/compatibility/important.js +13 -0
- package/tailwind/compatibility/legacy-spacing.js +133 -0
- package/tailwind/plugins/theme-background.js +4 -3
- package/tailwind/plugins/theme-border.js +4 -3
- package/tailwind/plugins/theme-divider.js +7 -6
- package/tailwind/plugins/theme-foreground.js +4 -3
- package/tailwind/plugins/theme-outline.js +4 -3
- package/tailwind/plugins/theme-preset.js +17 -16
- package/tailwind.config.js +1 -3
- package/tailwind.config.json +2681 -1030
- package/tailwind.config.preset.js +1 -230
- package/tailwind.config.preset.v4.js +231 -0
- package/legacy-utilities.layer.css +0 -67219
|
@@ -0,0 +1,816 @@
|
|
|
1
|
+
const postcss = require('postcss');
|
|
2
|
+
const postcssNested = require('postcss-nested');
|
|
3
|
+
|
|
4
|
+
const screens = require('../screens.json');
|
|
5
|
+
const {
|
|
6
|
+
importantMarker,
|
|
7
|
+
} = require('../tailwind/compatibility/important');
|
|
8
|
+
const {
|
|
9
|
+
legacySpacingAliasEntries,
|
|
10
|
+
} = require('../tailwind/compatibility/legacy-spacing');
|
|
11
|
+
const coreVariants = require('../tailwind/plugins/core').variants;
|
|
12
|
+
const themePresetValues = require('../tailwind/plugins/theme-preset').values;
|
|
13
|
+
const spacing = require('../tailwind.config.preset.v4').theme.spacing;
|
|
14
|
+
|
|
15
|
+
const legacyStateVariantOrder = new Map(
|
|
16
|
+
Object.keys(coreVariants)
|
|
17
|
+
.map((variant, index) => [variant, index]),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const legacySpacingAliases = legacySpacingAliasEntries(spacing)
|
|
21
|
+
.sort(([, left], [, right]) => right.length - left.length);
|
|
22
|
+
const legacySpacingUtilityPattern = /^-?(?:p(?:[xytrblse])?|m(?:[xytrblse])?|gap(?:-[xy])?|w|h|min-[wh]|max-[wh])-/;
|
|
23
|
+
const responsiveVariantOrder = new Map(
|
|
24
|
+
['xs', ...Object.keys(screens)].map((variant, index) => [variant, index]),
|
|
25
|
+
);
|
|
26
|
+
const legacyTransformValue = [
|
|
27
|
+
'translate(var(--tw-translate-x, 0), var(--tw-translate-y, 0))',
|
|
28
|
+
'rotate(var(--tw-rotate, 0))',
|
|
29
|
+
'skewX(var(--tw-skew-x, 0))',
|
|
30
|
+
'skewY(var(--tw-skew-y, 0))',
|
|
31
|
+
'scaleX(var(--tw-scale-x, 1))',
|
|
32
|
+
'scaleY(var(--tw-scale-y, 1))',
|
|
33
|
+
].join(' ');
|
|
34
|
+
const legacyComponentFactories = [
|
|
35
|
+
['theme-outline', require('../tailwind/plugins/theme-outline').values],
|
|
36
|
+
['theme-background', require('../tailwind/plugins/theme-background').values],
|
|
37
|
+
['theme-foreground', require('../tailwind/plugins/theme-foreground').values],
|
|
38
|
+
['theme-preset-1', themePresetValues],
|
|
39
|
+
['theme-preset-2', themePresetValues],
|
|
40
|
+
['theme-preset-3', themePresetValues],
|
|
41
|
+
['theme-preset-4', themePresetValues],
|
|
42
|
+
['theme-divider', require('../tailwind/plugins/theme-divider').values],
|
|
43
|
+
['theme-border', require('../tailwind/plugins/theme-border').values],
|
|
44
|
+
]
|
|
45
|
+
.map(([factory, values]) => [
|
|
46
|
+
factory,
|
|
47
|
+
new Map(Object.keys(values).map((value, index) => [value, index])),
|
|
48
|
+
])
|
|
49
|
+
.sort(([left], [right]) => right.length - left.length);
|
|
50
|
+
const legacyComponentFactoryNames = [
|
|
51
|
+
'theme-background',
|
|
52
|
+
'theme-foreground',
|
|
53
|
+
'theme-preset-1',
|
|
54
|
+
'theme-preset-2',
|
|
55
|
+
'theme-preset-3',
|
|
56
|
+
'theme-preset-4',
|
|
57
|
+
'theme-divider',
|
|
58
|
+
'theme-outline',
|
|
59
|
+
'theme-border',
|
|
60
|
+
'iconography',
|
|
61
|
+
'typography',
|
|
62
|
+
'layout',
|
|
63
|
+
].sort((left, right) => right.length - left.length);
|
|
64
|
+
const legacyCoreUtilities = new Map([
|
|
65
|
+
['leading-none', [
|
|
66
|
+
['line-height', '1'],
|
|
67
|
+
]],
|
|
68
|
+
['text-inherit', [
|
|
69
|
+
['font-size', 'inherit'],
|
|
70
|
+
['line-height', 'inherit'],
|
|
71
|
+
['color', 'inherit'],
|
|
72
|
+
]],
|
|
73
|
+
['outline', [
|
|
74
|
+
['outline-style', 'solid'],
|
|
75
|
+
]],
|
|
76
|
+
['outline-none', [
|
|
77
|
+
['outline', '2px solid transparent'],
|
|
78
|
+
['outline-offset', '2px'],
|
|
79
|
+
]],
|
|
80
|
+
['transition-transform', [
|
|
81
|
+
['transition-property', 'transform'],
|
|
82
|
+
]],
|
|
83
|
+
['max-w-none', [
|
|
84
|
+
['max-width', 'none'],
|
|
85
|
+
]],
|
|
86
|
+
['max-h-none', [
|
|
87
|
+
['max-height', 'none'],
|
|
88
|
+
]],
|
|
89
|
+
]);
|
|
90
|
+
const legacyCoreReplacementProps = new Map([
|
|
91
|
+
['leading-none', new Set(['--tw-leading', 'line-height'])],
|
|
92
|
+
['text-inherit', new Set(['font-size', 'line-height', 'color'])],
|
|
93
|
+
['outline', new Set([
|
|
94
|
+
'--tw-outline-style',
|
|
95
|
+
'outline',
|
|
96
|
+
'outline-style',
|
|
97
|
+
'outline-width',
|
|
98
|
+
])],
|
|
99
|
+
['outline-none', new Set([
|
|
100
|
+
'--tw-outline-style',
|
|
101
|
+
'outline',
|
|
102
|
+
'outline-offset',
|
|
103
|
+
'outline-style',
|
|
104
|
+
])],
|
|
105
|
+
['transition-transform', new Set([
|
|
106
|
+
'transition-property',
|
|
107
|
+
'transition-timing-function',
|
|
108
|
+
'transition-duration',
|
|
109
|
+
])],
|
|
110
|
+
['max-w-none', new Set(['max-width'])],
|
|
111
|
+
['max-h-none', new Set(['max-height'])],
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
function tailwindV4Compat() {
|
|
115
|
+
return {
|
|
116
|
+
postcssPlugin: 'onereach-tailwind-v4-compat',
|
|
117
|
+
async OnceExit(root) {
|
|
118
|
+
utilityLayers(root).forEach(restoreNestedVariantOrder);
|
|
119
|
+
await flattenUtilityLayers(root);
|
|
120
|
+
|
|
121
|
+
utilityLayers(root).forEach((layer) => {
|
|
122
|
+
restoreLegacyGroupHover(layer);
|
|
123
|
+
restoreStackedVariantOrder(layer);
|
|
124
|
+
restoreLegacySpacingClassNames(layer);
|
|
125
|
+
restoreImportantDeclarations(layer);
|
|
126
|
+
restoreLegacyCoreUtilities(layer);
|
|
127
|
+
restoreLegacyTransformUtilities(layer);
|
|
128
|
+
restoreArbitraryValueOrder(layer);
|
|
129
|
+
reorderLegacyComponentValueSiblings(layer);
|
|
130
|
+
reorderLegacyStateVariantSiblings(layer);
|
|
131
|
+
reorderResponsiveVariantSiblings(layer);
|
|
132
|
+
});
|
|
133
|
+
restoreLegacyComponentLayers(root);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function restoreNestedVariantOrder(root) {
|
|
139
|
+
root.walkRules((candidateRule) => {
|
|
140
|
+
const candidate = classNames(candidateRule.selector)
|
|
141
|
+
.find((className) => {
|
|
142
|
+
const variants = classSegments(className).slice(0, -1);
|
|
143
|
+
const arbitraryIndex = variants.findIndex((variant) => variant.startsWith('[&'));
|
|
144
|
+
|
|
145
|
+
return variants.includes('children')
|
|
146
|
+
|| arbitraryIndex > 0;
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (!candidate) return;
|
|
150
|
+
|
|
151
|
+
const segments = classSegments(candidate);
|
|
152
|
+
const variantDepth = segments.length - 1;
|
|
153
|
+
|
|
154
|
+
const paths = nestedContainerPaths(candidateRule, variantDepth);
|
|
155
|
+
|
|
156
|
+
if (paths.length === 0) return;
|
|
157
|
+
|
|
158
|
+
candidateRule.removeAll();
|
|
159
|
+
candidateRule.append(paths.map(({ containers, nodes }) => {
|
|
160
|
+
let content = nodes.map((node) => node.clone());
|
|
161
|
+
|
|
162
|
+
containers.forEach((container) => {
|
|
163
|
+
const wrapper = container.clone();
|
|
164
|
+
|
|
165
|
+
wrapper.removeAll();
|
|
166
|
+
wrapper.append(content);
|
|
167
|
+
content = wrapper;
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return content;
|
|
171
|
+
}));
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function classSegments(className) {
|
|
176
|
+
const segments = [];
|
|
177
|
+
let bracketDepth = 0;
|
|
178
|
+
let segment = '';
|
|
179
|
+
|
|
180
|
+
for (const character of className) {
|
|
181
|
+
if (character === '[') bracketDepth += 1;
|
|
182
|
+
if (character === ']') bracketDepth -= 1;
|
|
183
|
+
|
|
184
|
+
if (character === ':' && bracketDepth === 0) {
|
|
185
|
+
segments.push(segment);
|
|
186
|
+
segment = '';
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
segment += character;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
segments.push(segment);
|
|
194
|
+
|
|
195
|
+
return segments;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function nestedContainerPaths(container, depth, containers = []) {
|
|
199
|
+
if (depth === 0) {
|
|
200
|
+
return [{
|
|
201
|
+
containers,
|
|
202
|
+
nodes: container.nodes,
|
|
203
|
+
}];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return container.nodes
|
|
207
|
+
.filter((node) => ['atrule', 'rule'].includes(node.type))
|
|
208
|
+
.flatMap((child) => nestedContainerPaths(child, depth - 1, [
|
|
209
|
+
...containers,
|
|
210
|
+
child,
|
|
211
|
+
]));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function flattenUtilityLayers(root) {
|
|
215
|
+
const layers = utilityLayers(root);
|
|
216
|
+
|
|
217
|
+
for (const layer of layers) {
|
|
218
|
+
const isolatedRoot = postcss.root();
|
|
219
|
+
|
|
220
|
+
isolatedRoot.append(layer.clone());
|
|
221
|
+
await postcss([postcssNested()]).process(isolatedRoot, { from: undefined });
|
|
222
|
+
layer.replaceWith(isolatedRoot.first);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function utilityLayers(root) {
|
|
227
|
+
const layers = [];
|
|
228
|
+
|
|
229
|
+
root.walkAtRules('layer', (layer) => {
|
|
230
|
+
if (layer.params.trim() === 'utilities') layers.push(layer);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
return layers;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function restoreLegacyComponentLayers(root) {
|
|
237
|
+
utilityLayers(root).forEach((utilityLayer) => {
|
|
238
|
+
const componentNodes = extractLegacyComponentNodes(utilityLayer);
|
|
239
|
+
|
|
240
|
+
if (componentNodes.length === 0) return;
|
|
241
|
+
|
|
242
|
+
const componentLayer = postcss.atRule({
|
|
243
|
+
name: 'layer',
|
|
244
|
+
params: 'components',
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
componentLayer.append(componentNodes);
|
|
248
|
+
utilityLayer.before(componentLayer);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function extractLegacyComponentNodes(container) {
|
|
253
|
+
return [...(container.nodes ?? [])].flatMap((node) => {
|
|
254
|
+
if (node.type === 'rule') {
|
|
255
|
+
const isLegacyComponent = classNames(node.selector)
|
|
256
|
+
.map(baseUtility)
|
|
257
|
+
.some((utility) => legacyComponentFactoryNames
|
|
258
|
+
.some((factory) => utility.startsWith(`${factory}-`)));
|
|
259
|
+
|
|
260
|
+
if (!isLegacyComponent) return [];
|
|
261
|
+
|
|
262
|
+
node.remove();
|
|
263
|
+
return [node];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (!node.nodes) return [];
|
|
267
|
+
|
|
268
|
+
const childNodes = extractLegacyComponentNodes(node);
|
|
269
|
+
|
|
270
|
+
if (childNodes.length === 0) return [];
|
|
271
|
+
if (node.type === 'atrule' && node.name === 'layer' && node.params === 'utilities') {
|
|
272
|
+
if (node.nodes.length === 0) node.remove();
|
|
273
|
+
|
|
274
|
+
return childNodes;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const wrapper = node.clone();
|
|
278
|
+
|
|
279
|
+
wrapper.removeAll();
|
|
280
|
+
wrapper.append(childNodes);
|
|
281
|
+
if (node.nodes.length === 0) node.remove();
|
|
282
|
+
|
|
283
|
+
return [wrapper];
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function reorderLegacyComponentValueSiblings(container) {
|
|
288
|
+
const groups = new Map();
|
|
289
|
+
|
|
290
|
+
container.nodes?.forEach((node, index) => {
|
|
291
|
+
if (node.type !== 'rule') return;
|
|
292
|
+
|
|
293
|
+
const candidate = classNames(node.selector)
|
|
294
|
+
.map((className) => ({
|
|
295
|
+
className,
|
|
296
|
+
utility: baseUtility(className),
|
|
297
|
+
}))
|
|
298
|
+
.map((entry) => ({
|
|
299
|
+
...entry,
|
|
300
|
+
factory: legacyComponentFactories
|
|
301
|
+
.find(([factory]) => entry.utility.startsWith(`${factory}-`)),
|
|
302
|
+
}))
|
|
303
|
+
.find(({ factory }) => factory);
|
|
304
|
+
|
|
305
|
+
if (!candidate) return;
|
|
306
|
+
|
|
307
|
+
const [factory, valueOrder] = candidate.factory;
|
|
308
|
+
const value = candidate.utility.slice(factory.length + 1);
|
|
309
|
+
const order = valueOrder.get(value);
|
|
310
|
+
|
|
311
|
+
if (order === undefined) return;
|
|
312
|
+
|
|
313
|
+
const variants = classSegments(candidate.className).slice(0, -1).join(':');
|
|
314
|
+
const key = `${factory}\0${variants}`;
|
|
315
|
+
const group = groups.get(key) ?? [];
|
|
316
|
+
|
|
317
|
+
group.push({
|
|
318
|
+
index,
|
|
319
|
+
node,
|
|
320
|
+
order,
|
|
321
|
+
});
|
|
322
|
+
groups.set(key, group);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
groups.forEach((group) => {
|
|
326
|
+
const sorted = [...group].sort((left, right) => (
|
|
327
|
+
left.order - right.order || left.index - right.index
|
|
328
|
+
));
|
|
329
|
+
|
|
330
|
+
group.forEach(({ index }, sortedIndex) => {
|
|
331
|
+
const node = sorted[sortedIndex].node;
|
|
332
|
+
|
|
333
|
+
container.nodes[index] = node;
|
|
334
|
+
node.parent = container;
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
container.nodes?.forEach((node) => {
|
|
339
|
+
if (node.nodes) reorderLegacyComponentValueSiblings(node);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function restoreStackedVariantOrder(root) {
|
|
344
|
+
root.walkRules((rule) => {
|
|
345
|
+
const candidate = classNames(rule.selector)
|
|
346
|
+
.find((className) => (
|
|
347
|
+
className.split(':').includes('children')
|
|
348
|
+
&& ['first', 'last'].some((variant) => className.split(':').includes(variant))
|
|
349
|
+
));
|
|
350
|
+
|
|
351
|
+
if (!candidate) return;
|
|
352
|
+
|
|
353
|
+
const variants = candidate.split(':');
|
|
354
|
+
const childIndex = variants.indexOf('children');
|
|
355
|
+
const position = variants.includes('first') ? 'first' : 'last';
|
|
356
|
+
const positionIndex = variants.indexOf(position);
|
|
357
|
+
|
|
358
|
+
if (childIndex < positionIndex) {
|
|
359
|
+
rule.selector = rule.selector.replace(
|
|
360
|
+
new RegExp(`\\s*>\\s*\\*:${position}-child`, 'g'),
|
|
361
|
+
`:${position}-child > *`,
|
|
362
|
+
);
|
|
363
|
+
} else {
|
|
364
|
+
rule.selector = rule.selector.replace(
|
|
365
|
+
new RegExp(`:${position}-child\\s*>\\s*\\*`, 'g'),
|
|
366
|
+
` > *:${position}-child`,
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function restoreLegacySpacingClassNames(root) {
|
|
373
|
+
root.walkRules((rule) => {
|
|
374
|
+
let restoredLegacyClass = false;
|
|
375
|
+
|
|
376
|
+
rule.selector = rule.selector.replace(
|
|
377
|
+
/\.((?:\\.|[^\s.#>+~,[\]()=:])+)/g,
|
|
378
|
+
(selector, escapedClassName) => {
|
|
379
|
+
const utility = baseUtility(unescapeClassName(escapedClassName));
|
|
380
|
+
const aliasEntry = legacySpacingAliases.find(([, alias]) => (
|
|
381
|
+
utility.endsWith(`-${alias}`)
|
|
382
|
+
&& legacySpacingUtilityPattern.test(utility)
|
|
383
|
+
));
|
|
384
|
+
|
|
385
|
+
if (!aliasEntry) return selector;
|
|
386
|
+
|
|
387
|
+
const [legacyName, alias] = aliasEntry;
|
|
388
|
+
const aliasStart = escapedClassName.lastIndexOf(`-${alias}`);
|
|
389
|
+
|
|
390
|
+
restoredLegacyClass = true;
|
|
391
|
+
|
|
392
|
+
return `.${escapedClassName.slice(0, aliasStart)}-${escapeClassName(legacyName)}${escapedClassName.slice(aliasStart + alias.length + 1)}`;
|
|
393
|
+
},
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
if (restoredLegacyClass) {
|
|
397
|
+
restoreLegacyAxisDeclarations(rule);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function restoreLegacyAxisDeclarations(rule) {
|
|
403
|
+
const physicalAxis = classNames(rule.selector)
|
|
404
|
+
.map(baseUtility)
|
|
405
|
+
.map((utility) => utility.match(/^-?(px|py|mx|my)-.*[+*]/)?.[1])
|
|
406
|
+
.find(Boolean);
|
|
407
|
+
const declarationMap = {
|
|
408
|
+
px: ['padding-inline', 'padding-left', 'padding-right'],
|
|
409
|
+
py: ['padding-block', 'padding-top', 'padding-bottom'],
|
|
410
|
+
mx: ['margin-inline', 'margin-left', 'margin-right'],
|
|
411
|
+
my: ['margin-block', 'margin-top', 'margin-bottom'],
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
if (!physicalAxis) return;
|
|
415
|
+
|
|
416
|
+
const [logicalProperty, firstProperty, secondProperty] = declarationMap[physicalAxis];
|
|
417
|
+
|
|
418
|
+
rule.walkDecls(logicalProperty, (declaration) => {
|
|
419
|
+
declaration.cloneBefore({ prop: firstProperty });
|
|
420
|
+
declaration.cloneBefore({ prop: secondProperty });
|
|
421
|
+
declaration.remove();
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function escapeClassName(className) {
|
|
426
|
+
return className.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, '\\$1');
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function unescapeClassName(className) {
|
|
430
|
+
return className.replace(/\\(.)/g, '$1');
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function restoreImportantDeclarations(root) {
|
|
434
|
+
root.walkDecls(importantMarker, (marker) => {
|
|
435
|
+
marker.parent.nodes
|
|
436
|
+
.filter((node) => node.type === 'decl' && node !== marker)
|
|
437
|
+
.forEach((declaration) => {
|
|
438
|
+
declaration.important = true;
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
marker.remove();
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function restoreLegacyCoreUtilities(root) {
|
|
446
|
+
const restoredContainers = new WeakSet();
|
|
447
|
+
|
|
448
|
+
root.walkRules((candidateRule) => {
|
|
449
|
+
const utility = classNames(candidateRule.selector)
|
|
450
|
+
.map(baseUtility)
|
|
451
|
+
.find((className) => legacyCoreUtilities.has(className));
|
|
452
|
+
|
|
453
|
+
if (!utility) return;
|
|
454
|
+
if (!candidateRule.selectors.every((selector) => classNames(selector)
|
|
455
|
+
.map(baseUtility)
|
|
456
|
+
.includes(utility))) return;
|
|
457
|
+
|
|
458
|
+
const declarations = legacyCoreUtilities.get(utility);
|
|
459
|
+
const replacedProps = legacyCoreReplacementProps.get(utility);
|
|
460
|
+
|
|
461
|
+
[candidateRule, ...descendantContainers(candidateRule)]
|
|
462
|
+
.filter((container) => directDeclarations(container).length > 0)
|
|
463
|
+
.forEach((container) => {
|
|
464
|
+
if (restoredContainers.has(container)) return;
|
|
465
|
+
|
|
466
|
+
const important = directDeclarations(container)
|
|
467
|
+
.some((declaration) => declaration.important);
|
|
468
|
+
|
|
469
|
+
directDeclarations(container)
|
|
470
|
+
.filter((declaration) => replacedProps.has(declaration.prop))
|
|
471
|
+
.forEach((declaration) => declaration.remove());
|
|
472
|
+
declarations.slice().reverse().forEach(([prop, value]) => {
|
|
473
|
+
container.prepend({
|
|
474
|
+
prop,
|
|
475
|
+
value,
|
|
476
|
+
important,
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
restoredContainers.add(container);
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function restoreLegacyTransformUtilities(root) {
|
|
485
|
+
root.walkRules((rule) => {
|
|
486
|
+
const utility = classNames(rule.selector)
|
|
487
|
+
.map(baseUtility)
|
|
488
|
+
.find((className) => (
|
|
489
|
+
/^-?rotate-(?![xy]-)/.test(className)
|
|
490
|
+
|| /^-?translate-[xy]-/.test(className)
|
|
491
|
+
|| /^-?skew-[xy]-/.test(className)
|
|
492
|
+
|| /^scale(?:-[xy])?-/.test(className)
|
|
493
|
+
));
|
|
494
|
+
|
|
495
|
+
if (!utility) return;
|
|
496
|
+
if (!rule.selectors.every((selector) => classNames(selector)
|
|
497
|
+
.map(baseUtility)
|
|
498
|
+
.includes(utility))) return;
|
|
499
|
+
|
|
500
|
+
const declarations = directDeclarations(rule);
|
|
501
|
+
const important = declarations.some((declaration) => declaration.important);
|
|
502
|
+
const rotate = declarations.find((declaration) => declaration.prop === 'rotate');
|
|
503
|
+
const translate = declarations.find((declaration) => declaration.prop === 'translate');
|
|
504
|
+
const scale = declarations.find((declaration) => declaration.prop === 'scale');
|
|
505
|
+
const transform = declarations.find((declaration) => declaration.prop === 'transform');
|
|
506
|
+
|
|
507
|
+
if (rotate) {
|
|
508
|
+
rotate.cloneBefore({
|
|
509
|
+
prop: '--tw-rotate',
|
|
510
|
+
value: rotate.value,
|
|
511
|
+
important,
|
|
512
|
+
});
|
|
513
|
+
rotate.remove();
|
|
514
|
+
}
|
|
515
|
+
translate?.remove();
|
|
516
|
+
scale?.remove();
|
|
517
|
+
transform?.remove();
|
|
518
|
+
declarations
|
|
519
|
+
.filter(({ prop }) => prop === '--tw-scale-z')
|
|
520
|
+
.forEach((declaration) => declaration.remove());
|
|
521
|
+
declarations
|
|
522
|
+
.filter(({ prop }) => prop === '--tw-skew-x' || prop === '--tw-skew-y')
|
|
523
|
+
.forEach((declaration) => {
|
|
524
|
+
declaration.value = declaration.value.replace(/^skew[XY]\((.*)\)$/, '$1');
|
|
525
|
+
});
|
|
526
|
+
rule.append({
|
|
527
|
+
prop: 'transform',
|
|
528
|
+
value: legacyTransformValue,
|
|
529
|
+
important,
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function restoreLegacyGroupHover(root) {
|
|
535
|
+
const restoredByParent = new WeakMap();
|
|
536
|
+
|
|
537
|
+
root.walkRules((rule) => {
|
|
538
|
+
const selectors = rule.selectors.map(restoreLegacyGroupHoverSelector);
|
|
539
|
+
|
|
540
|
+
if (selectors.every((selector, index) => selector === rule.selectors[index])) return;
|
|
541
|
+
|
|
542
|
+
rule.selectors = [...new Set(selectors)];
|
|
543
|
+
|
|
544
|
+
const signature = [
|
|
545
|
+
rule.selector,
|
|
546
|
+
...directDeclarations(rule)
|
|
547
|
+
.map(({ prop, value, important }) => `${prop}:${value}:${important}`),
|
|
548
|
+
].join('\0');
|
|
549
|
+
const restored = restoredByParent.get(rule.parent) ?? new Set();
|
|
550
|
+
|
|
551
|
+
if (restored.has(signature)) {
|
|
552
|
+
rule.remove();
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
restored.add(signature);
|
|
557
|
+
restoredByParent.set(rule.parent, restored);
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function restoreLegacyGroupHoverSelector(selector) {
|
|
562
|
+
const candidate = classNames(selector)
|
|
563
|
+
.map((className) => ({
|
|
564
|
+
className,
|
|
565
|
+
variant: classSegments(className)
|
|
566
|
+
.find((segment) => segment === 'group-hover' || segment.startsWith('group-hover/')),
|
|
567
|
+
}))
|
|
568
|
+
.find(({ variant }) => variant);
|
|
569
|
+
|
|
570
|
+
if (!candidate) return selector;
|
|
571
|
+
|
|
572
|
+
const groupName = `group${candidate.variant.slice('group-hover'.length)}`;
|
|
573
|
+
const groupSelector = `.${escapeClassName(groupName)}`;
|
|
574
|
+
const compoundStart = selector.indexOf(`:is(:where(${groupSelector})`);
|
|
575
|
+
|
|
576
|
+
if (compoundStart < 0) return selector;
|
|
577
|
+
|
|
578
|
+
const compoundEnd = closingParenthesis(selector, compoundStart + 3);
|
|
579
|
+
|
|
580
|
+
if (compoundEnd < 0) return selector;
|
|
581
|
+
|
|
582
|
+
return [
|
|
583
|
+
`${groupSelector}:hover `,
|
|
584
|
+
selector.slice(0, compoundStart),
|
|
585
|
+
selector.slice(compoundEnd + 1),
|
|
586
|
+
].join('');
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function closingParenthesis(value, openingIndex) {
|
|
590
|
+
let depth = 0;
|
|
591
|
+
|
|
592
|
+
for (let index = openingIndex;index < value.length;index += 1) {
|
|
593
|
+
if (value[index] === '(') depth += 1;
|
|
594
|
+
if (value[index] === ')') depth -= 1;
|
|
595
|
+
if (depth === 0) return index;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return -1;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function classNames(selector) {
|
|
602
|
+
const names = [];
|
|
603
|
+
let attributeDepth = 0;
|
|
604
|
+
|
|
605
|
+
for (let index = 0;index < selector.length;index += 1) {
|
|
606
|
+
if (selector[index] === '\\') {
|
|
607
|
+
index += 1;
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
if (selector[index] === '[') {
|
|
611
|
+
attributeDepth += 1;
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
if (selector[index] === ']') {
|
|
615
|
+
attributeDepth -= 1;
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
if (
|
|
619
|
+
attributeDepth > 0
|
|
620
|
+
|| selector[index] !== '.'
|
|
621
|
+
|| selector[index - 1] === '\\'
|
|
622
|
+
) continue;
|
|
623
|
+
|
|
624
|
+
let name = '';
|
|
625
|
+
index += 1;
|
|
626
|
+
|
|
627
|
+
while (index < selector.length) {
|
|
628
|
+
const character = selector[index];
|
|
629
|
+
|
|
630
|
+
if (character === '\\' && index + 1 < selector.length) {
|
|
631
|
+
name += selector[index + 1];
|
|
632
|
+
index += 2;
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
if (/[\s.#>+~,[\]()=:]/.test(character)) break;
|
|
637
|
+
|
|
638
|
+
name += character;
|
|
639
|
+
index += 1;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (name) names.push(name);
|
|
643
|
+
index -= 1;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return names;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function baseUtility(className) {
|
|
650
|
+
return className.split(':').at(-1).replace(/^!|!$/g, '');
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function descendantContainers(rule) {
|
|
654
|
+
const containers = [];
|
|
655
|
+
|
|
656
|
+
rule.walk((node) => {
|
|
657
|
+
if (node !== rule && node.nodes) containers.push(node);
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
return containers;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function directDeclarations(container) {
|
|
664
|
+
return container.nodes?.filter((node) => node.type === 'decl') ?? [];
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function restoreArbitraryValueOrder(root) {
|
|
668
|
+
reorderArbitraryValueSiblings(root);
|
|
669
|
+
|
|
670
|
+
root.each((node) => {
|
|
671
|
+
if (node.nodes) restoreArbitraryValueOrder(node);
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
function reorderLegacyStateVariantSiblings(container) {
|
|
676
|
+
const nodes = container.nodes ?? [];
|
|
677
|
+
const stateNodes = nodes.flatMap((node, index) => {
|
|
678
|
+
if (node.type !== 'rule') return [];
|
|
679
|
+
|
|
680
|
+
const variants = classNames(node.selector)
|
|
681
|
+
.map((className) => classSegments(className)
|
|
682
|
+
.slice(0, -1)
|
|
683
|
+
.filter((segment) => legacyStateVariantOrder.has(segment))
|
|
684
|
+
.map((segment) => legacyStateVariantOrder.get(segment))
|
|
685
|
+
.reverse())
|
|
686
|
+
.find((order) => order.length > 0);
|
|
687
|
+
|
|
688
|
+
if (!variants) return [];
|
|
689
|
+
|
|
690
|
+
return [{
|
|
691
|
+
index,
|
|
692
|
+
node,
|
|
693
|
+
order: variants,
|
|
694
|
+
}];
|
|
695
|
+
});
|
|
696
|
+
const stateSet = new Set(stateNodes.map(({ node }) => node));
|
|
697
|
+
const sorted = [...stateNodes].sort((left, right) => (
|
|
698
|
+
Math.min(...left.order) - Math.min(...right.order)
|
|
699
|
+
|| compareVariantOrders(left.order, right.order)
|
|
700
|
+
|| left.index - right.index
|
|
701
|
+
));
|
|
702
|
+
|
|
703
|
+
if (stateNodes.length > 0) {
|
|
704
|
+
container.nodes = [
|
|
705
|
+
...nodes.filter((node) => !stateSet.has(node)),
|
|
706
|
+
...sorted.map(({ node }) => node),
|
|
707
|
+
];
|
|
708
|
+
container.nodes.forEach((node) => {
|
|
709
|
+
node.parent = container;
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
container.nodes?.forEach((node) => {
|
|
714
|
+
if (node.nodes) reorderLegacyStateVariantSiblings(node);
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
function compareVariantOrders(left, right) {
|
|
719
|
+
const length = Math.max(left.length, right.length);
|
|
720
|
+
|
|
721
|
+
for (let index = 0;index < length;index += 1) {
|
|
722
|
+
const difference = (left[index] ?? -1) - (right[index] ?? -1);
|
|
723
|
+
|
|
724
|
+
if (difference !== 0) return difference;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return 0;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function reorderArbitraryValueSiblings(container) {
|
|
731
|
+
const groups = new Map();
|
|
732
|
+
|
|
733
|
+
container.nodes?.forEach((node, index) => {
|
|
734
|
+
if (node.type !== 'rule') return;
|
|
735
|
+
|
|
736
|
+
const candidate = classNames(node.selector)
|
|
737
|
+
.find((className) => className.includes('[') && className.includes(']'));
|
|
738
|
+
|
|
739
|
+
if (!candidate) return;
|
|
740
|
+
|
|
741
|
+
const normalizedCandidate = candidate.replace(/\[[^\]]*]/g, '[]');
|
|
742
|
+
const declarationSignature = [];
|
|
743
|
+
|
|
744
|
+
node.walkDecls((declaration) => {
|
|
745
|
+
declarationSignature.push(declaration.prop);
|
|
746
|
+
});
|
|
747
|
+
declarationSignature.sort();
|
|
748
|
+
|
|
749
|
+
const key = `${normalizedCandidate}\0${declarationSignature.join('\0')}`;
|
|
750
|
+
const group = groups.get(key) ?? [];
|
|
751
|
+
|
|
752
|
+
group.push({
|
|
753
|
+
candidate,
|
|
754
|
+
index,
|
|
755
|
+
node,
|
|
756
|
+
});
|
|
757
|
+
groups.set(key, group);
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
groups.forEach((group) => {
|
|
761
|
+
if (group.length < 2) return;
|
|
762
|
+
|
|
763
|
+
const sorted = [...group].sort((left, right) => {
|
|
764
|
+
if (left.candidate === right.candidate) return 0;
|
|
765
|
+
|
|
766
|
+
return left.candidate < right.candidate ? -1 : 1;
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
group.forEach(({ index }, sortedIndex) => {
|
|
770
|
+
const node = sorted[sortedIndex].node;
|
|
771
|
+
|
|
772
|
+
container.nodes[index] = node;
|
|
773
|
+
node.parent = container;
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function reorderResponsiveVariantSiblings(container) {
|
|
779
|
+
const nodes = container.nodes ?? [];
|
|
780
|
+
const responsiveNodes = nodes.flatMap((node) => {
|
|
781
|
+
const variant = responsiveVariantForNode(node);
|
|
782
|
+
|
|
783
|
+
if (!variant) return [];
|
|
784
|
+
|
|
785
|
+
return [{
|
|
786
|
+
node,
|
|
787
|
+
order: responsiveVariantOrder.get(variant),
|
|
788
|
+
}];
|
|
789
|
+
});
|
|
790
|
+
const sorted = [...responsiveNodes].sort((left, right) => left.order - right.order);
|
|
791
|
+
const responsiveSet = new Set(responsiveNodes.map(({ node }) => node));
|
|
792
|
+
|
|
793
|
+
container.nodes = [
|
|
794
|
+
...nodes.filter((node) => !responsiveSet.has(node)),
|
|
795
|
+
...sorted.map(({ node }) => node),
|
|
796
|
+
];
|
|
797
|
+
container.nodes.forEach((node) => {
|
|
798
|
+
node.parent = container;
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function responsiveVariantForNode(node) {
|
|
803
|
+
const selectors = [];
|
|
804
|
+
|
|
805
|
+
if (node.type === 'rule') selectors.push(node.selector);
|
|
806
|
+
node.walkRules?.((rule) => selectors.push(rule.selector));
|
|
807
|
+
|
|
808
|
+
return selectors
|
|
809
|
+
.flatMap(classNames)
|
|
810
|
+
.flatMap((className) => className.split(':'))
|
|
811
|
+
.find((segment) => responsiveVariantOrder.has(segment));
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
tailwindV4Compat.postcss = true;
|
|
815
|
+
|
|
816
|
+
module.exports = tailwindV4Compat;
|