tailwindcss 3.0.23 → 3.1.1
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/CHANGELOG.md +92 -2
- package/colors.d.ts +3 -0
- package/defaultConfig.d.ts +3 -0
- package/defaultTheme.d.ts +3 -0
- package/lib/cli-peer-dependencies.js +10 -5
- package/lib/cli.js +266 -203
- package/lib/constants.js +8 -8
- package/lib/corePluginList.js +1 -0
- package/lib/corePlugins.js +1640 -1562
- package/lib/css/preflight.css +1 -8
- package/lib/featureFlags.js +14 -12
- package/lib/index.js +16 -6
- package/lib/lib/cacheInvalidation.js +87 -0
- package/lib/lib/collapseAdjacentRules.js +30 -15
- package/lib/lib/collapseDuplicateDeclarations.js +1 -1
- package/lib/lib/defaultExtractor.js +191 -32
- package/lib/lib/detectNesting.js +9 -9
- package/lib/lib/evaluateTailwindFunctions.js +37 -28
- package/lib/lib/expandApplyAtRules.js +379 -189
- package/lib/lib/expandTailwindAtRules.js +168 -144
- package/lib/lib/generateRules.js +177 -95
- package/lib/lib/getModuleDependencies.js +14 -14
- package/lib/lib/normalizeTailwindDirectives.js +35 -35
- package/lib/lib/partitionApplyAtRules.js +7 -7
- package/lib/lib/regex.js +52 -0
- package/lib/lib/resolveDefaultsAtRules.js +96 -81
- package/lib/lib/setupContextUtils.js +202 -159
- package/lib/lib/setupTrackingContext.js +61 -63
- package/lib/lib/sharedState.js +10 -9
- package/lib/lib/substituteScreenAtRules.js +3 -4
- package/lib/postcss-plugins/nesting/README.md +2 -2
- package/lib/postcss-plugins/nesting/index.js +1 -1
- package/lib/postcss-plugins/nesting/plugin.js +40 -9
- package/lib/processTailwindFeatures.js +7 -7
- package/lib/public/colors.js +241 -241
- package/lib/public/resolve-config.js +5 -5
- package/lib/util/buildMediaQuery.js +2 -3
- package/lib/util/cloneDeep.js +3 -5
- package/lib/util/cloneNodes.js +12 -1
- package/lib/util/color.js +42 -51
- package/lib/util/createPlugin.js +1 -2
- package/lib/util/createUtilityPlugin.js +6 -7
- package/lib/util/dataTypes.js +85 -81
- package/lib/util/escapeClassName.js +5 -5
- package/lib/util/escapeCommas.js +1 -1
- package/lib/util/flattenColorPalette.js +4 -7
- package/lib/util/formatVariantSelector.js +82 -75
- package/lib/util/getAllConfigs.js +15 -10
- package/lib/util/hashConfig.js +5 -5
- package/lib/util/isKeyframeRule.js +1 -1
- package/lib/util/isPlainObject.js +1 -1
- package/lib/util/isValidArbitraryValue.js +26 -27
- package/lib/util/log.js +9 -10
- package/lib/util/nameClass.js +7 -7
- package/lib/util/negateValue.js +4 -5
- package/lib/util/normalizeConfig.js +68 -58
- package/lib/util/normalizeScreens.js +5 -6
- package/lib/util/parseAnimationValue.js +56 -57
- package/lib/util/parseBoxShadowValue.js +19 -20
- package/lib/util/parseDependency.js +32 -32
- package/lib/util/parseObjectStyles.js +6 -6
- package/lib/util/pluginUtils.js +20 -12
- package/lib/util/prefixSelector.js +1 -1
- package/lib/util/resolveConfig.js +81 -58
- package/lib/util/resolveConfigPath.js +16 -16
- package/lib/util/responsive.js +6 -6
- package/lib/util/splitAtTopLevelOnly.js +90 -0
- package/lib/util/toColorValue.js +1 -1
- package/lib/util/toPath.js +2 -2
- package/lib/util/transformThemeValue.js +30 -28
- package/lib/util/validateConfig.js +21 -0
- package/lib/util/withAlphaVariable.js +23 -23
- package/package.json +33 -27
- package/peers/index.js +7702 -5822
- package/plugin.d.ts +11 -0
- package/scripts/generate-types.js +52 -0
- package/src/cli-peer-dependencies.js +7 -1
- package/src/cli.js +118 -24
- package/src/corePluginList.js +1 -1
- package/src/corePlugins.js +109 -30
- package/src/css/preflight.css +1 -8
- package/src/featureFlags.js +4 -4
- package/src/index.js +15 -1
- package/src/lib/cacheInvalidation.js +52 -0
- package/src/lib/collapseAdjacentRules.js +21 -2
- package/src/lib/defaultExtractor.js +177 -35
- package/src/lib/evaluateTailwindFunctions.js +20 -4
- package/src/lib/expandApplyAtRules.js +418 -186
- package/src/lib/expandTailwindAtRules.js +29 -9
- package/src/lib/generateRules.js +137 -51
- package/src/lib/regex.js +74 -0
- package/src/lib/resolveDefaultsAtRules.js +53 -32
- package/src/lib/setupContextUtils.js +128 -65
- package/src/lib/setupTrackingContext.js +7 -3
- package/src/lib/sharedState.js +1 -0
- package/src/postcss-plugins/nesting/README.md +2 -2
- package/src/postcss-plugins/nesting/plugin.js +36 -0
- package/src/util/cloneNodes.js +14 -1
- package/src/util/color.js +25 -21
- package/src/util/dataTypes.js +14 -6
- package/src/util/formatVariantSelector.js +79 -62
- package/src/util/getAllConfigs.js +7 -0
- package/src/util/log.js +8 -8
- package/src/util/normalizeConfig.js +0 -8
- package/src/util/parseBoxShadowValue.js +3 -2
- package/src/util/pluginUtils.js +13 -1
- package/src/util/resolveConfig.js +66 -22
- package/src/util/splitAtTopLevelOnly.js +71 -0
- package/src/util/toPath.js +1 -1
- package/src/util/transformThemeValue.js +4 -2
- package/src/util/validateConfig.js +13 -0
- package/src/util/withAlphaVariable.js +1 -1
- package/stubs/defaultConfig.stub.js +5 -1
- package/stubs/simpleConfig.stub.js +1 -0
- package/types/config.d.ts +325 -0
- package/types/generated/.gitkeep +0 -0
- package/types/generated/colors.d.ts +276 -0
- package/types/generated/corePluginList.d.ts +1 -0
- package/types/index.d.ts +7 -0
|
@@ -17,14 +17,14 @@ const builtInTransformers = {
|
|
|
17
17
|
svelte: (content) => content.replace(/(?:^|\s)class:/g, ' '),
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
function getExtractor(
|
|
21
|
-
let extractors = tailwindConfig.content.extract
|
|
20
|
+
function getExtractor(context, fileExtension) {
|
|
21
|
+
let extractors = context.tailwindConfig.content.extract
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
extractors[fileExtension] ||
|
|
25
25
|
extractors.DEFAULT ||
|
|
26
26
|
builtInExtractors[fileExtension] ||
|
|
27
|
-
builtInExtractors.DEFAULT
|
|
27
|
+
builtInExtractors.DEFAULT(context)
|
|
28
28
|
)
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -165,7 +165,7 @@ export default function expandTailwindAtRules(context) {
|
|
|
165
165
|
|
|
166
166
|
for (let { content, extension } of context.changedContent) {
|
|
167
167
|
let transformer = getTransformer(context.tailwindConfig, extension)
|
|
168
|
-
let extractor = getExtractor(context
|
|
168
|
+
let extractor = getExtractor(context, extension)
|
|
169
169
|
getClassCandidates(transformer(content), extractor, candidates, seen)
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -204,17 +204,29 @@ export default function expandTailwindAtRules(context) {
|
|
|
204
204
|
// Replace any Tailwind directives with generated CSS
|
|
205
205
|
|
|
206
206
|
if (layerNodes.base) {
|
|
207
|
-
layerNodes.base.before(
|
|
207
|
+
layerNodes.base.before(
|
|
208
|
+
cloneNodes([...baseNodes, ...defaultNodes], layerNodes.base.source, {
|
|
209
|
+
layer: 'base',
|
|
210
|
+
})
|
|
211
|
+
)
|
|
208
212
|
layerNodes.base.remove()
|
|
209
213
|
}
|
|
210
214
|
|
|
211
215
|
if (layerNodes.components) {
|
|
212
|
-
layerNodes.components.before(
|
|
216
|
+
layerNodes.components.before(
|
|
217
|
+
cloneNodes([...componentNodes], layerNodes.components.source, {
|
|
218
|
+
layer: 'components',
|
|
219
|
+
})
|
|
220
|
+
)
|
|
213
221
|
layerNodes.components.remove()
|
|
214
222
|
}
|
|
215
223
|
|
|
216
224
|
if (layerNodes.utilities) {
|
|
217
|
-
layerNodes.utilities.before(
|
|
225
|
+
layerNodes.utilities.before(
|
|
226
|
+
cloneNodes([...utilityNodes], layerNodes.utilities.source, {
|
|
227
|
+
layer: 'utilities',
|
|
228
|
+
})
|
|
229
|
+
)
|
|
218
230
|
layerNodes.utilities.remove()
|
|
219
231
|
}
|
|
220
232
|
|
|
@@ -234,10 +246,18 @@ export default function expandTailwindAtRules(context) {
|
|
|
234
246
|
})
|
|
235
247
|
|
|
236
248
|
if (layerNodes.variants) {
|
|
237
|
-
layerNodes.variants.before(
|
|
249
|
+
layerNodes.variants.before(
|
|
250
|
+
cloneNodes(variantNodes, layerNodes.variants.source, {
|
|
251
|
+
layer: 'variants',
|
|
252
|
+
})
|
|
253
|
+
)
|
|
238
254
|
layerNodes.variants.remove()
|
|
239
255
|
} else if (variantNodes.length > 0) {
|
|
240
|
-
root.append(
|
|
256
|
+
root.append(
|
|
257
|
+
cloneNodes(variantNodes, root.source, {
|
|
258
|
+
layer: 'variants',
|
|
259
|
+
})
|
|
260
|
+
)
|
|
241
261
|
}
|
|
242
262
|
|
|
243
263
|
// If we've got a utility layer and no utilities are generated there's likely something wrong
|
package/src/lib/generateRules.js
CHANGED
|
@@ -9,7 +9,10 @@ import * as sharedState from './sharedState'
|
|
|
9
9
|
import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector'
|
|
10
10
|
import { asClass } from '../util/nameClass'
|
|
11
11
|
import { normalize } from '../util/dataTypes'
|
|
12
|
+
import { isValidVariantFormatString, parseVariant } from './setupContextUtils'
|
|
12
13
|
import isValidArbitraryValue from '../util/isValidArbitraryValue'
|
|
14
|
+
import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly.js'
|
|
15
|
+
import { flagEnabled } from '../featureFlags'
|
|
13
16
|
|
|
14
17
|
let classNameParser = selectorParser((selectors) => {
|
|
15
18
|
return selectors.first.filter(({ type }) => type === 'class').pop().value
|
|
@@ -88,7 +91,7 @@ function applyPrefix(matches, context) {
|
|
|
88
91
|
return matches
|
|
89
92
|
}
|
|
90
93
|
|
|
91
|
-
function applyImportant(matches) {
|
|
94
|
+
function applyImportant(matches, classCandidate) {
|
|
92
95
|
if (matches.length === 0) {
|
|
93
96
|
return matches
|
|
94
97
|
}
|
|
@@ -98,7 +101,10 @@ function applyImportant(matches) {
|
|
|
98
101
|
let container = postcss.root({ nodes: [rule.clone()] })
|
|
99
102
|
container.walkRules((r) => {
|
|
100
103
|
r.selector = updateAllClasses(r.selector, (className) => {
|
|
101
|
-
|
|
104
|
+
if (className === classCandidate) {
|
|
105
|
+
return `!${className}`
|
|
106
|
+
}
|
|
107
|
+
return className
|
|
102
108
|
})
|
|
103
109
|
r.walkDecls((d) => (d.important = true))
|
|
104
110
|
})
|
|
@@ -122,8 +128,31 @@ function applyVariant(variant, matches, context) {
|
|
|
122
128
|
return matches
|
|
123
129
|
}
|
|
124
130
|
|
|
131
|
+
let args
|
|
132
|
+
|
|
133
|
+
// Find partial arbitrary variants
|
|
134
|
+
if (variant.endsWith(']') && !variant.startsWith('[')) {
|
|
135
|
+
args = variant.slice(variant.lastIndexOf('[') + 1, -1)
|
|
136
|
+
variant = variant.slice(0, variant.indexOf(args) - 1 /* - */ - 1 /* [ */)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Register arbitrary variants
|
|
140
|
+
if (isArbitraryValue(variant) && !context.variantMap.has(variant)) {
|
|
141
|
+
let selector = normalize(variant.slice(1, -1))
|
|
142
|
+
|
|
143
|
+
if (!isValidVariantFormatString(selector)) {
|
|
144
|
+
return []
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let fn = parseVariant(selector)
|
|
148
|
+
|
|
149
|
+
let sort = Array.from(context.variantOrder.values()).pop() << 1n
|
|
150
|
+
context.variantMap.set(variant, [[sort, fn]])
|
|
151
|
+
context.variantOrder.set(variant, sort)
|
|
152
|
+
}
|
|
153
|
+
|
|
125
154
|
if (context.variantMap.has(variant)) {
|
|
126
|
-
let variantFunctionTuples = context.variantMap.get(variant)
|
|
155
|
+
let variantFunctionTuples = context.variantMap.get(variant).slice()
|
|
127
156
|
let result = []
|
|
128
157
|
|
|
129
158
|
for (let [meta, rule] of matches) {
|
|
@@ -184,8 +213,29 @@ function applyVariant(variant, matches, context) {
|
|
|
184
213
|
format(selectorFormat) {
|
|
185
214
|
collectedFormats.push(selectorFormat)
|
|
186
215
|
},
|
|
216
|
+
args,
|
|
187
217
|
})
|
|
188
218
|
|
|
219
|
+
// It can happen that a list of format strings is returned from within the function. In that
|
|
220
|
+
// case, we have to process them as well. We can use the existing `variantSort`.
|
|
221
|
+
if (Array.isArray(ruleWithVariant)) {
|
|
222
|
+
for (let [idx, variantFunction] of ruleWithVariant.entries()) {
|
|
223
|
+
// This is a little bit scary since we are pushing to an array of items that we are
|
|
224
|
+
// currently looping over. However, you can also think of it like a processing queue
|
|
225
|
+
// where you keep handling jobs until everything is done and each job can queue more
|
|
226
|
+
// jobs if needed.
|
|
227
|
+
variantFunctionTuples.push([
|
|
228
|
+
// TODO: This could have potential bugs if we shift the sort order from variant A far
|
|
229
|
+
// enough into the sort space of variant B. The chances are low, but if this happens
|
|
230
|
+
// then this might be the place too look at. One potential solution to this problem is
|
|
231
|
+
// reserving additional X places for these 'unknown' variants in between.
|
|
232
|
+
variantSort | BigInt(idx << ruleWithVariant.length),
|
|
233
|
+
variantFunction,
|
|
234
|
+
])
|
|
235
|
+
}
|
|
236
|
+
continue
|
|
237
|
+
}
|
|
238
|
+
|
|
189
239
|
if (typeof ruleWithVariant === 'string') {
|
|
190
240
|
collectedFormats.push(ruleWithVariant)
|
|
191
241
|
}
|
|
@@ -300,6 +350,19 @@ function looksLikeUri(declaration) {
|
|
|
300
350
|
}
|
|
301
351
|
}
|
|
302
352
|
|
|
353
|
+
function isParsableNode(node) {
|
|
354
|
+
let isParsable = true
|
|
355
|
+
|
|
356
|
+
node.walkDecls((decl) => {
|
|
357
|
+
if (!isParsableCssValue(decl.name, decl.value)) {
|
|
358
|
+
isParsable = false
|
|
359
|
+
return false
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
return isParsable
|
|
364
|
+
}
|
|
365
|
+
|
|
303
366
|
function isParsableCssValue(property, value) {
|
|
304
367
|
// We don't want to to treat [https://example.com] as a custom property
|
|
305
368
|
// Even though, according to the CSS grammar, it's a totally valid CSS declaration
|
|
@@ -366,7 +429,11 @@ function* resolveMatchedPlugins(classCandidate, context) {
|
|
|
366
429
|
const twConfigPrefix = context.tailwindConfig.prefix
|
|
367
430
|
|
|
368
431
|
const twConfigPrefixLen = twConfigPrefix.length
|
|
369
|
-
|
|
432
|
+
|
|
433
|
+
const hasMatchingPrefix =
|
|
434
|
+
candidatePrefix.startsWith(twConfigPrefix) || candidatePrefix.startsWith(`-${twConfigPrefix}`)
|
|
435
|
+
|
|
436
|
+
if (candidatePrefix[twConfigPrefixLen] === '-' && hasMatchingPrefix) {
|
|
370
437
|
negative = true
|
|
371
438
|
candidatePrefix = twConfigPrefix + candidatePrefix.slice(twConfigPrefixLen + 1)
|
|
372
439
|
}
|
|
@@ -387,7 +454,7 @@ function splitWithSeparator(input, separator) {
|
|
|
387
454
|
return [sharedState.NOT_ON_DEMAND]
|
|
388
455
|
}
|
|
389
456
|
|
|
390
|
-
return
|
|
457
|
+
return Array.from(splitAtTopLevelOnly(input, separator))
|
|
391
458
|
}
|
|
392
459
|
|
|
393
460
|
function* recordCandidates(matches, classCandidate) {
|
|
@@ -398,7 +465,7 @@ function* recordCandidates(matches, classCandidate) {
|
|
|
398
465
|
}
|
|
399
466
|
}
|
|
400
467
|
|
|
401
|
-
function* resolveMatches(candidate, context) {
|
|
468
|
+
function* resolveMatches(candidate, context, original = candidate) {
|
|
402
469
|
let separator = context.tailwindConfig.separator
|
|
403
470
|
let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse()
|
|
404
471
|
let important = false
|
|
@@ -408,6 +475,15 @@ function* resolveMatches(candidate, context) {
|
|
|
408
475
|
classCandidate = classCandidate.slice(1)
|
|
409
476
|
}
|
|
410
477
|
|
|
478
|
+
if (flagEnabled(context.tailwindConfig, 'variantGrouping')) {
|
|
479
|
+
if (classCandidate.startsWith('(') && classCandidate.endsWith(')')) {
|
|
480
|
+
let base = variants.slice().reverse().join(separator)
|
|
481
|
+
for (let part of splitAtTopLevelOnly(classCandidate.slice(1, -1), ',')) {
|
|
482
|
+
yield* resolveMatches(base + separator + part, context, original)
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
411
487
|
// TODO: Reintroduce this in ways that doesn't break on false positives
|
|
412
488
|
// function sortAgainst(toSort, against) {
|
|
413
489
|
// return toSort.slice().sort((a, z) => {
|
|
@@ -453,60 +529,66 @@ function* resolveMatches(candidate, context) {
|
|
|
453
529
|
}
|
|
454
530
|
}
|
|
455
531
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
532
|
+
if (isArbitraryValue(modifier)) {
|
|
533
|
+
// When generated arbitrary values are ambiguous, we can't know
|
|
534
|
+
// which to pick so don't generate any utilities for them
|
|
535
|
+
if (matches.length > 1) {
|
|
536
|
+
let typesPerPlugin = matches.map((match) => new Set([...(typesByMatches.get(match) ?? [])]))
|
|
460
537
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
538
|
+
// Remove duplicates, so that we can detect proper unique types for each plugin.
|
|
539
|
+
for (let pluginTypes of typesPerPlugin) {
|
|
540
|
+
for (let type of pluginTypes) {
|
|
541
|
+
let removeFromOwnGroup = false
|
|
465
542
|
|
|
466
|
-
|
|
467
|
-
|
|
543
|
+
for (let otherGroup of typesPerPlugin) {
|
|
544
|
+
if (pluginTypes === otherGroup) continue
|
|
468
545
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
546
|
+
if (otherGroup.has(type)) {
|
|
547
|
+
otherGroup.delete(type)
|
|
548
|
+
removeFromOwnGroup = true
|
|
549
|
+
}
|
|
472
550
|
}
|
|
473
|
-
}
|
|
474
551
|
|
|
475
|
-
|
|
552
|
+
if (removeFromOwnGroup) pluginTypes.delete(type)
|
|
553
|
+
}
|
|
476
554
|
}
|
|
477
|
-
}
|
|
478
555
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
556
|
+
let messages = []
|
|
557
|
+
|
|
558
|
+
for (let [idx, group] of typesPerPlugin.entries()) {
|
|
559
|
+
for (let type of group) {
|
|
560
|
+
let rules = matches[idx]
|
|
561
|
+
.map(([, rule]) => rule)
|
|
562
|
+
.flat()
|
|
563
|
+
.map((rule) =>
|
|
564
|
+
rule
|
|
565
|
+
.toString()
|
|
566
|
+
.split('\n')
|
|
567
|
+
.slice(1, -1) // Remove selector and closing '}'
|
|
568
|
+
.map((line) => line.trim())
|
|
569
|
+
.map((x) => ` ${x}`) // Re-indent
|
|
570
|
+
.join('\n')
|
|
571
|
+
)
|
|
572
|
+
.join('\n\n')
|
|
573
|
+
|
|
574
|
+
messages.push(
|
|
575
|
+
` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\``
|
|
494
576
|
)
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
messages.push(` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\``)
|
|
498
|
-
break
|
|
577
|
+
break
|
|
578
|
+
}
|
|
499
579
|
}
|
|
580
|
+
|
|
581
|
+
log.warn([
|
|
582
|
+
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
|
|
583
|
+
...messages,
|
|
584
|
+
`If this is content and not a class, replace it with \`${candidate
|
|
585
|
+
.replace('[', '[')
|
|
586
|
+
.replace(']', ']')}\` to silence this warning.`,
|
|
587
|
+
])
|
|
588
|
+
continue
|
|
500
589
|
}
|
|
501
590
|
|
|
502
|
-
|
|
503
|
-
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
|
|
504
|
-
...messages,
|
|
505
|
-
`If this is content and not a class, replace it with \`${candidate
|
|
506
|
-
.replace('[', '[')
|
|
507
|
-
.replace(']', ']')}\` to silence this warning.`,
|
|
508
|
-
])
|
|
509
|
-
continue
|
|
591
|
+
matches = matches.map((list) => list.filter((match) => isParsableNode(match[1])))
|
|
510
592
|
}
|
|
511
593
|
|
|
512
594
|
matches = matches.flat()
|
|
@@ -514,7 +596,7 @@ function* resolveMatches(candidate, context) {
|
|
|
514
596
|
matches = applyPrefix(matches, context)
|
|
515
597
|
|
|
516
598
|
if (important) {
|
|
517
|
-
matches = applyImportant(matches,
|
|
599
|
+
matches = applyImportant(matches, classCandidate)
|
|
518
600
|
}
|
|
519
601
|
|
|
520
602
|
for (let variant of variants) {
|
|
@@ -533,7 +615,11 @@ function* resolveMatches(candidate, context) {
|
|
|
533
615
|
|
|
534
616
|
rule.selector = finalizeSelector(finalFormat, {
|
|
535
617
|
selector: rule.selector,
|
|
536
|
-
candidate,
|
|
618
|
+
candidate: original,
|
|
619
|
+
base: candidate
|
|
620
|
+
.split(new RegExp(`\\${context?.tailwindConfig?.separator ?? ':'}(?![^[]*\\])`))
|
|
621
|
+
.pop(),
|
|
622
|
+
|
|
537
623
|
context,
|
|
538
624
|
})
|
|
539
625
|
})
|
package/src/lib/regex.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const REGEX_SPECIAL = /[\\^$.*+?()[\]{}|]/g
|
|
2
|
+
const REGEX_HAS_SPECIAL = RegExp(REGEX_SPECIAL.source)
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string|RegExp|Array<string|RegExp>} source
|
|
6
|
+
*/
|
|
7
|
+
function toSource(source) {
|
|
8
|
+
source = Array.isArray(source) ? source : [source]
|
|
9
|
+
|
|
10
|
+
source = source.map((item) => (item instanceof RegExp ? item.source : item))
|
|
11
|
+
|
|
12
|
+
return source.join('')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string|RegExp|Array<string|RegExp>} source
|
|
17
|
+
*/
|
|
18
|
+
export function pattern(source) {
|
|
19
|
+
return new RegExp(toSource(source), 'g')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {string|RegExp|Array<string|RegExp>} source
|
|
24
|
+
*/
|
|
25
|
+
export function withoutCapturing(source) {
|
|
26
|
+
return new RegExp(`(?:${toSource(source)})`, 'g')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {Array<string|RegExp>} sources
|
|
31
|
+
*/
|
|
32
|
+
export function any(sources) {
|
|
33
|
+
return `(?:${sources.map(toSource).join('|')})`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {string|RegExp} source
|
|
38
|
+
*/
|
|
39
|
+
export function optional(source) {
|
|
40
|
+
return `(?:${toSource(source)})?`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string|RegExp|Array<string|RegExp>} source
|
|
45
|
+
*/
|
|
46
|
+
export function zeroOrMore(source) {
|
|
47
|
+
return `(?:${toSource(source)})*`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generate a RegExp that matches balanced brackets for a given depth
|
|
52
|
+
* We have to specify a depth because JS doesn't support recursive groups using ?R
|
|
53
|
+
*
|
|
54
|
+
* Based on https://stackoverflow.com/questions/17759004/how-to-match-string-within-parentheses-nested-in-java/17759264#17759264
|
|
55
|
+
*
|
|
56
|
+
* @param {string|RegExp|Array<string|RegExp>} source
|
|
57
|
+
*/
|
|
58
|
+
export function nestedBrackets(open, close, depth = 1) {
|
|
59
|
+
return withoutCapturing([
|
|
60
|
+
escape(open),
|
|
61
|
+
/[^\s]*/,
|
|
62
|
+
depth === 1
|
|
63
|
+
? `[^${escape(open)}${escape(close)}\s]*`
|
|
64
|
+
: any([`[^${escape(open)}${escape(close)}\s]*`, nestedBrackets(open, close, depth - 1)]),
|
|
65
|
+
/[^\s]*/,
|
|
66
|
+
escape(close),
|
|
67
|
+
])
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function escape(string) {
|
|
71
|
+
return string && REGEX_HAS_SPECIAL.test(string)
|
|
72
|
+
? string.replace(REGEX_SPECIAL, '\\$&')
|
|
73
|
+
: string || ''
|
|
74
|
+
}
|
|
@@ -91,52 +91,73 @@ export default function resolveDefaultsAtRules({ tailwindConfig }) {
|
|
|
91
91
|
rule.remove()
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
if (flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
|
|
95
|
+
for (let universal of universals) {
|
|
96
|
+
/** @type {Map<string, Set<string>>} */
|
|
97
|
+
let selectorGroups = new Map()
|
|
98
|
+
|
|
99
|
+
let rules = variableNodeMap.get(universal.params) ?? []
|
|
100
|
+
|
|
101
|
+
for (let rule of rules) {
|
|
102
|
+
for (let selector of extractElementSelector(rule.selector)) {
|
|
103
|
+
// If selector contains a vendor prefix after a pseudo element or class,
|
|
104
|
+
// we consider them separately because merging the declarations into
|
|
105
|
+
// a single rule will cause browsers that do not understand the
|
|
106
|
+
// vendor prefix to throw out the whole rule
|
|
107
|
+
let selectorGroupName =
|
|
108
|
+
selector.includes(':-') || selector.includes('::-') ? selector : '__DEFAULT__'
|
|
109
|
+
|
|
110
|
+
let selectors = selectorGroups.get(selectorGroupName) ?? new Set()
|
|
111
|
+
selectorGroups.set(selectorGroupName, selectors)
|
|
112
|
+
|
|
113
|
+
selectors.add(selector)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
97
116
|
|
|
98
|
-
|
|
117
|
+
if (flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
|
|
118
|
+
if (selectorGroups.size === 0) {
|
|
119
|
+
universal.remove()
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
99
122
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// a single rule will cause browsers that do not understand the
|
|
105
|
-
// vendor prefix to throw out the whole rule
|
|
106
|
-
let selectorGroupName =
|
|
107
|
-
selector.includes(':-') || selector.includes('::-') ? selector : '__DEFAULT__'
|
|
123
|
+
for (let [, selectors] of selectorGroups) {
|
|
124
|
+
let universalRule = postcss.rule({
|
|
125
|
+
source: universal.source,
|
|
126
|
+
})
|
|
108
127
|
|
|
109
|
-
|
|
110
|
-
selectorGroups.set(selectorGroupName, selectors)
|
|
128
|
+
universalRule.selectors = [...selectors]
|
|
111
129
|
|
|
112
|
-
|
|
130
|
+
universalRule.append(universal.nodes.map((node) => node.clone()))
|
|
131
|
+
universal.before(universalRule)
|
|
132
|
+
}
|
|
113
133
|
}
|
|
114
|
-
}
|
|
115
134
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
for (let [, selectors] of selectorGroups) {
|
|
123
|
-
let universalRule = postcss.rule()
|
|
135
|
+
universal.remove()
|
|
136
|
+
}
|
|
137
|
+
} else if (universals.size) {
|
|
138
|
+
let universalRule = postcss.rule({
|
|
139
|
+
selectors: ['*', '::before', '::after'],
|
|
140
|
+
})
|
|
124
141
|
|
|
125
|
-
|
|
142
|
+
for (let universal of universals) {
|
|
143
|
+
universalRule.append(universal.nodes)
|
|
126
144
|
|
|
127
|
-
|
|
145
|
+
if (!universalRule.parent) {
|
|
128
146
|
universal.before(universalRule)
|
|
129
147
|
}
|
|
130
|
-
} else {
|
|
131
|
-
let universalRule = postcss.rule()
|
|
132
148
|
|
|
133
|
-
universalRule.
|
|
149
|
+
if (!universalRule.source) {
|
|
150
|
+
universalRule.source = universal.source
|
|
151
|
+
}
|
|
134
152
|
|
|
135
|
-
|
|
136
|
-
universal.before(universalRule)
|
|
153
|
+
universal.remove()
|
|
137
154
|
}
|
|
138
155
|
|
|
139
|
-
|
|
156
|
+
let backdropRule = universalRule.clone({
|
|
157
|
+
selectors: ['::backdrop'],
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
universalRule.after(backdropRule)
|
|
140
161
|
}
|
|
141
162
|
}
|
|
142
163
|
}
|