tailwindcss 3.0.22 → 3.1.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/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 +1662 -1554
- 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 -30
- 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 +190 -81
- 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 +80 -79
- package/lib/lib/setupContextUtils.js +207 -170
- package/lib/lib/setupTrackingContext.js +61 -63
- package/lib/lib/sharedState.js +11 -8
- 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 +7728 -5848
- 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 +142 -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 -33
- package/src/lib/evaluateTailwindFunctions.js +20 -4
- package/src/lib/expandApplyAtRules.js +418 -186
- package/src/lib/expandTailwindAtRules.js +30 -10
- package/src/lib/generateRules.js +142 -51
- package/src/lib/regex.js +74 -0
- package/src/lib/resolveDefaultsAtRules.js +7 -3
- package/src/lib/setupContextUtils.js +142 -87
- package/src/lib/setupTrackingContext.js +7 -3
- package/src/lib/sharedState.js +2 -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 +1 -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
|
|
|
@@ -158,14 +158,14 @@ export default function expandTailwindAtRules(context) {
|
|
|
158
158
|
// ---
|
|
159
159
|
|
|
160
160
|
// Find potential rules in changed files
|
|
161
|
-
let candidates = new Set([
|
|
161
|
+
let candidates = new Set([sharedState.NOT_ON_DEMAND])
|
|
162
162
|
let seen = new Set()
|
|
163
163
|
|
|
164
164
|
env.DEBUG && console.time('Reading changed files')
|
|
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
|
@@ -5,10 +5,14 @@ import isPlainObject from '../util/isPlainObject'
|
|
|
5
5
|
import prefixSelector from '../util/prefixSelector'
|
|
6
6
|
import { updateAllClasses } from '../util/pluginUtils'
|
|
7
7
|
import log from '../util/log'
|
|
8
|
+
import * as sharedState from './sharedState'
|
|
8
9
|
import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector'
|
|
9
10
|
import { asClass } from '../util/nameClass'
|
|
10
11
|
import { normalize } from '../util/dataTypes'
|
|
12
|
+
import { isValidVariantFormatString, parseVariant } from './setupContextUtils'
|
|
11
13
|
import isValidArbitraryValue from '../util/isValidArbitraryValue'
|
|
14
|
+
import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly.js'
|
|
15
|
+
import { flagEnabled } from '../featureFlags'
|
|
12
16
|
|
|
13
17
|
let classNameParser = selectorParser((selectors) => {
|
|
14
18
|
return selectors.first.filter(({ type }) => type === 'class').pop().value
|
|
@@ -87,7 +91,7 @@ function applyPrefix(matches, context) {
|
|
|
87
91
|
return matches
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
function applyImportant(matches) {
|
|
94
|
+
function applyImportant(matches, classCandidate) {
|
|
91
95
|
if (matches.length === 0) {
|
|
92
96
|
return matches
|
|
93
97
|
}
|
|
@@ -97,7 +101,10 @@ function applyImportant(matches) {
|
|
|
97
101
|
let container = postcss.root({ nodes: [rule.clone()] })
|
|
98
102
|
container.walkRules((r) => {
|
|
99
103
|
r.selector = updateAllClasses(r.selector, (className) => {
|
|
100
|
-
|
|
104
|
+
if (className === classCandidate) {
|
|
105
|
+
return `!${className}`
|
|
106
|
+
}
|
|
107
|
+
return className
|
|
101
108
|
})
|
|
102
109
|
r.walkDecls((d) => (d.important = true))
|
|
103
110
|
})
|
|
@@ -121,8 +128,31 @@ function applyVariant(variant, matches, context) {
|
|
|
121
128
|
return matches
|
|
122
129
|
}
|
|
123
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
|
+
|
|
124
154
|
if (context.variantMap.has(variant)) {
|
|
125
|
-
let variantFunctionTuples = context.variantMap.get(variant)
|
|
155
|
+
let variantFunctionTuples = context.variantMap.get(variant).slice()
|
|
126
156
|
let result = []
|
|
127
157
|
|
|
128
158
|
for (let [meta, rule] of matches) {
|
|
@@ -183,8 +213,29 @@ function applyVariant(variant, matches, context) {
|
|
|
183
213
|
format(selectorFormat) {
|
|
184
214
|
collectedFormats.push(selectorFormat)
|
|
185
215
|
},
|
|
216
|
+
args,
|
|
186
217
|
})
|
|
187
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
|
+
|
|
188
239
|
if (typeof ruleWithVariant === 'string') {
|
|
189
240
|
collectedFormats.push(ruleWithVariant)
|
|
190
241
|
}
|
|
@@ -299,6 +350,19 @@ function looksLikeUri(declaration) {
|
|
|
299
350
|
}
|
|
300
351
|
}
|
|
301
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
|
+
|
|
302
366
|
function isParsableCssValue(property, value) {
|
|
303
367
|
// We don't want to to treat [https://example.com] as a custom property
|
|
304
368
|
// Even though, according to the CSS grammar, it's a totally valid CSS declaration
|
|
@@ -365,7 +429,11 @@ function* resolveMatchedPlugins(classCandidate, context) {
|
|
|
365
429
|
const twConfigPrefix = context.tailwindConfig.prefix
|
|
366
430
|
|
|
367
431
|
const twConfigPrefixLen = twConfigPrefix.length
|
|
368
|
-
|
|
432
|
+
|
|
433
|
+
const hasMatchingPrefix =
|
|
434
|
+
candidatePrefix.startsWith(twConfigPrefix) || candidatePrefix.startsWith(`-${twConfigPrefix}`)
|
|
435
|
+
|
|
436
|
+
if (candidatePrefix[twConfigPrefixLen] === '-' && hasMatchingPrefix) {
|
|
369
437
|
negative = true
|
|
370
438
|
candidatePrefix = twConfigPrefix + candidatePrefix.slice(twConfigPrefixLen + 1)
|
|
371
439
|
}
|
|
@@ -382,7 +450,11 @@ function* resolveMatchedPlugins(classCandidate, context) {
|
|
|
382
450
|
}
|
|
383
451
|
|
|
384
452
|
function splitWithSeparator(input, separator) {
|
|
385
|
-
|
|
453
|
+
if (input === sharedState.NOT_ON_DEMAND) {
|
|
454
|
+
return [sharedState.NOT_ON_DEMAND]
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return Array.from(splitAtTopLevelOnly(input, separator))
|
|
386
458
|
}
|
|
387
459
|
|
|
388
460
|
function* recordCandidates(matches, classCandidate) {
|
|
@@ -393,7 +465,7 @@ function* recordCandidates(matches, classCandidate) {
|
|
|
393
465
|
}
|
|
394
466
|
}
|
|
395
467
|
|
|
396
|
-
function* resolveMatches(candidate, context) {
|
|
468
|
+
function* resolveMatches(candidate, context, original = candidate) {
|
|
397
469
|
let separator = context.tailwindConfig.separator
|
|
398
470
|
let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse()
|
|
399
471
|
let important = false
|
|
@@ -403,6 +475,15 @@ function* resolveMatches(candidate, context) {
|
|
|
403
475
|
classCandidate = classCandidate.slice(1)
|
|
404
476
|
}
|
|
405
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
|
+
|
|
406
487
|
// TODO: Reintroduce this in ways that doesn't break on false positives
|
|
407
488
|
// function sortAgainst(toSort, against) {
|
|
408
489
|
// return toSort.slice().sort((a, z) => {
|
|
@@ -448,60 +529,66 @@ function* resolveMatches(candidate, context) {
|
|
|
448
529
|
}
|
|
449
530
|
}
|
|
450
531
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
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) ?? [])]))
|
|
455
537
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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
|
|
460
542
|
|
|
461
|
-
|
|
462
|
-
|
|
543
|
+
for (let otherGroup of typesPerPlugin) {
|
|
544
|
+
if (pluginTypes === otherGroup) continue
|
|
463
545
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
546
|
+
if (otherGroup.has(type)) {
|
|
547
|
+
otherGroup.delete(type)
|
|
548
|
+
removeFromOwnGroup = true
|
|
549
|
+
}
|
|
467
550
|
}
|
|
468
|
-
}
|
|
469
551
|
|
|
470
|
-
|
|
552
|
+
if (removeFromOwnGroup) pluginTypes.delete(type)
|
|
553
|
+
}
|
|
471
554
|
}
|
|
472
|
-
}
|
|
473
555
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
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()}\``
|
|
489
576
|
)
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
messages.push(` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\``)
|
|
493
|
-
break
|
|
577
|
+
break
|
|
578
|
+
}
|
|
494
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
|
|
495
589
|
}
|
|
496
590
|
|
|
497
|
-
|
|
498
|
-
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
|
|
499
|
-
...messages,
|
|
500
|
-
`If this is content and not a class, replace it with \`${candidate
|
|
501
|
-
.replace('[', '[')
|
|
502
|
-
.replace(']', ']')}\` to silence this warning.`,
|
|
503
|
-
])
|
|
504
|
-
continue
|
|
591
|
+
matches = matches.map((list) => list.filter((match) => isParsableNode(match[1])))
|
|
505
592
|
}
|
|
506
593
|
|
|
507
594
|
matches = matches.flat()
|
|
@@ -509,7 +596,7 @@ function* resolveMatches(candidate, context) {
|
|
|
509
596
|
matches = applyPrefix(matches, context)
|
|
510
597
|
|
|
511
598
|
if (important) {
|
|
512
|
-
matches = applyImportant(matches,
|
|
599
|
+
matches = applyImportant(matches, classCandidate)
|
|
513
600
|
}
|
|
514
601
|
|
|
515
602
|
for (let variant of variants) {
|
|
@@ -528,7 +615,11 @@ function* resolveMatches(candidate, context) {
|
|
|
528
615
|
|
|
529
616
|
rule.selector = finalizeSelector(finalFormat, {
|
|
530
617
|
selector: rule.selector,
|
|
531
|
-
candidate,
|
|
618
|
+
candidate: original,
|
|
619
|
+
base: candidate
|
|
620
|
+
.split(new RegExp(`\\${context?.tailwindConfig?.separator ?? ':'}(?![^[]*\\])`))
|
|
621
|
+
.pop(),
|
|
622
|
+
|
|
532
623
|
context,
|
|
533
624
|
})
|
|
534
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
|
+
}
|
|
@@ -120,7 +120,9 @@ export default function resolveDefaultsAtRules({ tailwindConfig }) {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
for (let [, selectors] of selectorGroups) {
|
|
123
|
-
let universalRule = postcss.rule(
|
|
123
|
+
let universalRule = postcss.rule({
|
|
124
|
+
source: universal.source,
|
|
125
|
+
})
|
|
124
126
|
|
|
125
127
|
universalRule.selectors = [...selectors]
|
|
126
128
|
|
|
@@ -128,9 +130,11 @@ export default function resolveDefaultsAtRules({ tailwindConfig }) {
|
|
|
128
130
|
universal.before(universalRule)
|
|
129
131
|
}
|
|
130
132
|
} else {
|
|
131
|
-
let universalRule = postcss.rule(
|
|
133
|
+
let universalRule = postcss.rule({
|
|
134
|
+
source: universal.source,
|
|
135
|
+
})
|
|
132
136
|
|
|
133
|
-
universalRule.selectors = ['*', '::before', '::after']
|
|
137
|
+
universalRule.selectors = ['*', '::before', '::after', '::backdrop']
|
|
134
138
|
|
|
135
139
|
universalRule.append(universal.nodes)
|
|
136
140
|
universal.before(universalRule)
|