tailwindcss 3.0.12 → 3.0.16
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 +38 -5
- package/lib/cli.js +8 -16
- package/lib/corePlugins.js +71 -139
- package/lib/featureFlags.js +1 -2
- package/lib/lib/expandTailwindAtRules.js +29 -13
- package/lib/lib/generateRules.js +8 -2
- package/lib/lib/normalizeTailwindDirectives.js +2 -1
- package/lib/lib/partitionApplyAtRules.js +53 -0
- package/lib/lib/setupContextUtils.js +56 -120
- package/{nesting → lib/postcss-plugins/nesting}/README.md +0 -0
- package/lib/postcss-plugins/nesting/index.js +17 -0
- package/lib/postcss-plugins/nesting/plugin.js +53 -0
- package/lib/processTailwindFeatures.js +2 -0
- package/lib/util/createPlugin.js +1 -2
- package/lib/util/createUtilityPlugin.js +4 -8
- package/lib/util/flattenColorPalette.js +1 -3
- package/lib/util/normalizeConfig.js +19 -16
- package/lib/util/normalizeScreens.js +2 -4
- package/lib/util/pluginUtils.js +5 -12
- package/lib/util/resolveConfig.js +9 -18
- package/lib/util/resolveConfigPath.js +1 -2
- package/lib/util/toColorValue.js +1 -2
- package/lib/util/transformThemeValue.js +4 -8
- package/nesting/index.js +2 -12
- package/package.json +10 -12
- package/peers/index.js +261 -231
- package/src/corePlugins.js +1 -0
- package/src/lib/expandTailwindAtRules.js +31 -6
- package/src/lib/generateRules.js +6 -0
- package/src/lib/normalizeTailwindDirectives.js +1 -0
- package/src/lib/partitionApplyAtRules.js +52 -0
- package/src/lib/setupContextUtils.js +7 -75
- package/src/postcss-plugins/nesting/README.md +42 -0
- package/src/postcss-plugins/nesting/index.js +13 -0
- package/{nesting → src/postcss-plugins/nesting}/plugin.js +7 -4
- package/src/processTailwindFeatures.js +2 -0
- package/src/util/normalizeConfig.js +12 -4
package/src/corePlugins.js
CHANGED
|
@@ -144,6 +144,7 @@ export let variantPlugins = {
|
|
|
144
144
|
log.warn('darkmode-false', [
|
|
145
145
|
'The `darkMode` option in your Tailwind CSS configuration is set to `false`, which now behaves the same as `media`.',
|
|
146
146
|
'Change `darkMode` to `media` or remove it entirely.',
|
|
147
|
+
'https://tailwindcss.com/docs/upgrade-guide#remove-dark-mode-configuration',
|
|
147
148
|
])
|
|
148
149
|
}
|
|
149
150
|
|
|
@@ -2,6 +2,7 @@ import LRU from 'quick-lru'
|
|
|
2
2
|
import * as sharedState from './sharedState'
|
|
3
3
|
import { generateRules } from './generateRules'
|
|
4
4
|
import bigSign from '../util/bigSign'
|
|
5
|
+
import log from '../util/log'
|
|
5
6
|
import cloneNodes from '../util/cloneNodes'
|
|
6
7
|
import { defaultExtractor } from './defaultExtractor'
|
|
7
8
|
|
|
@@ -204,9 +205,6 @@ export default function expandTailwindAtRules(context) {
|
|
|
204
205
|
|
|
205
206
|
if (layerNodes.base) {
|
|
206
207
|
layerNodes.base.before(cloneNodes([...baseNodes, ...defaultNodes], layerNodes.base.source))
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (layerNodes.base) {
|
|
210
208
|
layerNodes.base.remove()
|
|
211
209
|
}
|
|
212
210
|
|
|
@@ -220,11 +218,38 @@ export default function expandTailwindAtRules(context) {
|
|
|
220
218
|
layerNodes.utilities.remove()
|
|
221
219
|
}
|
|
222
220
|
|
|
221
|
+
// We do post-filtering to not alter the emitted order of the variants
|
|
222
|
+
const variantNodes = Array.from(screenNodes).filter((node) => {
|
|
223
|
+
const parentLayer = node.raws.tailwind?.parentLayer
|
|
224
|
+
|
|
225
|
+
if (parentLayer === 'components') {
|
|
226
|
+
return layerNodes.components !== null
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (parentLayer === 'utilities') {
|
|
230
|
+
return layerNodes.utilities !== null
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return true
|
|
234
|
+
})
|
|
235
|
+
|
|
223
236
|
if (layerNodes.variants) {
|
|
224
|
-
layerNodes.variants.before(cloneNodes(
|
|
237
|
+
layerNodes.variants.before(cloneNodes(variantNodes, layerNodes.variants.source))
|
|
225
238
|
layerNodes.variants.remove()
|
|
226
|
-
} else {
|
|
227
|
-
root.append(cloneNodes(
|
|
239
|
+
} else if (variantNodes.length > 0) {
|
|
240
|
+
root.append(cloneNodes(variantNodes, root.source))
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// If we've got a utility layer and no utilities are generated there's likely something wrong
|
|
244
|
+
const hasUtilityVariants = variantNodes.some(
|
|
245
|
+
(node) => node.raws.tailwind?.parentLayer === 'utilities'
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
|
|
249
|
+
log.warn('content-problems', [
|
|
250
|
+
'No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.',
|
|
251
|
+
'https://tailwindcss.com/docs/content-configuration',
|
|
252
|
+
])
|
|
228
253
|
}
|
|
229
254
|
|
|
230
255
|
// ---
|
package/src/lib/generateRules.js
CHANGED
|
@@ -216,6 +216,12 @@ function applyVariant(variant, matches, context) {
|
|
|
216
216
|
})
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
// This tracks the originating layer for the variant
|
|
220
|
+
// For example:
|
|
221
|
+
// .sm:underline {} is a variant of something in the utilities layer
|
|
222
|
+
// .sm:container {} is a variant of the container component
|
|
223
|
+
clone.nodes[0].raws.tailwind = { parentLayer: meta.layer }
|
|
224
|
+
|
|
219
225
|
let withOffset = [
|
|
220
226
|
{
|
|
221
227
|
...meta,
|
|
@@ -49,6 +49,7 @@ export default function normalizeTailwindDirectives(root) {
|
|
|
49
49
|
log.warn(`${atRule.name}-at-rule-deprecated`, [
|
|
50
50
|
`The \`@${atRule.name}\` directive has been deprecated in Tailwind CSS v3.0.`,
|
|
51
51
|
`Use \`@layer utilities\` or \`@layer components\` instead.`,
|
|
52
|
+
'https://tailwindcss.com/docs/upgrade-guide#replace-variants-with-layer',
|
|
52
53
|
])
|
|
53
54
|
}
|
|
54
55
|
layerDirectives.add(atRule)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
function partitionRules(root) {
|
|
2
|
+
if (!root.walkAtRules) return
|
|
3
|
+
|
|
4
|
+
let applyParents = new Set()
|
|
5
|
+
|
|
6
|
+
root.walkAtRules('apply', (rule) => {
|
|
7
|
+
applyParents.add(rule.parent)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
if (applyParents.size === 0) {
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
for (let rule of applyParents) {
|
|
15
|
+
let nodeGroups = []
|
|
16
|
+
let lastGroup = []
|
|
17
|
+
|
|
18
|
+
for (let node of rule.nodes) {
|
|
19
|
+
if (node.type === 'atrule' && node.name === 'apply') {
|
|
20
|
+
if (lastGroup.length > 0) {
|
|
21
|
+
nodeGroups.push(lastGroup)
|
|
22
|
+
lastGroup = []
|
|
23
|
+
}
|
|
24
|
+
nodeGroups.push([node])
|
|
25
|
+
} else {
|
|
26
|
+
lastGroup.push(node)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (lastGroup.length > 0) {
|
|
31
|
+
nodeGroups.push(lastGroup)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (nodeGroups.length === 1) {
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
for (let group of [...nodeGroups].reverse()) {
|
|
39
|
+
let clone = rule.clone({ nodes: [] })
|
|
40
|
+
clone.append(group)
|
|
41
|
+
rule.after(clone)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
rule.remove()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default function expandApplyAtRules() {
|
|
49
|
+
return (root) => {
|
|
50
|
+
partitionRules(root)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -20,58 +20,6 @@ import log from '../util/log'
|
|
|
20
20
|
import negateValue from '../util/negateValue'
|
|
21
21
|
import isValidArbitraryValue from '../util/isValidArbitraryValue'
|
|
22
22
|
|
|
23
|
-
function partitionRules(root) {
|
|
24
|
-
if (!root.walkAtRules) return [root]
|
|
25
|
-
|
|
26
|
-
let applyParents = new Set()
|
|
27
|
-
let rules = []
|
|
28
|
-
|
|
29
|
-
root.walkAtRules('apply', (rule) => {
|
|
30
|
-
applyParents.add(rule.parent)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
if (applyParents.size === 0) {
|
|
34
|
-
rules.push(root)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
for (let rule of applyParents) {
|
|
38
|
-
let nodeGroups = []
|
|
39
|
-
let lastGroup = []
|
|
40
|
-
|
|
41
|
-
for (let node of rule.nodes) {
|
|
42
|
-
if (node.type === 'atrule' && node.name === 'apply') {
|
|
43
|
-
if (lastGroup.length > 0) {
|
|
44
|
-
nodeGroups.push(lastGroup)
|
|
45
|
-
lastGroup = []
|
|
46
|
-
}
|
|
47
|
-
nodeGroups.push([node])
|
|
48
|
-
} else {
|
|
49
|
-
lastGroup.push(node)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (lastGroup.length > 0) {
|
|
54
|
-
nodeGroups.push(lastGroup)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (nodeGroups.length === 1) {
|
|
58
|
-
rules.push(rule)
|
|
59
|
-
continue
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
for (let group of [...nodeGroups].reverse()) {
|
|
63
|
-
let clone = rule.clone({ nodes: [] })
|
|
64
|
-
clone.append(group)
|
|
65
|
-
rules.unshift(clone)
|
|
66
|
-
rule.after(clone)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
rule.remove()
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return rules
|
|
73
|
-
}
|
|
74
|
-
|
|
75
23
|
function parseVariantFormatString(input) {
|
|
76
24
|
if (input.includes('{')) {
|
|
77
25
|
if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`)
|
|
@@ -284,9 +232,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
284
232
|
context.candidateRuleMap.set(identifier, [])
|
|
285
233
|
}
|
|
286
234
|
|
|
287
|
-
context.candidateRuleMap
|
|
288
|
-
.get(identifier)
|
|
289
|
-
.push(...partitionRules(rule).map((rule) => [{ sort: offset, layer: 'user' }, rule]))
|
|
235
|
+
context.candidateRuleMap.get(identifier).push([{ sort: offset, layer: 'user' }, rule])
|
|
290
236
|
}
|
|
291
237
|
},
|
|
292
238
|
addBase(base) {
|
|
@@ -300,7 +246,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
300
246
|
|
|
301
247
|
context.candidateRuleMap
|
|
302
248
|
.get(prefixedIdentifier)
|
|
303
|
-
.push(
|
|
249
|
+
.push([{ sort: offset, layer: 'base' }, rule])
|
|
304
250
|
}
|
|
305
251
|
},
|
|
306
252
|
/**
|
|
@@ -321,12 +267,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
321
267
|
|
|
322
268
|
context.candidateRuleMap
|
|
323
269
|
.get(prefixedIdentifier)
|
|
324
|
-
.push(
|
|
325
|
-
...partitionRules(rule).map((rule) => [
|
|
326
|
-
{ sort: offsets.base++, layer: 'defaults' },
|
|
327
|
-
rule,
|
|
328
|
-
])
|
|
329
|
-
)
|
|
270
|
+
.push([{ sort: offsets.base++, layer: 'defaults' }, rule])
|
|
330
271
|
}
|
|
331
272
|
},
|
|
332
273
|
addComponents(components, options) {
|
|
@@ -348,12 +289,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
348
289
|
|
|
349
290
|
context.candidateRuleMap
|
|
350
291
|
.get(prefixedIdentifier)
|
|
351
|
-
.push(
|
|
352
|
-
...partitionRules(rule).map((rule) => [
|
|
353
|
-
{ sort: offsets.components++, layer: 'components', options },
|
|
354
|
-
rule,
|
|
355
|
-
])
|
|
356
|
-
)
|
|
292
|
+
.push([{ sort: offsets.components++, layer: 'components', options }, rule])
|
|
357
293
|
}
|
|
358
294
|
},
|
|
359
295
|
addUtilities(utilities, options) {
|
|
@@ -375,12 +311,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
375
311
|
|
|
376
312
|
context.candidateRuleMap
|
|
377
313
|
.get(prefixedIdentifier)
|
|
378
|
-
.push(
|
|
379
|
-
...partitionRules(rule).map((rule) => [
|
|
380
|
-
{ sort: offsets.utilities++, layer: 'utilities', options },
|
|
381
|
-
rule,
|
|
382
|
-
])
|
|
383
|
-
)
|
|
314
|
+
.push([{ sort: offsets.utilities++, layer: 'utilities', options }, rule])
|
|
384
315
|
}
|
|
385
316
|
},
|
|
386
317
|
matchUtilities: function (utilities, options) {
|
|
@@ -725,7 +656,7 @@ function registerPlugins(plugins, context) {
|
|
|
725
656
|
log.warn('root-regex', [
|
|
726
657
|
'Regular expressions in `safelist` work differently in Tailwind CSS v3.0.',
|
|
727
658
|
'Update your `safelist` configuration to eliminate this warning.',
|
|
728
|
-
|
|
659
|
+
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
|
|
729
660
|
])
|
|
730
661
|
continue
|
|
731
662
|
}
|
|
@@ -783,6 +714,7 @@ function registerPlugins(plugins, context) {
|
|
|
783
714
|
log.warn([
|
|
784
715
|
`The safelist pattern \`${regex}\` doesn't match any Tailwind CSS classes.`,
|
|
785
716
|
'Fix this pattern or remove it from your `safelist` configuration.',
|
|
717
|
+
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
|
|
786
718
|
])
|
|
787
719
|
}
|
|
788
720
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# tailwindcss/nesting
|
|
2
|
+
|
|
3
|
+
This is a PostCSS plugin that wraps [postcss-nested](https://github.com/postcss/postcss-nested) or [postcss-nesting](https://github.com/jonathantneal/postcss-nesting) and acts as a compatibility layer to make sure your nesting plugin of choice properly understands Tailwind's custom syntax like `@apply` and `@screen`.
|
|
4
|
+
|
|
5
|
+
Add it to your PostCSS configuration, somewhere before Tailwind itself:
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
// postcss.config.js
|
|
9
|
+
module.exports = {
|
|
10
|
+
plugins: [
|
|
11
|
+
require('postcss-import'),
|
|
12
|
+
require('tailwindcss/nesting'),
|
|
13
|
+
require('tailwindcss'),
|
|
14
|
+
require('autoprefixer'),
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
By default, it uses the [postcss-nested](https://github.com/postcss/postcss-nested) plugin under the hood, which uses a Sass-like syntax and is the plugin that powers nesting support in the [Tailwind CSS plugin API](https://tailwindcss.com/docs/plugins#css-in-js-syntax).
|
|
20
|
+
|
|
21
|
+
If you'd rather use [postcss-nesting](https://github.com/jonathantneal/postcss-nesting) (which is based on the work-in-progress [CSS Nesting](https://drafts.csswg.org/css-nesting-1/) specification), first install the plugin alongside:
|
|
22
|
+
|
|
23
|
+
```shell
|
|
24
|
+
npm install postcss-nesting
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then pass the plugin itself as an argument to `tailwindcss/nesting` in your PostCSS configuration:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
// postcss.config.js
|
|
31
|
+
module.exports = {
|
|
32
|
+
plugins: [
|
|
33
|
+
require('postcss-import'),
|
|
34
|
+
require('tailwindcss/nesting')(require('postcss-nesting')),
|
|
35
|
+
require('tailwindcss'),
|
|
36
|
+
require('autoprefixer'),
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
This can also be helpful if for whatever reason you need to use a very specific version of `postcss-nested` and want to override the version we bundle with `tailwindcss/nesting` itself.
|
|
42
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import postcss from 'postcss'
|
|
2
|
+
import postcssNested from 'postcss-nested'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
export function nesting(opts = postcssNested) {
|
|
5
5
|
return (root, result) => {
|
|
6
6
|
root.walkAtRules('screen', (rule) => {
|
|
7
7
|
rule.name = 'media'
|
|
@@ -14,7 +14,10 @@ module.exports = function nesting(opts = postcssNested) {
|
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
let plugin = (() => {
|
|
17
|
-
if (
|
|
17
|
+
if (
|
|
18
|
+
typeof opts === 'function' ||
|
|
19
|
+
(typeof opts === 'object' && opts?.hasOwnProperty?.('postcssPlugin'))
|
|
20
|
+
) {
|
|
18
21
|
return opts
|
|
19
22
|
}
|
|
20
23
|
|
|
@@ -6,6 +6,7 @@ import substituteScreenAtRules from './lib/substituteScreenAtRules'
|
|
|
6
6
|
import resolveDefaultsAtRules from './lib/resolveDefaultsAtRules'
|
|
7
7
|
import collapseAdjacentRules from './lib/collapseAdjacentRules'
|
|
8
8
|
import collapseDuplicateDeclarations from './lib/collapseDuplicateDeclarations'
|
|
9
|
+
import partitionApplyAtRules from './lib/partitionApplyAtRules'
|
|
9
10
|
import detectNesting from './lib/detectNesting'
|
|
10
11
|
import { createContext } from './lib/setupContextUtils'
|
|
11
12
|
import { issueFlagNotices } from './featureFlags'
|
|
@@ -15,6 +16,7 @@ export default function processTailwindFeatures(setupContext) {
|
|
|
15
16
|
let { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root)
|
|
16
17
|
|
|
17
18
|
detectNesting()(root, result)
|
|
19
|
+
partitionApplyAtRules()(root, result)
|
|
18
20
|
|
|
19
21
|
let context = setupContext({
|
|
20
22
|
tailwindDirectives,
|
|
@@ -124,7 +124,7 @@ export function normalizeConfig(config) {
|
|
|
124
124
|
log.warn('purge-deprecation', [
|
|
125
125
|
'The `purge`/`content` options have changed in Tailwind CSS v3.0.',
|
|
126
126
|
'Update your configuration file to eliminate this warning.',
|
|
127
|
-
|
|
127
|
+
'https://tailwindcss.com/docs/upgrade-guide#configure-content-sources',
|
|
128
128
|
])
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -145,7 +145,7 @@ export function normalizeConfig(config) {
|
|
|
145
145
|
log.warn('prefix-function', [
|
|
146
146
|
'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
|
|
147
147
|
'Update `prefix` in your configuration to be a string to eliminate this warning.',
|
|
148
|
-
|
|
148
|
+
'https://tailwindcss.com/docs/upgrade-guide#prefix-cannot-be-a-function',
|
|
149
149
|
])
|
|
150
150
|
config.prefix = ''
|
|
151
151
|
} else {
|
|
@@ -250,13 +250,21 @@ export function normalizeConfig(config) {
|
|
|
250
250
|
for (let file of config.content.files) {
|
|
251
251
|
if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) {
|
|
252
252
|
log.warn('invalid-glob-braces', [
|
|
253
|
-
`The glob pattern ${dim(file)} in your
|
|
254
|
-
`
|
|
253
|
+
`The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`,
|
|
254
|
+
`Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`,
|
|
255
255
|
// TODO: Add https://tw.wtf/invalid-glob-braces
|
|
256
256
|
])
|
|
257
257
|
break
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
if (config.content.files.length === 0) {
|
|
262
|
+
log.warn('content-problems', [
|
|
263
|
+
'The `content` option in your Tailwind CSS configuration is missing or empty.',
|
|
264
|
+
'Configure your content sources or your generated CSS will be missing styles.',
|
|
265
|
+
'https://tailwindcss.com/docs/content-configuration',
|
|
266
|
+
])
|
|
267
|
+
}
|
|
268
|
+
|
|
261
269
|
return config
|
|
262
270
|
}
|