tailwindcss 3.3.2 → 3.3.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.
- package/CHANGELOG.md +50 -1
- package/lib/cli/build/plugin.js +2 -2
- package/lib/cli/build/watching.js +1 -1
- package/lib/corePlugins.js +11 -7
- package/lib/css/preflight.css +9 -0
- package/lib/lib/defaultExtractor.js +16 -22
- package/lib/lib/evaluateTailwindFunctions.js +5 -3
- package/lib/lib/expandApplyAtRules.js +6 -0
- package/lib/lib/expandTailwindAtRules.js +20 -6
- package/lib/lib/generateRules.js +34 -24
- package/lib/lib/setupContextUtils.js +53 -33
- package/lib/lib/setupTrackingContext.js +2 -1
- package/lib/oxide/cli/build/plugin.js +2 -2
- package/lib/plugin.js +3 -3
- package/lib/processTailwindFeatures.js +2 -2
- package/lib/util/color.js +1 -1
- package/lib/util/dataTypes.js +100 -16
- package/lib/util/formatVariantSelector.js +10 -3
- package/lib/util/isPlainObject.js +1 -1
- package/lib/util/prefixSelector.js +1 -1
- package/lib/util/pseudoElements.js +18 -34
- package/lib/value-parser/LICENSE +22 -0
- package/lib/value-parser/README.md +3 -0
- package/lib/value-parser/index.d.js +2 -0
- package/lib/value-parser/index.js +22 -0
- package/lib/value-parser/parse.js +259 -0
- package/lib/value-parser/stringify.js +38 -0
- package/lib/value-parser/unit.js +86 -0
- package/lib/value-parser/walk.js +16 -0
- package/nesting/index.d.ts +4 -0
- package/package.json +5 -6
- package/peers/index.js +701 -617
- package/src/cli/build/plugin.js +2 -2
- package/src/cli/build/watching.js +1 -1
- package/src/corePlugins.js +13 -7
- package/src/css/preflight.css +9 -0
- package/src/featureFlags.js +0 -1
- package/src/lib/defaultExtractor.js +12 -13
- package/src/lib/evaluateTailwindFunctions.js +4 -1
- package/src/lib/expandApplyAtRules.js +7 -0
- package/src/lib/expandTailwindAtRules.js +20 -6
- package/src/lib/generateRules.js +34 -25
- package/src/lib/setupContextUtils.js +50 -35
- package/src/lib/setupTrackingContext.js +1 -3
- package/src/oxide/cli/build/plugin.ts +2 -2
- package/src/plugin.js +3 -3
- package/src/processTailwindFeatures.js +3 -2
- package/src/util/color.js +1 -1
- package/src/util/dataTypes.js +101 -18
- package/src/util/formatVariantSelector.js +11 -3
- package/src/util/isPlainObject.js +1 -1
- package/src/util/prefixSelector.js +1 -0
- package/src/util/pseudoElements.js +14 -17
- package/src/value-parser/LICENSE +22 -0
- package/src/value-parser/README.md +3 -0
- package/src/value-parser/index.d.ts +177 -0
- package/src/value-parser/index.js +28 -0
- package/src/value-parser/parse.js +303 -0
- package/src/value-parser/stringify.js +41 -0
- package/src/value-parser/unit.js +118 -0
- package/src/value-parser/walk.js +18 -0
- package/stubs/config.full.js +1 -0
- package/types/config.d.ts +6 -6
- package/types/generated/default-theme.d.ts +1 -0
- package/types/index.d.ts +7 -3
package/src/cli/build/plugin.js
CHANGED
|
@@ -278,9 +278,9 @@ export async function createProcessor(args, cliConfigPath) {
|
|
|
278
278
|
let tailwindPlugin = () => {
|
|
279
279
|
return {
|
|
280
280
|
postcssPlugin: 'tailwindcss',
|
|
281
|
-
Once(root, { result }) {
|
|
281
|
+
async Once(root, { result }) {
|
|
282
282
|
env.DEBUG && console.time('Compiling CSS')
|
|
283
|
-
tailwind(({ createContext }) => {
|
|
283
|
+
await tailwind(({ createContext }) => {
|
|
284
284
|
console.error()
|
|
285
285
|
console.error('Rebuilding...')
|
|
286
286
|
|
|
@@ -164,7 +164,7 @@ export function createWatcher(args, { state, rebuild }) {
|
|
|
164
164
|
// This is very likely a chokidar bug but it's one we need to work around
|
|
165
165
|
// We treat this as a change event and rebuild the CSS
|
|
166
166
|
watcher.on('raw', (evt, filePath, meta) => {
|
|
167
|
-
if (evt !== 'rename') {
|
|
167
|
+
if (evt !== 'rename' || filePath === null) {
|
|
168
168
|
return
|
|
169
169
|
}
|
|
170
170
|
|
package/src/corePlugins.js
CHANGED
|
@@ -22,6 +22,7 @@ import { formatBoxShadowValue, parseBoxShadowValue } from './util/parseBoxShadow
|
|
|
22
22
|
import { removeAlphaVariables } from './util/removeAlphaVariables'
|
|
23
23
|
import { flagEnabled } from './featureFlags'
|
|
24
24
|
import { normalize } from './util/dataTypes'
|
|
25
|
+
import { INTERNAL_FEATURES } from './lib/setupContextUtils'
|
|
25
26
|
|
|
26
27
|
export let variantPlugins = {
|
|
27
28
|
pseudoElementVariants: ({ addVariant }) => {
|
|
@@ -80,7 +81,7 @@ export let variantPlugins = {
|
|
|
80
81
|
})
|
|
81
82
|
},
|
|
82
83
|
|
|
83
|
-
pseudoClassVariants: ({ addVariant, matchVariant, config }) => {
|
|
84
|
+
pseudoClassVariants: ({ addVariant, matchVariant, config, prefix }) => {
|
|
84
85
|
let pseudoVariants = [
|
|
85
86
|
// Positional
|
|
86
87
|
['first', '&:first-child'],
|
|
@@ -151,12 +152,12 @@ export let variantPlugins = {
|
|
|
151
152
|
let variants = {
|
|
152
153
|
group: (_, { modifier }) =>
|
|
153
154
|
modifier
|
|
154
|
-
? [`:merge(.group\\/${escapeClassName(modifier)})`, ' &']
|
|
155
|
-
: [`:merge(.group)`, ' &'],
|
|
155
|
+
? [`:merge(${prefix('.group')}\\/${escapeClassName(modifier)})`, ' &']
|
|
156
|
+
: [`:merge(${prefix('.group')})`, ' &'],
|
|
156
157
|
peer: (_, { modifier }) =>
|
|
157
158
|
modifier
|
|
158
|
-
? [`:merge(.peer\\/${escapeClassName(modifier)})`, ' ~ &']
|
|
159
|
-
: [`:merge(.peer)`, ' ~ &'],
|
|
159
|
+
? [`:merge(${prefix('.peer')}\\/${escapeClassName(modifier)})`, ' ~ &']
|
|
160
|
+
: [`:merge(${prefix('.peer')})`, ' ~ &'],
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
for (let [name, fn] of Object.entries(variants)) {
|
|
@@ -192,7 +193,12 @@ export let variantPlugins = {
|
|
|
192
193
|
|
|
193
194
|
return result.slice(0, start) + a + result.slice(start + 1, end) + b + result.slice(end)
|
|
194
195
|
},
|
|
195
|
-
{
|
|
196
|
+
{
|
|
197
|
+
values: Object.fromEntries(pseudoVariants),
|
|
198
|
+
[INTERNAL_FEATURES]: {
|
|
199
|
+
respectPrefix: false,
|
|
200
|
+
},
|
|
201
|
+
}
|
|
196
202
|
)
|
|
197
203
|
}
|
|
198
204
|
},
|
|
@@ -913,7 +919,7 @@ export let corePlugins = {
|
|
|
913
919
|
},
|
|
914
920
|
|
|
915
921
|
animation: ({ matchUtilities, theme, config }) => {
|
|
916
|
-
let prefixName = (name) =>
|
|
922
|
+
let prefixName = (name) => escapeClassName(config('prefix') + name)
|
|
917
923
|
let keyframes = Object.fromEntries(
|
|
918
924
|
Object.entries(theme('keyframes') ?? {}).map(([key, value]) => {
|
|
919
925
|
return [key, { [`@keyframes ${prefixName(key)}`]: value }]
|
package/src/css/preflight.css
CHANGED
|
@@ -163,6 +163,8 @@ optgroup,
|
|
|
163
163
|
select,
|
|
164
164
|
textarea {
|
|
165
165
|
font-family: inherit; /* 1 */
|
|
166
|
+
font-feature-settings: inherit; /* 1 */
|
|
167
|
+
font-variation-settings: inherit; /* 1 */
|
|
166
168
|
font-size: 100%; /* 1 */
|
|
167
169
|
font-weight: inherit; /* 1 */
|
|
168
170
|
line-height: inherit; /* 1 */
|
|
@@ -300,6 +302,13 @@ menu {
|
|
|
300
302
|
padding: 0;
|
|
301
303
|
}
|
|
302
304
|
|
|
305
|
+
/*
|
|
306
|
+
Reset default styling for dialogs.
|
|
307
|
+
*/
|
|
308
|
+
dialog {
|
|
309
|
+
padding: 0;
|
|
310
|
+
}
|
|
311
|
+
|
|
303
312
|
/*
|
|
304
313
|
Prevent resizing textareas horizontally by default.
|
|
305
314
|
*/
|
package/src/featureFlags.js
CHANGED
|
@@ -12,16 +12,17 @@ export function defaultExtractor(context) {
|
|
|
12
12
|
let results = []
|
|
13
13
|
|
|
14
14
|
for (let pattern of patterns) {
|
|
15
|
-
|
|
15
|
+
for (let result of content.match(pattern) ?? []) {
|
|
16
|
+
results.push(clipAtBalancedParens(result))
|
|
17
|
+
}
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
return results
|
|
20
|
+
return results
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
function* buildRegExps(context) {
|
|
23
25
|
let separator = context.tailwindConfig.separator
|
|
24
|
-
let variantGroupingEnabled = flagEnabled(context.tailwindConfig, 'variantGrouping')
|
|
25
26
|
let prefix =
|
|
26
27
|
context.tailwindConfig.prefix !== ''
|
|
27
28
|
? regex.optional(regex.pattern([/-?/, regex.escape(context.tailwindConfig.prefix)]))
|
|
@@ -35,7 +36,7 @@ function* buildRegExps(context) {
|
|
|
35
36
|
// This is a targeted fix to continue to allow theme()
|
|
36
37
|
// with square brackets to work in arbitrary properties
|
|
37
38
|
// while fixing a problem with the regex matching too much
|
|
38
|
-
/\[[^\s:'"
|
|
39
|
+
/\[[^\s:'"`\]]+:[^\s]+?\[[^\s]+\][^\s]+?\]/,
|
|
39
40
|
|
|
40
41
|
// Utilities
|
|
41
42
|
regex.pattern([
|
|
@@ -80,12 +81,18 @@ function* buildRegExps(context) {
|
|
|
80
81
|
// This is here to provide special support for the `@` variant
|
|
81
82
|
regex.pattern([/@\[[^\s"'`]+\](\/[^\s"'`]+)?/, separator]),
|
|
82
83
|
|
|
84
|
+
// With variant modifier (e.g.: group-[..]/modifier)
|
|
85
|
+
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]\/\w+/, separator]),
|
|
86
|
+
|
|
83
87
|
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, separator]),
|
|
84
88
|
regex.pattern([/[^\s"'`\[\\]+/, separator]),
|
|
85
89
|
]),
|
|
86
90
|
|
|
87
91
|
// With quotes allowed
|
|
88
92
|
regex.any([
|
|
93
|
+
// With variant modifier (e.g.: group-[..]/modifier)
|
|
94
|
+
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]\/\w+/, separator]),
|
|
95
|
+
|
|
89
96
|
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]/, separator]),
|
|
90
97
|
regex.pattern([/[^\s`\[\\]+/, separator]),
|
|
91
98
|
]),
|
|
@@ -103,15 +110,7 @@ function* buildRegExps(context) {
|
|
|
103
110
|
|
|
104
111
|
prefix,
|
|
105
112
|
|
|
106
|
-
|
|
107
|
-
? regex.any([
|
|
108
|
-
// Or any of those things but grouped separated by commas
|
|
109
|
-
regex.pattern([/\(/, utility, regex.zeroOrMore([/,/, utility]), /\)/]),
|
|
110
|
-
|
|
111
|
-
// Arbitrary properties, constrained utilities, arbitrary values, etc…
|
|
112
|
-
utility,
|
|
113
|
-
])
|
|
114
|
-
: utility,
|
|
113
|
+
utility,
|
|
115
114
|
])
|
|
116
115
|
}
|
|
117
116
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import dlv from 'dlv'
|
|
2
2
|
import didYouMean from 'didyoumean'
|
|
3
3
|
import transformThemeValue from '../util/transformThemeValue'
|
|
4
|
-
import parseValue from '
|
|
4
|
+
import parseValue from '../value-parser/index'
|
|
5
5
|
import { normalizeScreens } from '../util/normalizeScreens'
|
|
6
6
|
import buildMediaQuery from '../util/buildMediaQuery'
|
|
7
7
|
import { toPath } from '../util/toPath'
|
|
@@ -146,6 +146,9 @@ function resolveVNode(node, vNode, functions) {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
function resolveFunctions(node, input, functions) {
|
|
149
|
+
let hasAnyFn = Object.keys(functions).some((fn) => input.includes(`${fn}(`))
|
|
150
|
+
if (!hasAnyFn) return input
|
|
151
|
+
|
|
149
152
|
return parseValue(input)
|
|
150
153
|
.walk((vNode) => {
|
|
151
154
|
resolveVNode(node, vNode, functions)
|
|
@@ -553,6 +553,13 @@ function processApply(root, context, localCache) {
|
|
|
553
553
|
? parent.selector.slice(importantSelector.length)
|
|
554
554
|
: parent.selector
|
|
555
555
|
|
|
556
|
+
// If the selector becomes empty after replacing the important selector
|
|
557
|
+
// This means that it's the same as the parent selector and we don't want to replace it
|
|
558
|
+
// Otherwise we'll crash
|
|
559
|
+
if (parentSelector === '') {
|
|
560
|
+
parentSelector = parent.selector
|
|
561
|
+
}
|
|
562
|
+
|
|
556
563
|
rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate)
|
|
557
564
|
|
|
558
565
|
// And then re-add it if it was removed
|
|
@@ -98,7 +98,7 @@ function buildStylesheet(rules, context) {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
export default function expandTailwindAtRules(context) {
|
|
101
|
-
return (root) => {
|
|
101
|
+
return async (root) => {
|
|
102
102
|
let layerNodes = {
|
|
103
103
|
base: null,
|
|
104
104
|
components: null,
|
|
@@ -145,11 +145,25 @@ export default function expandTailwindAtRules(context) {
|
|
|
145
145
|
// getClassCandidatesOxide(file, transformer(content), extractor, candidates, seen)
|
|
146
146
|
// }
|
|
147
147
|
} else {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
/** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */
|
|
149
|
+
let regexParserContent = []
|
|
150
|
+
|
|
151
|
+
for (let item of context.changedContent) {
|
|
152
|
+
let transformer = getTransformer(context.tailwindConfig, item.extension)
|
|
153
|
+
let extractor = getExtractor(context, item.extension)
|
|
154
|
+
regexParserContent.push([item, { transformer, extractor }])
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const BATCH_SIZE = 500
|
|
158
|
+
|
|
159
|
+
for (let i = 0; i < regexParserContent.length; i += BATCH_SIZE) {
|
|
160
|
+
let batch = regexParserContent.slice(i, i + BATCH_SIZE)
|
|
161
|
+
await Promise.all(
|
|
162
|
+
batch.map(async ([{ file, content }, { transformer, extractor }]) => {
|
|
163
|
+
content = file ? await fs.promises.readFile(file, 'utf8') : content
|
|
164
|
+
getClassCandidates(transformer(content), extractor, candidates, seen)
|
|
165
|
+
})
|
|
166
|
+
)
|
|
153
167
|
}
|
|
154
168
|
}
|
|
155
169
|
|
package/src/lib/generateRules.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from '../util/formatVariantSelector'
|
|
14
14
|
import { asClass } from '../util/nameClass'
|
|
15
15
|
import { normalize } from '../util/dataTypes'
|
|
16
|
-
import { isValidVariantFormatString, parseVariant } from './setupContextUtils'
|
|
16
|
+
import { isValidVariantFormatString, parseVariant, INTERNAL_FEATURES } from './setupContextUtils'
|
|
17
17
|
import isValidArbitraryValue from '../util/isSyntacticallyValidPropertyValue'
|
|
18
18
|
import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly.js'
|
|
19
19
|
import { flagEnabled } from '../featureFlags'
|
|
@@ -193,13 +193,13 @@ function applyVariant(variant, matches, context) {
|
|
|
193
193
|
// group[:hover] (`-` is missing)
|
|
194
194
|
let match = /(.)(-?)\[(.*)\]/g.exec(variant)
|
|
195
195
|
if (match) {
|
|
196
|
-
let [, char,
|
|
196
|
+
let [, char, separator, value] = match
|
|
197
197
|
// @-[200px] case
|
|
198
|
-
if (char === '@' &&
|
|
198
|
+
if (char === '@' && separator === '-') return []
|
|
199
199
|
// group[:hover] case
|
|
200
|
-
if (char !== '@' &&
|
|
200
|
+
if (char !== '@' && separator === '') return []
|
|
201
201
|
|
|
202
|
-
variant = variant.replace(`${
|
|
202
|
+
variant = variant.replace(`${separator}[${value}]`, '')
|
|
203
203
|
args.value = value
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -230,9 +230,16 @@ function applyVariant(variant, matches, context) {
|
|
|
230
230
|
|
|
231
231
|
if (context.variantMap.has(variant)) {
|
|
232
232
|
let isArbitraryVariant = isArbitraryValue(variant)
|
|
233
|
+
let internalFeatures = context.variantOptions.get(variant)?.[INTERNAL_FEATURES] ?? {}
|
|
233
234
|
let variantFunctionTuples = context.variantMap.get(variant).slice()
|
|
234
235
|
let result = []
|
|
235
236
|
|
|
237
|
+
let respectPrefix = (() => {
|
|
238
|
+
if (isArbitraryVariant) return false
|
|
239
|
+
if (internalFeatures.respectPrefix === false) return false
|
|
240
|
+
return true
|
|
241
|
+
})()
|
|
242
|
+
|
|
236
243
|
for (let [meta, rule] of matches) {
|
|
237
244
|
// Don't generate variants for user css
|
|
238
245
|
if (meta.layer === 'user') {
|
|
@@ -293,7 +300,7 @@ function applyVariant(variant, matches, context) {
|
|
|
293
300
|
format(selectorFormat) {
|
|
294
301
|
collectedFormats.push({
|
|
295
302
|
format: selectorFormat,
|
|
296
|
-
|
|
303
|
+
respectPrefix,
|
|
297
304
|
})
|
|
298
305
|
},
|
|
299
306
|
args,
|
|
@@ -322,7 +329,7 @@ function applyVariant(variant, matches, context) {
|
|
|
322
329
|
if (typeof ruleWithVariant === 'string') {
|
|
323
330
|
collectedFormats.push({
|
|
324
331
|
format: ruleWithVariant,
|
|
325
|
-
|
|
332
|
+
respectPrefix,
|
|
326
333
|
})
|
|
327
334
|
}
|
|
328
335
|
|
|
@@ -366,7 +373,7 @@ function applyVariant(variant, matches, context) {
|
|
|
366
373
|
// format: .foo &
|
|
367
374
|
collectedFormats.push({
|
|
368
375
|
format: modified.replace(rebuiltBase, '&'),
|
|
369
|
-
|
|
376
|
+
respectPrefix,
|
|
370
377
|
})
|
|
371
378
|
rule.selector = before
|
|
372
379
|
})
|
|
@@ -489,7 +496,7 @@ function extractArbitraryProperty(classCandidate, context) {
|
|
|
489
496
|
return null
|
|
490
497
|
}
|
|
491
498
|
|
|
492
|
-
let normalized = normalize(value)
|
|
499
|
+
let normalized = normalize(value, { property })
|
|
493
500
|
|
|
494
501
|
if (!isParsableCssValue(property, normalized)) {
|
|
495
502
|
return null
|
|
@@ -566,7 +573,7 @@ function* recordCandidates(matches, classCandidate) {
|
|
|
566
573
|
}
|
|
567
574
|
}
|
|
568
575
|
|
|
569
|
-
function* resolveMatches(candidate, context
|
|
576
|
+
function* resolveMatches(candidate, context) {
|
|
570
577
|
let separator = context.tailwindConfig.separator
|
|
571
578
|
let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse()
|
|
572
579
|
let important = false
|
|
@@ -576,15 +583,6 @@ function* resolveMatches(candidate, context, original = candidate) {
|
|
|
576
583
|
classCandidate = classCandidate.slice(1)
|
|
577
584
|
}
|
|
578
585
|
|
|
579
|
-
if (flagEnabled(context.tailwindConfig, 'variantGrouping')) {
|
|
580
|
-
if (classCandidate.startsWith('(') && classCandidate.endsWith(')')) {
|
|
581
|
-
let base = variants.slice().reverse().join(separator)
|
|
582
|
-
for (let part of splitAtTopLevelOnly(classCandidate.slice(1, -1), ',')) {
|
|
583
|
-
yield* resolveMatches(base + separator + part, context, original)
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
586
|
// TODO: Reintroduce this in ways that doesn't break on false positives
|
|
589
587
|
// function sortAgainst(toSort, against) {
|
|
590
588
|
// return toSort.slice().sort((a, z) => {
|
|
@@ -773,7 +771,7 @@ function* resolveMatches(candidate, context, original = candidate) {
|
|
|
773
771
|
match[1].raws.tailwind = { ...match[1].raws.tailwind, candidate }
|
|
774
772
|
|
|
775
773
|
// Apply final format selector
|
|
776
|
-
match = applyFinalFormat(match, { context, candidate
|
|
774
|
+
match = applyFinalFormat(match, { context, candidate })
|
|
777
775
|
|
|
778
776
|
// Skip rules with invalid selectors
|
|
779
777
|
// This will cause the candidate to be added to the "not class"
|
|
@@ -787,7 +785,7 @@ function* resolveMatches(candidate, context, original = candidate) {
|
|
|
787
785
|
}
|
|
788
786
|
}
|
|
789
787
|
|
|
790
|
-
function applyFinalFormat(match, { context, candidate
|
|
788
|
+
function applyFinalFormat(match, { context, candidate }) {
|
|
791
789
|
if (!match[0].collectedFormats) {
|
|
792
790
|
return match
|
|
793
791
|
}
|
|
@@ -822,10 +820,19 @@ function applyFinalFormat(match, { context, candidate, original }) {
|
|
|
822
820
|
}
|
|
823
821
|
|
|
824
822
|
try {
|
|
825
|
-
|
|
826
|
-
candidate
|
|
823
|
+
let selector = finalizeSelector(rule.selector, finalFormat, {
|
|
824
|
+
candidate,
|
|
827
825
|
context,
|
|
828
826
|
})
|
|
827
|
+
|
|
828
|
+
// Finalize Selector determined that this candidate is irrelevant
|
|
829
|
+
// TODO: This elimination should happen earlier so this never happens
|
|
830
|
+
if (selector === null) {
|
|
831
|
+
rule.remove()
|
|
832
|
+
return
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
rule.selector = selector
|
|
829
836
|
} catch {
|
|
830
837
|
// If this selector is invalid we also want to skip it
|
|
831
838
|
// But it's likely that being invalid here means there's a bug in a plugin rather than too loosely matching content
|
|
@@ -875,7 +882,7 @@ function getImportantStrategy(important) {
|
|
|
875
882
|
}
|
|
876
883
|
}
|
|
877
884
|
|
|
878
|
-
function generateRules(candidates, context) {
|
|
885
|
+
function generateRules(candidates, context, isSorting = false) {
|
|
879
886
|
let allRules = []
|
|
880
887
|
let strategy = getImportantStrategy(context.tailwindConfig.important)
|
|
881
888
|
|
|
@@ -910,7 +917,9 @@ function generateRules(candidates, context) {
|
|
|
910
917
|
rule = container.nodes[0]
|
|
911
918
|
}
|
|
912
919
|
|
|
913
|
-
|
|
920
|
+
// Note: We have to clone rules during sorting
|
|
921
|
+
// so we eliminate some shared mutable state
|
|
922
|
+
let newEntry = [sort, isSorting ? rule.clone() : rule]
|
|
914
923
|
rules.add(newEntry)
|
|
915
924
|
context.ruleCache.add(newEntry)
|
|
916
925
|
allRules.push(newEntry)
|
|
@@ -24,6 +24,8 @@ import { Offsets } from './offsets.js'
|
|
|
24
24
|
import { flagEnabled } from '../featureFlags.js'
|
|
25
25
|
import { finalizeSelector, formatVariantSelector } from '../util/formatVariantSelector'
|
|
26
26
|
|
|
27
|
+
export const INTERNAL_FEATURES = Symbol()
|
|
28
|
+
|
|
27
29
|
const VARIANT_TYPES = {
|
|
28
30
|
AddVariant: Symbol.for('ADD_VARIANT'),
|
|
29
31
|
MatchVariant: Symbol.for('MATCH_VARIANT'),
|
|
@@ -146,43 +148,45 @@ function getClasses(selector, mutate) {
|
|
|
146
148
|
return parser.transformSync(selector)
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Ignore everything inside a :not(...). This allows you to write code like
|
|
153
|
+
* `div:not(.foo)`. If `.foo` is never found in your code, then we used to
|
|
154
|
+
* not generated it. But now we will ignore everything inside a `:not`, so
|
|
155
|
+
* that it still gets generated.
|
|
156
|
+
*
|
|
157
|
+
* @param {selectorParser.Root} selectors
|
|
158
|
+
*/
|
|
159
|
+
function ignoreNot(selectors) {
|
|
160
|
+
selectors.walkPseudos((pseudo) => {
|
|
161
|
+
if (pseudo.value === ':not') {
|
|
162
|
+
pseudo.remove()
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
149
167
|
function extractCandidates(node, state = { containsNonOnDemandable: false }, depth = 0) {
|
|
150
168
|
let classes = []
|
|
169
|
+
let selectors = []
|
|
151
170
|
|
|
152
|
-
// Handle normal rules
|
|
153
171
|
if (node.type === 'rule') {
|
|
154
|
-
//
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (pseudo.value === ':not') {
|
|
161
|
-
pseudo.remove()
|
|
162
|
-
}
|
|
163
|
-
})
|
|
164
|
-
}
|
|
172
|
+
// Handle normal rules
|
|
173
|
+
selectors.push(...node.selectors)
|
|
174
|
+
} else if (node.type === 'atrule') {
|
|
175
|
+
// Handle at-rules (which contains nested rules)
|
|
176
|
+
node.walkRules((rule) => selectors.push(...rule.selectors))
|
|
177
|
+
}
|
|
165
178
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
// At least one of the selectors contains non-"on-demandable" candidates.
|
|
169
|
-
if (classCandidates.length === 0) {
|
|
170
|
-
state.containsNonOnDemandable = true
|
|
171
|
-
}
|
|
179
|
+
for (let selector of selectors) {
|
|
180
|
+
let classCandidates = getClasses(selector, ignoreNot)
|
|
172
181
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
182
|
+
// At least one of the selectors contains non-"on-demandable" candidates.
|
|
183
|
+
if (classCandidates.length === 0) {
|
|
184
|
+
state.containsNonOnDemandable = true
|
|
176
185
|
}
|
|
177
|
-
}
|
|
178
186
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
for (let classCandidate of rule.selectors.flatMap((selector) => getClasses(selector))) {
|
|
183
|
-
classes.push(classCandidate)
|
|
184
|
-
}
|
|
185
|
-
})
|
|
187
|
+
for (let classCandidate of classCandidates) {
|
|
188
|
+
classes.push(classCandidate)
|
|
189
|
+
}
|
|
186
190
|
}
|
|
187
191
|
|
|
188
192
|
if (depth === 0) {
|
|
@@ -230,8 +234,8 @@ export function parseVariant(variant) {
|
|
|
230
234
|
return ({ format }) => format(str)
|
|
231
235
|
}
|
|
232
236
|
|
|
233
|
-
let [, name, params] = /@(
|
|
234
|
-
return ({ wrap }) => wrap(postcss.atRule({ name, params: params
|
|
237
|
+
let [, name, params] = /@(\S*)( .+|[({].*)?/g.exec(str)
|
|
238
|
+
return ({ wrap }) => wrap(postcss.atRule({ name, params: params?.trim() ?? '' }))
|
|
235
239
|
})
|
|
236
240
|
.reverse()
|
|
237
241
|
|
|
@@ -943,13 +947,17 @@ function registerPlugins(plugins, context) {
|
|
|
943
947
|
|
|
944
948
|
// Sort all classes in order
|
|
945
949
|
// Non-tailwind classes won't be generated and will be left as `null`
|
|
946
|
-
let rules = generateRules(new Set(sorted), context)
|
|
950
|
+
let rules = generateRules(new Set(sorted), context, true)
|
|
947
951
|
rules = context.offsets.sort(rules)
|
|
948
952
|
|
|
949
953
|
let idx = BigInt(parasiteUtilities.length)
|
|
950
954
|
|
|
951
955
|
for (const [, rule] of rules) {
|
|
952
|
-
|
|
956
|
+
let candidate = rule.raws.tailwind.candidate
|
|
957
|
+
|
|
958
|
+
// When multiple rules match a candidate
|
|
959
|
+
// always take the position of the first one
|
|
960
|
+
sortedClassNames.set(candidate, sortedClassNames.get(candidate) ?? idx++)
|
|
953
961
|
}
|
|
954
962
|
|
|
955
963
|
return classes.map((className) => {
|
|
@@ -1119,17 +1127,24 @@ function registerPlugins(plugins, context) {
|
|
|
1119
1127
|
}
|
|
1120
1128
|
|
|
1121
1129
|
let isArbitraryVariant = !(value in (options.values ?? {}))
|
|
1130
|
+
let internalFeatures = options[INTERNAL_FEATURES] ?? {}
|
|
1131
|
+
|
|
1132
|
+
let respectPrefix = (() => {
|
|
1133
|
+
if (isArbitraryVariant) return false
|
|
1134
|
+
if (internalFeatures.respectPrefix === false) return false
|
|
1135
|
+
return true
|
|
1136
|
+
})()
|
|
1122
1137
|
|
|
1123
1138
|
formatStrings = formatStrings.map((format) =>
|
|
1124
1139
|
format.map((str) => ({
|
|
1125
1140
|
format: str,
|
|
1126
|
-
|
|
1141
|
+
respectPrefix,
|
|
1127
1142
|
}))
|
|
1128
1143
|
)
|
|
1129
1144
|
|
|
1130
1145
|
manualFormatStrings = manualFormatStrings.map((format) => ({
|
|
1131
1146
|
format,
|
|
1132
|
-
|
|
1147
|
+
respectPrefix,
|
|
1133
1148
|
}))
|
|
1134
1149
|
|
|
1135
1150
|
let opts = {
|
|
@@ -63,9 +63,7 @@ function getTailwindConfig(configOrPath) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// It's a plain object, not a path
|
|
66
|
-
let newConfig = resolveConfig(
|
|
67
|
-
configOrPath.config === undefined ? configOrPath : configOrPath.config
|
|
68
|
-
)
|
|
66
|
+
let newConfig = resolveConfig(configOrPath?.config ?? configOrPath ?? {})
|
|
69
67
|
|
|
70
68
|
newConfig = validateConfig(newConfig)
|
|
71
69
|
|
|
@@ -277,9 +277,9 @@ export async function createProcessor(args, cliConfigPath) {
|
|
|
277
277
|
let tailwindPlugin = () => {
|
|
278
278
|
return {
|
|
279
279
|
postcssPlugin: 'tailwindcss',
|
|
280
|
-
Once(root, { result }) {
|
|
280
|
+
async Once(root, { result }) {
|
|
281
281
|
env.DEBUG && console.time('Compiling CSS')
|
|
282
|
-
tailwind(({ createContext }) => {
|
|
282
|
+
await tailwind(({ createContext }) => {
|
|
283
283
|
console.error()
|
|
284
284
|
console.error('Rebuilding...')
|
|
285
285
|
|
package/src/plugin.js
CHANGED
|
@@ -13,7 +13,7 @@ module.exports = function tailwindcss(configOrPath) {
|
|
|
13
13
|
console.time('JIT TOTAL')
|
|
14
14
|
return root
|
|
15
15
|
},
|
|
16
|
-
function (root, result) {
|
|
16
|
+
async function (root, result) {
|
|
17
17
|
// Use the path for the `@config` directive if it exists, otherwise use the
|
|
18
18
|
// path for the file being processed
|
|
19
19
|
configOrPath = findAtConfigPath(root, result) ?? configOrPath
|
|
@@ -25,14 +25,14 @@ module.exports = function tailwindcss(configOrPath) {
|
|
|
25
25
|
|
|
26
26
|
for (const root of roots) {
|
|
27
27
|
if (root.type === 'root') {
|
|
28
|
-
processTailwindFeatures(context)(root, result)
|
|
28
|
+
await processTailwindFeatures(context)(root, result)
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
return
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
processTailwindFeatures(context)(root, result)
|
|
35
|
+
await processTailwindFeatures(context)(root, result)
|
|
36
36
|
},
|
|
37
37
|
__OXIDE__ &&
|
|
38
38
|
function lightningCssPlugin(_root, result) {
|
|
@@ -12,7 +12,7 @@ import { createContext } from './lib/setupContextUtils'
|
|
|
12
12
|
import { issueFlagNotices } from './featureFlags'
|
|
13
13
|
|
|
14
14
|
export default function processTailwindFeatures(setupContext) {
|
|
15
|
-
return function (root, result) {
|
|
15
|
+
return async function (root, result) {
|
|
16
16
|
let { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root)
|
|
17
17
|
|
|
18
18
|
detectNesting()(root, result)
|
|
@@ -44,7 +44,8 @@ export default function processTailwindFeatures(setupContext) {
|
|
|
44
44
|
|
|
45
45
|
issueFlagNotices(context.tailwindConfig)
|
|
46
46
|
|
|
47
|
-
expandTailwindAtRules(context)(root, result)
|
|
47
|
+
await expandTailwindAtRules(context)(root, result)
|
|
48
|
+
|
|
48
49
|
// Partition apply rules that are generated by
|
|
49
50
|
// addComponents, addUtilities and so on.
|
|
50
51
|
partitionApplyAtRules()(root, result)
|
package/src/util/color.js
CHANGED
|
@@ -5,7 +5,7 @@ let SHORT_HEX = /^#([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i
|
|
|
5
5
|
let VALUE = /(?:\d+|\d*\.\d+)%?/
|
|
6
6
|
let SEP = /(?:\s*,\s*|\s+)/
|
|
7
7
|
let ALPHA_SEP = /\s*[,/]\s*/
|
|
8
|
-
let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)\)/
|
|
8
|
+
let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)(?:,(?:[^ )]*?|var\(--[^ )]*?\)))?\)/
|
|
9
9
|
|
|
10
10
|
let RGB = new RegExp(
|
|
11
11
|
`^(rgba?)\\(\\s*(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$`
|