tailwindcss 3.0.11 → 3.0.12

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.
@@ -129,8 +129,6 @@ function buildStylesheet(rules, context) {
129
129
  return returnValue
130
130
  }
131
131
 
132
- export const DEFAULTS_LAYER = Symbol('defaults-layer')
133
-
134
132
  export default function expandTailwindAtRules(context) {
135
133
  return (root) => {
136
134
  let layerNodes = {
@@ -140,8 +138,6 @@ export default function expandTailwindAtRules(context) {
140
138
  variants: null,
141
139
  }
142
140
 
143
- // let hasApply = false
144
-
145
141
  root.walkAtRules((rule) => {
146
142
  // Make sure this file contains Tailwind directives. If not, we can save
147
143
  // a lot of work and bail early. Also we don't have to register our touch
@@ -152,13 +148,6 @@ export default function expandTailwindAtRules(context) {
152
148
  layerNodes[rule.params] = rule
153
149
  }
154
150
  }
155
-
156
- // We also want to check for @apply because the user can
157
- // apply classes in an isolated environment like CSS
158
- // modules and we still need to inject defaults
159
- // if (rule.name === 'apply') {
160
- // hasApply = true
161
- // }
162
151
  })
163
152
 
164
153
  if (Object.values(layerNodes).every((n) => n === null)) {
@@ -179,6 +168,8 @@ export default function expandTailwindAtRules(context) {
179
168
  getClassCandidates(transformer(content), extractor, candidates, seen)
180
169
  }
181
170
 
171
+ env.DEBUG && console.timeEnd('Reading changed files')
172
+
182
173
  // ---
183
174
 
184
175
  // Generate the actual CSS
@@ -212,18 +203,7 @@ export default function expandTailwindAtRules(context) {
212
203
  // Replace any Tailwind directives with generated CSS
213
204
 
214
205
  if (layerNodes.base) {
215
- layerNodes.base.before(cloneNodes([...baseNodes], layerNodes.base.source))
216
- }
217
-
218
- // @defaults rules are unconditionally added first to ensure that
219
- // using any utility that relies on defaults will work even when
220
- // compiled in an isolated environment like CSS modules
221
- if (context.tailwindConfig[DEFAULTS_LAYER] !== false) {
222
- if (layerNodes.base) {
223
- layerNodes.base.after(cloneNodes([...defaultNodes], root.source))
224
- } else {
225
- root.prepend(cloneNodes([...defaultNodes], root.source))
226
- }
206
+ layerNodes.base.before(cloneNodes([...baseNodes, ...defaultNodes], layerNodes.base.source))
227
207
  }
228
208
 
229
209
  if (layerNodes.base) {
@@ -113,12 +113,12 @@ export default function resolveDefaultsAtRules({ tailwindConfig }) {
113
113
  }
114
114
  }
115
115
 
116
- if (selectorGroups.size === 0) {
117
- universal.remove()
118
- continue
119
- }
120
-
121
116
  if (flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
117
+ if (selectorGroups.size === 0) {
118
+ universal.remove()
119
+ continue
120
+ }
121
+
122
122
  for (let [, selectors] of selectorGroups) {
123
123
  let universalRule = postcss.rule()
124
124
 
@@ -20,6 +20,58 @@ 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
+
23
75
  function parseVariantFormatString(input) {
24
76
  if (input.includes('{')) {
25
77
  if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`)
@@ -89,39 +141,55 @@ function getClasses(selector) {
89
141
  return parser.transformSync(selector)
90
142
  }
91
143
 
92
- function extractCandidates(node) {
144
+ function extractCandidates(node, state = { containsNonOnDemandable: false }, depth = 0) {
93
145
  let classes = []
94
146
 
147
+ // Handle normal rules
95
148
  if (node.type === 'rule') {
96
149
  for (let selector of node.selectors) {
97
150
  let classCandidates = getClasses(selector)
98
151
  // At least one of the selectors contains non-"on-demandable" candidates.
99
- if (classCandidates.length === 0) return []
152
+ if (classCandidates.length === 0) {
153
+ state.containsNonOnDemandable = true
154
+ }
100
155
 
101
- classes = [...classes, ...classCandidates]
156
+ for (let classCandidate of classCandidates) {
157
+ classes.push(classCandidate)
158
+ }
102
159
  }
103
- return classes
104
160
  }
105
161
 
106
- if (node.type === 'atrule') {
162
+ // Handle at-rules (which contains nested rules)
163
+ else if (node.type === 'atrule') {
107
164
  node.walkRules((rule) => {
108
- classes = [...classes, ...rule.selectors.flatMap((selector) => getClasses(selector))]
165
+ for (let classCandidate of rule.selectors.flatMap((selector) =>
166
+ getClasses(selector, state, depth + 1)
167
+ )) {
168
+ classes.push(classCandidate)
169
+ }
109
170
  })
110
171
  }
111
172
 
173
+ if (depth === 0) {
174
+ return [state.containsNonOnDemandable || classes.length === 0, classes]
175
+ }
176
+
112
177
  return classes
113
178
  }
114
179
 
115
180
  function withIdentifiers(styles) {
116
181
  return parseStyles(styles).flatMap((node) => {
117
182
  let nodeMap = new Map()
118
- let candidates = extractCandidates(node)
183
+ let [containsNonOnDemandableSelectors, candidates] = extractCandidates(node)
119
184
 
120
- // If this isn't "on-demandable", assign it a universal candidate.
121
- if (candidates.length === 0) {
122
- return [['*', node]]
185
+ // If this isn't "on-demandable", assign it a universal candidate to always include it.
186
+ if (containsNonOnDemandableSelectors) {
187
+ candidates.unshift('*')
123
188
  }
124
189
 
190
+ // However, it could be that it also contains "on-demandable" candidates.
191
+ // E.g.: `span, .foo {}`, in that case it should still be possible to use
192
+ // `@apply foo` for example.
125
193
  return candidates.map((c) => {
126
194
  if (!nodeMap.has(node)) {
127
195
  nodeMap.set(node, node)
@@ -216,7 +284,9 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
216
284
  context.candidateRuleMap.set(identifier, [])
217
285
  }
218
286
 
219
- context.candidateRuleMap.get(identifier).push([{ sort: offset, layer: 'user' }, rule])
287
+ context.candidateRuleMap
288
+ .get(identifier)
289
+ .push(...partitionRules(rule).map((rule) => [{ sort: offset, layer: 'user' }, rule]))
220
290
  }
221
291
  },
222
292
  addBase(base) {
@@ -230,7 +300,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
230
300
 
231
301
  context.candidateRuleMap
232
302
  .get(prefixedIdentifier)
233
- .push([{ sort: offset, layer: 'base' }, rule])
303
+ .push(...partitionRules(rule).map((rule) => [{ sort: offset, layer: 'base' }, rule]))
234
304
  }
235
305
  },
236
306
  /**
@@ -244,7 +314,6 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
244
314
 
245
315
  for (let [identifier, rule] of withIdentifiers(groups)) {
246
316
  let prefixedIdentifier = prefixIdentifier(identifier, {})
247
- let offset = offsets.base++
248
317
 
249
318
  if (!context.candidateRuleMap.has(prefixedIdentifier)) {
250
319
  context.candidateRuleMap.set(prefixedIdentifier, [])
@@ -252,7 +321,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
252
321
 
253
322
  context.candidateRuleMap
254
323
  .get(prefixedIdentifier)
255
- .push([{ sort: offset, layer: 'defaults' }, rule])
324
+ .push(
325
+ ...partitionRules(rule).map((rule) => [
326
+ { sort: offsets.base++, layer: 'defaults' },
327
+ rule,
328
+ ])
329
+ )
256
330
  }
257
331
  },
258
332
  addComponents(components, options) {
@@ -265,7 +339,6 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
265
339
 
266
340
  for (let [identifier, rule] of withIdentifiers(components)) {
267
341
  let prefixedIdentifier = prefixIdentifier(identifier, options)
268
- let offset = offsets.components++
269
342
 
270
343
  classList.add(prefixedIdentifier)
271
344
 
@@ -275,7 +348,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
275
348
 
276
349
  context.candidateRuleMap
277
350
  .get(prefixedIdentifier)
278
- .push([{ sort: offset, layer: 'components', options }, rule])
351
+ .push(
352
+ ...partitionRules(rule).map((rule) => [
353
+ { sort: offsets.components++, layer: 'components', options },
354
+ rule,
355
+ ])
356
+ )
279
357
  }
280
358
  },
281
359
  addUtilities(utilities, options) {
@@ -288,7 +366,6 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
288
366
 
289
367
  for (let [identifier, rule] of withIdentifiers(utilities)) {
290
368
  let prefixedIdentifier = prefixIdentifier(identifier, options)
291
- let offset = offsets.utilities++
292
369
 
293
370
  classList.add(prefixedIdentifier)
294
371
 
@@ -298,7 +375,12 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
298
375
 
299
376
  context.candidateRuleMap
300
377
  .get(prefixedIdentifier)
301
- .push([{ sort: offset, layer: 'utilities', options }, rule])
378
+ .push(
379
+ ...partitionRules(rule).map((rule) => [
380
+ { sort: offsets.utilities++, layer: 'utilities', options },
381
+ rule,
382
+ ])
383
+ )
302
384
  }
303
385
  },
304
386
  matchUtilities: function (utilities, options) {
@@ -14,6 +14,8 @@ export default function processTailwindFeatures(setupContext) {
14
14
  return function (root, result) {
15
15
  let { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root)
16
16
 
17
+ detectNesting()(root, result)
18
+
17
19
  let context = setupContext({
18
20
  tailwindDirectives,
19
21
  applyDirectives,
@@ -37,7 +39,6 @@ export default function processTailwindFeatures(setupContext) {
37
39
 
38
40
  issueFlagNotices(context.tailwindConfig)
39
41
 
40
- detectNesting(context)(root, result)
41
42
  expandTailwindAtRules(context)(root, result)
42
43
  expandApplyAtRules(context)(root, result)
43
44
  evaluateTailwindFunctions(context)(root, result)
@@ -185,7 +185,7 @@ export function coerceValue(types, modifier, options, tailwindConfig) {
185
185
  // Find first matching type
186
186
  for (let type of [].concat(types)) {
187
187
  let result = typeMap[type](modifier, options, { tailwindConfig })
188
- if (result) return [result, type]
188
+ if (result !== undefined) return [result, type]
189
189
  }
190
190
 
191
191
  return []