tailwindcss 3.0.0 → 3.0.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.
@@ -529,27 +529,26 @@ export let corePlugins = {
529
529
  { supportsNegativeValues: true }
530
530
  ),
531
531
 
532
- transform: ({ addBase, addUtilities }) => {
533
- addBase({
534
- '@defaults transform': {
535
- '--tw-translate-x': '0',
536
- '--tw-translate-y': '0',
537
- '--tw-rotate': '0',
538
- '--tw-skew-x': '0',
539
- '--tw-skew-y': '0',
540
- '--tw-scale-x': '1',
541
- '--tw-scale-y': '1',
542
- '--tw-transform': [
543
- 'translateX(var(--tw-translate-x))',
544
- 'translateY(var(--tw-translate-y))',
545
- 'rotate(var(--tw-rotate))',
546
- 'skewX(var(--tw-skew-x))',
547
- 'skewY(var(--tw-skew-y))',
548
- 'scaleX(var(--tw-scale-x))',
549
- 'scaleY(var(--tw-scale-y))',
550
- ].join(' '),
551
- },
532
+ transform: ({ addDefaults, addUtilities }) => {
533
+ addDefaults('transform', {
534
+ '--tw-translate-x': '0',
535
+ '--tw-translate-y': '0',
536
+ '--tw-rotate': '0',
537
+ '--tw-skew-x': '0',
538
+ '--tw-skew-y': '0',
539
+ '--tw-scale-x': '1',
540
+ '--tw-scale-y': '1',
541
+ '--tw-transform': [
542
+ 'translateX(var(--tw-translate-x))',
543
+ 'translateY(var(--tw-translate-y))',
544
+ 'rotate(var(--tw-rotate))',
545
+ 'skewX(var(--tw-skew-x))',
546
+ 'skewY(var(--tw-skew-y))',
547
+ 'scaleX(var(--tw-scale-x))',
548
+ 'scaleY(var(--tw-scale-y))',
549
+ ].join(' '),
552
550
  })
551
+
553
552
  addUtilities({
554
553
  '.transform': { '@defaults transform': {}, transform: 'var(--tw-transform)' },
555
554
  '.transform-cpu': {
@@ -611,14 +610,12 @@ export let corePlugins = {
611
610
 
612
611
  cursor: createUtilityPlugin('cursor'),
613
612
 
614
- touchAction: ({ addBase, addUtilities }) => {
615
- addBase({
616
- '@defaults touch-action': {
617
- '--tw-pan-x': 'var(--tw-empty,/*!*/ /*!*/)',
618
- '--tw-pan-y': 'var(--tw-empty,/*!*/ /*!*/)',
619
- '--tw-pinch-zoom': 'var(--tw-empty,/*!*/ /*!*/)',
620
- '--tw-touch-action': 'var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom)',
621
- },
613
+ touchAction: ({ addDefaults, addUtilities }) => {
614
+ addDefaults('touch-action', {
615
+ '--tw-pan-x': 'var(--tw-empty,/*!*/ /*!*/)',
616
+ '--tw-pan-y': 'var(--tw-empty,/*!*/ /*!*/)',
617
+ '--tw-pinch-zoom': 'var(--tw-empty,/*!*/ /*!*/)',
618
+ '--tw-touch-action': 'var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom)',
622
619
  })
623
620
 
624
621
  addUtilities({
@@ -681,11 +678,9 @@ export let corePlugins = {
681
678
  })
682
679
  },
683
680
 
684
- scrollSnapType: ({ addUtilities, addBase }) => {
685
- addBase({
686
- '@defaults scroll-snap-type': {
687
- '--tw-scroll-snap-strictness': 'proximity',
688
- },
681
+ scrollSnapType: ({ addDefaults, addUtilities }) => {
682
+ addDefaults('scroll-snap-type', {
683
+ '--tw-scroll-snap-strictness': 'proximity',
689
684
  })
690
685
 
691
686
  addUtilities({
@@ -1182,22 +1177,21 @@ export let corePlugins = {
1182
1177
  })
1183
1178
  },
1184
1179
 
1185
- borderColor: ({ addBase, matchUtilities, theme, corePlugins }) => {
1180
+ borderColor: ({ addDefaults, matchUtilities, theme, corePlugins }) => {
1186
1181
  if (!corePlugins('borderOpacity')) {
1187
1182
  let value = theme('borderColor.DEFAULT', 'currentColor')
1188
- addBase({
1189
- '@defaults border-width': {
1190
- 'border-color': toColorValue(value),
1191
- },
1183
+ addDefaults('border-width', {
1184
+ 'border-color': toColorValue(value),
1192
1185
  })
1193
1186
  } else {
1194
- addBase({
1195
- '@defaults border-width': withAlphaVariable({
1187
+ addDefaults(
1188
+ 'border-width',
1189
+ withAlphaVariable({
1196
1190
  color: theme('borderColor.DEFAULT', 'currentColor'),
1197
1191
  property: 'border-color',
1198
1192
  variable: '--tw-border-opacity',
1199
- }),
1200
- })
1193
+ })
1194
+ )
1201
1195
  }
1202
1196
 
1203
1197
  matchUtilities(
@@ -1660,10 +1654,10 @@ export let corePlugins = {
1660
1654
 
1661
1655
  textDecoration: ({ addUtilities }) => {
1662
1656
  addUtilities({
1663
- '.underline': { 'text-decoration': 'underline' },
1664
- '.overline': { 'text-decoration': 'overline' },
1665
- '.line-through': { 'text-decoration': 'line-through' },
1666
- '.no-underline': { 'text-decoration': 'none' },
1657
+ '.underline': { 'text-decoration-line': 'underline' },
1658
+ '.overline': { 'text-decoration-line': 'overline' },
1659
+ '.line-through': { 'text-decoration-line': 'line-through' },
1660
+ '.no-underline': { 'text-decoration-line': 'none' },
1667
1661
  })
1668
1662
  },
1669
1663
 
@@ -1823,14 +1817,12 @@ export let corePlugins = {
1823
1817
  `var(--tw-shadow)`,
1824
1818
  ].join(', ')
1825
1819
 
1826
- return function ({ matchUtilities, addBase, theme }) {
1827
- addBase({
1828
- '@defaults box-shadow': {
1829
- '--tw-ring-offset-shadow': '0 0 #0000',
1830
- '--tw-ring-shadow': '0 0 #0000',
1831
- '--tw-shadow': '0 0 #0000',
1832
- '--tw-shadow-colored': '0 0 #0000',
1833
- },
1820
+ return function ({ matchUtilities, addDefaults, theme }) {
1821
+ addDefaults(' box-shadow', {
1822
+ '--tw-ring-offset-shadow': '0 0 #0000',
1823
+ '--tw-ring-shadow': '0 0 #0000',
1824
+ '--tw-shadow': '0 0 #0000',
1825
+ '--tw-shadow-colored': '0 0 #0000',
1834
1826
  })
1835
1827
 
1836
1828
  matchUtilities(
@@ -1908,7 +1900,7 @@ export let corePlugins = {
1908
1900
  )
1909
1901
  },
1910
1902
 
1911
- ringWidth: ({ matchUtilities, addBase, addUtilities, theme }) => {
1903
+ ringWidth: ({ matchUtilities, addDefaults, addUtilities, theme }) => {
1912
1904
  let ringOpacityDefault = theme('ringOpacity.DEFAULT', '0.5')
1913
1905
  let ringColorDefault = withAlphaValue(
1914
1906
  theme('ringColor.DEFAULT'),
@@ -1916,17 +1908,15 @@ export let corePlugins = {
1916
1908
  `rgb(147 197 253 / ${ringOpacityDefault})`
1917
1909
  )
1918
1910
 
1919
- addBase({
1920
- '@defaults ring-width': {
1921
- '--tw-ring-inset': 'var(--tw-empty,/*!*/ /*!*/)',
1922
- '--tw-ring-offset-width': theme('ringOffsetWidth.DEFAULT', '0px'),
1923
- '--tw-ring-offset-color': theme('ringOffsetColor.DEFAULT', '#fff'),
1924
- '--tw-ring-color': ringColorDefault,
1925
- '--tw-ring-offset-shadow': '0 0 #0000',
1926
- '--tw-ring-shadow': '0 0 #0000',
1927
- '--tw-shadow': '0 0 #0000',
1928
- '--tw-shadow-colored': '0 0 #0000',
1929
- },
1911
+ addDefaults('ring-width', {
1912
+ '--tw-ring-inset': 'var(--tw-empty,/*!*/ /*!*/)',
1913
+ '--tw-ring-offset-width': theme('ringOffsetWidth.DEFAULT', '0px'),
1914
+ '--tw-ring-offset-color': theme('ringOffsetColor.DEFAULT', '#fff'),
1915
+ '--tw-ring-color': ringColorDefault,
1916
+ '--tw-ring-offset-shadow': '0 0 #0000',
1917
+ '--tw-ring-shadow': '0 0 #0000',
1918
+ '--tw-shadow': '0 0 #0000',
1919
+ '--tw-shadow-colored': '0 0 #0000',
1930
1920
  })
1931
1921
 
1932
1922
  matchUtilities(
@@ -2133,30 +2123,28 @@ export let corePlugins = {
2133
2123
  )
2134
2124
  },
2135
2125
 
2136
- filter: ({ addBase, addUtilities }) => {
2137
- addBase({
2138
- '@defaults filter': {
2139
- '--tw-blur': 'var(--tw-empty,/*!*/ /*!*/)',
2140
- '--tw-brightness': 'var(--tw-empty,/*!*/ /*!*/)',
2141
- '--tw-contrast': 'var(--tw-empty,/*!*/ /*!*/)',
2142
- '--tw-grayscale': 'var(--tw-empty,/*!*/ /*!*/)',
2143
- '--tw-hue-rotate': 'var(--tw-empty,/*!*/ /*!*/)',
2144
- '--tw-invert': 'var(--tw-empty,/*!*/ /*!*/)',
2145
- '--tw-saturate': 'var(--tw-empty,/*!*/ /*!*/)',
2146
- '--tw-sepia': 'var(--tw-empty,/*!*/ /*!*/)',
2147
- '--tw-drop-shadow': 'var(--tw-empty,/*!*/ /*!*/)',
2148
- '--tw-filter': [
2149
- 'var(--tw-blur)',
2150
- 'var(--tw-brightness)',
2151
- 'var(--tw-contrast)',
2152
- 'var(--tw-grayscale)',
2153
- 'var(--tw-hue-rotate)',
2154
- 'var(--tw-invert)',
2155
- 'var(--tw-saturate)',
2156
- 'var(--tw-sepia)',
2157
- 'var(--tw-drop-shadow)',
2158
- ].join(' '),
2159
- },
2126
+ filter: ({ addDefaults, addUtilities }) => {
2127
+ addDefaults('filter', {
2128
+ '--tw-blur': 'var(--tw-empty,/*!*/ /*!*/)',
2129
+ '--tw-brightness': 'var(--tw-empty,/*!*/ /*!*/)',
2130
+ '--tw-contrast': 'var(--tw-empty,/*!*/ /*!*/)',
2131
+ '--tw-grayscale': 'var(--tw-empty,/*!*/ /*!*/)',
2132
+ '--tw-hue-rotate': 'var(--tw-empty,/*!*/ /*!*/)',
2133
+ '--tw-invert': 'var(--tw-empty,/*!*/ /*!*/)',
2134
+ '--tw-saturate': 'var(--tw-empty,/*!*/ /*!*/)',
2135
+ '--tw-sepia': 'var(--tw-empty,/*!*/ /*!*/)',
2136
+ '--tw-drop-shadow': 'var(--tw-empty,/*!*/ /*!*/)',
2137
+ '--tw-filter': [
2138
+ 'var(--tw-blur)',
2139
+ 'var(--tw-brightness)',
2140
+ 'var(--tw-contrast)',
2141
+ 'var(--tw-grayscale)',
2142
+ 'var(--tw-hue-rotate)',
2143
+ 'var(--tw-invert)',
2144
+ 'var(--tw-saturate)',
2145
+ 'var(--tw-sepia)',
2146
+ 'var(--tw-drop-shadow)',
2147
+ ].join(' '),
2160
2148
  })
2161
2149
  addUtilities({
2162
2150
  '.filter': { '@defaults filter': {}, filter: 'var(--tw-filter)' },
@@ -2299,30 +2287,28 @@ export let corePlugins = {
2299
2287
  )
2300
2288
  },
2301
2289
 
2302
- backdropFilter: ({ addBase, addUtilities }) => {
2303
- addBase({
2304
- '@defaults backdrop-filter': {
2305
- '--tw-backdrop-blur': 'var(--tw-empty,/*!*/ /*!*/)',
2306
- '--tw-backdrop-brightness': 'var(--tw-empty,/*!*/ /*!*/)',
2307
- '--tw-backdrop-contrast': 'var(--tw-empty,/*!*/ /*!*/)',
2308
- '--tw-backdrop-grayscale': 'var(--tw-empty,/*!*/ /*!*/)',
2309
- '--tw-backdrop-hue-rotate': 'var(--tw-empty,/*!*/ /*!*/)',
2310
- '--tw-backdrop-invert': 'var(--tw-empty,/*!*/ /*!*/)',
2311
- '--tw-backdrop-opacity': 'var(--tw-empty,/*!*/ /*!*/)',
2312
- '--tw-backdrop-saturate': 'var(--tw-empty,/*!*/ /*!*/)',
2313
- '--tw-backdrop-sepia': 'var(--tw-empty,/*!*/ /*!*/)',
2314
- '--tw-backdrop-filter': [
2315
- 'var(--tw-backdrop-blur)',
2316
- 'var(--tw-backdrop-brightness)',
2317
- 'var(--tw-backdrop-contrast)',
2318
- 'var(--tw-backdrop-grayscale)',
2319
- 'var(--tw-backdrop-hue-rotate)',
2320
- 'var(--tw-backdrop-invert)',
2321
- 'var(--tw-backdrop-opacity)',
2322
- 'var(--tw-backdrop-saturate)',
2323
- 'var(--tw-backdrop-sepia)',
2324
- ].join(' '),
2325
- },
2290
+ backdropFilter: ({ addDefaults, addUtilities }) => {
2291
+ addDefaults('backdrop-filter', {
2292
+ '--tw-backdrop-blur': 'var(--tw-empty,/*!*/ /*!*/)',
2293
+ '--tw-backdrop-brightness': 'var(--tw-empty,/*!*/ /*!*/)',
2294
+ '--tw-backdrop-contrast': 'var(--tw-empty,/*!*/ /*!*/)',
2295
+ '--tw-backdrop-grayscale': 'var(--tw-empty,/*!*/ /*!*/)',
2296
+ '--tw-backdrop-hue-rotate': 'var(--tw-empty,/*!*/ /*!*/)',
2297
+ '--tw-backdrop-invert': 'var(--tw-empty,/*!*/ /*!*/)',
2298
+ '--tw-backdrop-opacity': 'var(--tw-empty,/*!*/ /*!*/)',
2299
+ '--tw-backdrop-saturate': 'var(--tw-empty,/*!*/ /*!*/)',
2300
+ '--tw-backdrop-sepia': 'var(--tw-empty,/*!*/ /*!*/)',
2301
+ '--tw-backdrop-filter': [
2302
+ 'var(--tw-backdrop-blur)',
2303
+ 'var(--tw-backdrop-brightness)',
2304
+ 'var(--tw-backdrop-contrast)',
2305
+ 'var(--tw-backdrop-grayscale)',
2306
+ 'var(--tw-backdrop-hue-rotate)',
2307
+ 'var(--tw-backdrop-invert)',
2308
+ 'var(--tw-backdrop-opacity)',
2309
+ 'var(--tw-backdrop-saturate)',
2310
+ 'var(--tw-backdrop-sepia)',
2311
+ ].join(' '),
2326
2312
  })
2327
2313
  addUtilities({
2328
2314
  '.backdrop-filter': {
@@ -144,7 +144,7 @@ sup {
144
144
  table {
145
145
  text-indent: 0; /* 1 */
146
146
  border-color: inherit; /* 2 */
147
- border-collapse: collapse; /* 3 */
147
+ border-collapse: collapse; /* 3 */
148
148
  }
149
149
 
150
150
  /*
@@ -289,6 +289,7 @@ legend {
289
289
 
290
290
  ol,
291
291
  ul,
292
+ li,
292
293
  menu {
293
294
  list-style: none;
294
295
  margin: 0;
@@ -310,7 +311,7 @@ textarea {
310
311
 
311
312
  input::placeholder,
312
313
  textarea::placeholder {
313
- opacity: 1; /* 1 */
314
+ opacity: 1; /* 1 */
314
315
  color: theme('colors.gray.400', #9ca3af); /* 2 */
315
316
  }
316
317
 
@@ -2,7 +2,11 @@ import chalk from 'chalk'
2
2
  import log from './util/log'
3
3
 
4
4
  let defaults = {
5
- optimizeUniversalDefaults: true,
5
+ // TODO: Drop this once we can safely rely on optimizeUniversalDefaults being
6
+ // the default.
7
+ optimizeUniversalDefaults: process.env.NODE_ENV === 'test' ? true : false,
8
+
9
+ // optimizeUniversalDefaults: true
6
10
  }
7
11
 
8
12
  let featureFlags = {
@@ -1,8 +1,24 @@
1
1
  import postcss from 'postcss'
2
+ import parser from 'postcss-selector-parser'
2
3
  import { resolveMatches } from './generateRules'
3
4
  import bigSign from '../util/bigSign'
4
5
  import escapeClassName from '../util/escapeClassName'
5
6
 
7
+ function containsBase(selector, classCandidateBase, separator) {
8
+ return parser((selectors) => {
9
+ let contains = false
10
+
11
+ selectors.walkClasses((classSelector) => {
12
+ if (classSelector.value.split(separator).pop() === classCandidateBase) {
13
+ contains = true
14
+ return false
15
+ }
16
+ })
17
+
18
+ return contains
19
+ }).transformSync(selector)
20
+ }
21
+
6
22
  function prefix(context, selector) {
7
23
  let prefix = context.tailwindConfig.prefix
8
24
  return typeof prefix === 'function' ? prefix(selector) : prefix + selector
@@ -129,10 +145,10 @@ function processApply(root, context) {
129
145
  // TODO: Should we use postcss-selector-parser for this instead?
130
146
  function replaceSelector(selector, utilitySelectors, candidate) {
131
147
  let needle = `.${escapeClassName(candidate)}`
132
- let utilitySelectorsList = utilitySelectors.split(/\s*,\s*/g)
148
+ let utilitySelectorsList = utilitySelectors.split(/\s*\,(?![^(]*\))\s*/g)
133
149
 
134
150
  return selector
135
- .split(/\s*,\s*/g)
151
+ .split(/\s*\,(?![^(]*\))\s*/g)
136
152
  .map((s) => {
137
153
  let replaced = []
138
154
 
@@ -196,7 +212,18 @@ function processApply(root, context) {
196
212
  let siblings = []
197
213
 
198
214
  for (let [applyCandidate, important, rules] of candidates) {
215
+ let base = applyCandidate.split(context.tailwindConfig.separator).pop()
216
+
199
217
  for (let [meta, node] of rules) {
218
+ if (
219
+ containsBase(parent.selector, base, context.tailwindConfig.separator) &&
220
+ containsBase(node.selector, base, context.tailwindConfig.separator)
221
+ ) {
222
+ throw node.error(
223
+ `Circular dependency detected when using: \`@apply ${applyCandidate}\``
224
+ )
225
+ }
226
+
200
227
  let root = postcss.root({ nodes: [node.clone()] })
201
228
  let canRewriteSelector =
202
229
  node.type !== 'atrule' || (node.type === 'atrule' && node.name !== 'keyframes')
@@ -99,6 +99,7 @@ function buildStylesheet(rules, context) {
99
99
 
100
100
  let returnValue = {
101
101
  base: new Set(),
102
+ defaults: new Set(),
102
103
  components: new Set(),
103
104
  utilities: new Set(),
104
105
  variants: new Set(),
@@ -125,6 +126,11 @@ function buildStylesheet(rules, context) {
125
126
  continue
126
127
  }
127
128
 
129
+ if (sort & context.layerOrder.defaults) {
130
+ returnValue.defaults.add(rule)
131
+ continue
132
+ }
133
+
128
134
  if (sort & context.layerOrder.components) {
129
135
  returnValue.components.add(rule)
130
136
  continue
@@ -144,6 +150,8 @@ function buildStylesheet(rules, context) {
144
150
  return returnValue
145
151
  }
146
152
 
153
+ export const DEFAULTS_LAYER = Symbol('defaults-layer')
154
+
147
155
  export default function expandTailwindAtRules(context) {
148
156
  return (root) => {
149
157
  let layerNodes = {
@@ -202,6 +210,7 @@ export default function expandTailwindAtRules(context) {
202
210
  env.DEBUG && console.timeEnd('Build stylesheet')
203
211
 
204
212
  let {
213
+ defaults: defaultNodes,
205
214
  base: baseNodes,
206
215
  components: componentNodes,
207
216
  utilities: utilityNodes,
@@ -214,6 +223,20 @@ export default function expandTailwindAtRules(context) {
214
223
 
215
224
  if (layerNodes.base) {
216
225
  layerNodes.base.before(cloneNodes([...baseNodes], layerNodes.base.source))
226
+ }
227
+
228
+ // @defaults rules are unconditionally added first to ensure that
229
+ // using any utility that relies on defaults will work even when
230
+ // compiled in an isolated environment like CSS modules
231
+ if (context.tailwindConfig[DEFAULTS_LAYER] !== false) {
232
+ if (layerNodes.base) {
233
+ layerNodes.base.after(cloneNodes([...defaultNodes], root.source))
234
+ } else {
235
+ root.prepend(cloneNodes([...defaultNodes], root.source))
236
+ }
237
+ }
238
+
239
+ if (layerNodes.base) {
217
240
  layerNodes.base.remove()
218
241
  }
219
242
 
@@ -248,6 +248,21 @@ function parseRules(rule, cache, options = {}) {
248
248
  return [cache.get(rule), options]
249
249
  }
250
250
 
251
+ const IS_VALID_PROPERTY_NAME = /^[a-z_-]/
252
+
253
+ function isValidPropName(name) {
254
+ return IS_VALID_PROPERTY_NAME.test(name)
255
+ }
256
+
257
+ function isParsableCssValue(property, value) {
258
+ try {
259
+ postcss.parse(`a{${property}:${value}}`).toResult()
260
+ return true
261
+ } catch (err) {
262
+ return false
263
+ }
264
+ }
265
+
251
266
  function extractArbitraryProperty(classCandidate, context) {
252
267
  let [, property, value] = classCandidate.match(/^\[([a-zA-Z0-9-_]+):(\S+)\]$/) ?? []
253
268
 
@@ -255,9 +270,17 @@ function extractArbitraryProperty(classCandidate, context) {
255
270
  return null
256
271
  }
257
272
 
273
+ if (!isValidPropName(property)) {
274
+ return null
275
+ }
276
+
277
+ if (!isValidArbitraryValue(value)) {
278
+ return null
279
+ }
280
+
258
281
  let normalized = normalize(value)
259
282
 
260
- if (!isValidArbitraryValue(normalized)) {
283
+ if (!isParsableCssValue(property, normalized)) {
261
284
  return null
262
285
  }
263
286
 
@@ -71,6 +71,8 @@ function extractElementSelector(selector) {
71
71
  export default function resolveDefaultsAtRules({ tailwindConfig }) {
72
72
  return (root) => {
73
73
  let variableNodeMap = new Map()
74
+
75
+ /** @type {Set<import('postcss').AtRule>} */
74
76
  let universals = new Set()
75
77
 
76
78
  root.walkAtRules('defaults', (rule) => {
@@ -90,31 +92,50 @@ export default function resolveDefaultsAtRules({ tailwindConfig }) {
90
92
  })
91
93
 
92
94
  for (let universal of universals) {
93
- let selectors = new Set()
95
+ /** @type {Map<string, Set<string>>} */
96
+ let selectorGroups = new Map()
94
97
 
95
98
  let rules = variableNodeMap.get(universal.params) ?? []
96
99
 
97
100
  for (let rule of rules) {
98
101
  for (let selector of extractElementSelector(rule.selector)) {
102
+ // If selector contains a vendor prefix after a pseudo element or class,
103
+ // we consider them separately because merging the declarations into
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__'
108
+
109
+ let selectors = selectorGroups.get(selectorGroupName) ?? new Set()
110
+ selectorGroups.set(selectorGroupName, selectors)
111
+
99
112
  selectors.add(selector)
100
113
  }
101
114
  }
102
115
 
103
- if (selectors.size === 0) {
116
+ if (selectorGroups.size === 0) {
104
117
  universal.remove()
105
118
  continue
106
119
  }
107
120
 
108
- let universalRule = postcss.rule()
109
-
110
121
  if (flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
111
- universalRule.selectors = [...selectors]
122
+ for (let [, selectors] of selectorGroups) {
123
+ let universalRule = postcss.rule()
124
+
125
+ universalRule.selectors = [...selectors]
126
+
127
+ universalRule.append(universal.nodes.map((node) => node.clone()))
128
+ universal.before(universalRule)
129
+ }
112
130
  } else {
131
+ let universalRule = postcss.rule()
132
+
113
133
  universalRule.selectors = ['*', '::before', '::after']
134
+
135
+ universalRule.append(universal.nodes)
136
+ universal.before(universalRule)
114
137
  }
115
138
 
116
- universalRule.append(universal.nodes)
117
- universal.before(universalRule)
118
139
  universal.remove()
119
140
  }
120
141
  }
@@ -233,6 +233,28 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
233
233
  .push([{ sort: offset, layer: 'base' }, rule])
234
234
  }
235
235
  },
236
+ /**
237
+ * @param {string} group
238
+ * @param {Record<string, string | string[]>} declarations
239
+ */
240
+ addDefaults(group, declarations) {
241
+ const groups = {
242
+ [`@defaults ${group}`]: declarations,
243
+ }
244
+
245
+ for (let [identifier, rule] of withIdentifiers(groups)) {
246
+ let prefixedIdentifier = prefixIdentifier(identifier, {})
247
+ let offset = offsets.base++
248
+
249
+ if (!context.candidateRuleMap.has(prefixedIdentifier)) {
250
+ context.candidateRuleMap.set(prefixedIdentifier, [])
251
+ }
252
+
253
+ context.candidateRuleMap
254
+ .get(prefixedIdentifier)
255
+ .push([{ sort: offset, layer: 'defaults' }, rule])
256
+ }
257
+ },
236
258
  addComponents(components, options) {
237
259
  let defaultOptions = {
238
260
  respectPrefix: true,
@@ -528,6 +550,7 @@ function registerPlugins(plugins, context) {
528
550
  let variantList = []
529
551
  let variantMap = new Map()
530
552
  let offsets = {
553
+ defaults: 0n,
531
554
  base: 0n,
532
555
  components: 0n,
533
556
  utilities: 0n,
@@ -555,6 +578,7 @@ function registerPlugins(plugins, context) {
555
578
 
556
579
  let highestOffset = ((args) => args.reduce((m, e) => (e > m ? e : m)))([
557
580
  offsets.base,
581
+ offsets.defaults,
558
582
  offsets.components,
559
583
  offsets.utilities,
560
584
  offsets.user,
@@ -566,13 +590,14 @@ function registerPlugins(plugins, context) {
566
590
  context.arbitraryPropertiesSort = ((1n << reservedBits) << 0n) - 1n
567
591
 
568
592
  context.layerOrder = {
569
- base: (1n << reservedBits) << 0n,
570
- components: (1n << reservedBits) << 1n,
571
- utilities: (1n << reservedBits) << 2n,
572
- user: (1n << reservedBits) << 3n,
593
+ defaults: (1n << reservedBits) << 0n,
594
+ base: (1n << reservedBits) << 1n,
595
+ components: (1n << reservedBits) << 2n,
596
+ utilities: (1n << reservedBits) << 3n,
597
+ user: (1n << reservedBits) << 4n,
573
598
  }
574
599
 
575
- reservedBits += 4n
600
+ reservedBits += 5n
576
601
 
577
602
  let offset = 0
578
603
  context.variantOrder = new Map(
@@ -626,7 +651,15 @@ function registerPlugins(plugins, context) {
626
651
  let utils = Array.isArray(util)
627
652
  ? (() => {
628
653
  let [utilName, options] = util
629
- return Object.keys(options?.values ?? {}).map((value) => formatClass(utilName, value))
654
+ let classes = Object.keys(options?.values ?? {}).map((value) =>
655
+ formatClass(utilName, value)
656
+ )
657
+
658
+ if (options?.supportsNegativeValues) {
659
+ classes = [...classes, ...classes.map((cls) => '-' + cls)]
660
+ }
661
+
662
+ return classes
630
663
  })()
631
664
  : [util]
632
665
 
@@ -5,6 +5,12 @@ export function defaults(target, ...sources) {
5
5
  target[k] = source[k]
6
6
  }
7
7
  }
8
+
9
+ for (let k of Object.getOwnPropertySymbols(source)) {
10
+ if (!target?.hasOwnProperty?.(k)) {
11
+ target[k] = source[k]
12
+ }
13
+ }
8
14
  }
9
15
 
10
16
  return target
package/src/util/log.js CHANGED
@@ -12,6 +12,10 @@ function log(chalk, messages, key) {
12
12
  messages.forEach((message) => console.warn(chalk, '-', message))
13
13
  }
14
14
 
15
+ export function dim(input) {
16
+ return chalk.dim(input)
17
+ }
18
+
15
19
  export default {
16
20
  info(key, messages) {
17
21
  log(chalk.bold.cyan('info'), ...(Array.isArray(key) ? [key] : [messages, key]))