tailwindcss 0.0.0-insiders.d6301bd → 0.0.0-insiders.e2d5f21

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +39 -3
  2. package/lib/cli.js +60 -60
  3. package/lib/constants.js +1 -1
  4. package/lib/corePluginList.js +4 -0
  5. package/lib/corePlugins.js +157 -54
  6. package/lib/css/preflight.css +2 -1
  7. package/lib/featureFlags.js +3 -3
  8. package/lib/lib/collapseDuplicateDeclarations.js +2 -2
  9. package/lib/lib/detectNesting.js +17 -2
  10. package/lib/lib/evaluateTailwindFunctions.js +9 -5
  11. package/lib/lib/expandApplyAtRules.js +7 -7
  12. package/lib/lib/expandTailwindAtRules.js +2 -0
  13. package/lib/lib/generateRules.js +46 -10
  14. package/lib/lib/resolveDefaultsAtRules.js +2 -2
  15. package/lib/lib/setupContextUtils.js +15 -72
  16. package/lib/lib/sharedState.js +1 -1
  17. package/lib/lib/substituteScreenAtRules.js +7 -4
  18. package/lib/util/buildMediaQuery.js +13 -24
  19. package/lib/util/createUtilityPlugin.js +2 -2
  20. package/lib/util/dataTypes.js +23 -3
  21. package/lib/util/formatVariantSelector.js +93 -9
  22. package/lib/util/isValidArbitraryValue.js +64 -0
  23. package/lib/util/nameClass.js +1 -0
  24. package/lib/util/normalizeConfig.js +7 -7
  25. package/lib/util/normalizeScreens.js +58 -0
  26. package/lib/util/parseBoxShadowValue.js +77 -0
  27. package/lib/util/pluginUtils.js +12 -11
  28. package/lib/util/resolveConfig.js +8 -8
  29. package/package.json +10 -10
  30. package/peers/index.js +3772 -3072
  31. package/src/corePluginList.js +1 -1
  32. package/src/corePlugins.js +143 -61
  33. package/src/css/preflight.css +2 -1
  34. package/src/lib/detectNesting.js +22 -3
  35. package/src/lib/evaluateTailwindFunctions.js +5 -2
  36. package/src/lib/expandTailwindAtRules.js +2 -0
  37. package/src/lib/generateRules.js +34 -0
  38. package/src/lib/setupContextUtils.js +6 -58
  39. package/src/lib/substituteScreenAtRules.js +6 -3
  40. package/src/util/buildMediaQuery.js +14 -18
  41. package/src/util/dataTypes.js +19 -3
  42. package/src/util/formatVariantSelector.js +92 -1
  43. package/src/util/isValidArbitraryValue.js +61 -0
  44. package/src/util/nameClass.js +1 -1
  45. package/src/util/normalizeScreens.js +42 -0
  46. package/src/util/parseBoxShadowValue.js +71 -0
  47. package/src/util/pluginUtils.js +2 -0
  48. package/stubs/defaultConfig.stub.js +25 -9
@@ -1 +1 @@
1
- export default ["preflight","container","accessibility","pointerEvents","visibility","position","inset","isolation","zIndex","order","gridColumn","gridColumnStart","gridColumnEnd","gridRow","gridRowStart","gridRowEnd","float","clear","margin","boxSizing","display","aspectRatio","height","maxHeight","minHeight","width","minWidth","maxWidth","flex","flexShrink","flexGrow","flexBasis","tableLayout","borderCollapse","transformOrigin","translate","rotate","skew","scale","transform","animation","cursor","touchAction","userSelect","resize","scrollSnapType","scrollSnapAlign","scrollSnapStop","scrollMargin","scrollPadding","listStylePosition","listStyleType","appearance","columns","breakBefore","breakInside","breakAfter","gridAutoColumns","gridAutoFlow","gridAutoRows","gridTemplateColumns","gridTemplateRows","flexDirection","flexWrap","placeContent","placeItems","alignContent","alignItems","justifyContent","justifyItems","gap","space","divideWidth","divideStyle","divideColor","divideOpacity","placeSelf","alignSelf","justifySelf","overflow","overscrollBehavior","scrollBehavior","textOverflow","whitespace","wordBreak","borderRadius","borderWidth","borderStyle","borderColor","borderOpacity","backgroundColor","backgroundOpacity","backgroundImage","gradientColorStops","boxDecorationBreak","backgroundSize","backgroundAttachment","backgroundClip","backgroundPosition","backgroundRepeat","backgroundOrigin","fill","stroke","strokeWidth","objectFit","objectPosition","padding","textAlign","textIndent","verticalAlign","fontFamily","fontSize","fontWeight","textTransform","fontStyle","fontVariantNumeric","lineHeight","letterSpacing","textColor","textOpacity","textDecoration","textDecorationColor","fontSmoothing","placeholderColor","placeholderOpacity","caretColor","accentColor","opacity","backgroundBlendMode","mixBlendMode","boxShadow","outlineStyle","outlineWidth","outlineOffset","outlineColor","ringWidth","ringColor","ringOpacity","ringOffsetWidth","ringOffsetColor","blur","brightness","contrast","dropShadow","grayscale","hueRotate","invert","saturate","sepia","filter","backdropBlur","backdropBrightness","backdropContrast","backdropGrayscale","backdropHueRotate","backdropInvert","backdropOpacity","backdropSaturate","backdropSepia","backdropFilter","transitionProperty","transitionDelay","transitionDuration","transitionTimingFunction","willChange","content"]
1
+ export default ["preflight","container","accessibility","pointerEvents","visibility","position","inset","isolation","zIndex","order","gridColumn","gridColumnStart","gridColumnEnd","gridRow","gridRowStart","gridRowEnd","float","clear","margin","boxSizing","display","aspectRatio","height","maxHeight","minHeight","width","minWidth","maxWidth","flex","flexShrink","flexGrow","flexBasis","tableLayout","borderCollapse","transformOrigin","translate","rotate","skew","scale","transform","animation","cursor","touchAction","userSelect","resize","scrollSnapType","scrollSnapAlign","scrollSnapStop","scrollMargin","scrollPadding","listStylePosition","listStyleType","appearance","columns","breakBefore","breakInside","breakAfter","gridAutoColumns","gridAutoFlow","gridAutoRows","gridTemplateColumns","gridTemplateRows","flexDirection","flexWrap","placeContent","placeItems","alignContent","alignItems","justifyContent","justifyItems","gap","space","divideWidth","divideStyle","divideColor","divideOpacity","placeSelf","alignSelf","justifySelf","overflow","overscrollBehavior","scrollBehavior","textOverflow","whitespace","wordBreak","borderRadius","borderWidth","borderStyle","borderColor","borderOpacity","backgroundColor","backgroundOpacity","backgroundImage","gradientColorStops","boxDecorationBreak","backgroundSize","backgroundAttachment","backgroundClip","backgroundPosition","backgroundRepeat","backgroundOrigin","fill","stroke","strokeWidth","objectFit","objectPosition","padding","textAlign","textIndent","verticalAlign","fontFamily","fontSize","fontWeight","textTransform","fontStyle","fontVariantNumeric","lineHeight","letterSpacing","textColor","textOpacity","textDecoration","textDecorationColor","textDecorationStyle","textDecorationThickness","textUnderlineOffset","fontSmoothing","placeholderColor","placeholderOpacity","caretColor","accentColor","opacity","backgroundBlendMode","mixBlendMode","boxShadow","boxShadowColor","outlineStyle","outlineWidth","outlineOffset","outlineColor","ringWidth","ringColor","ringOpacity","ringOffsetWidth","ringOffsetColor","blur","brightness","contrast","dropShadow","grayscale","hueRotate","invert","saturate","sepia","filter","backdropBlur","backdropBrightness","backdropContrast","backdropGrayscale","backdropHueRotate","backdropInvert","backdropOpacity","backdropSaturate","backdropSepia","backdropFilter","transitionProperty","transitionDelay","transitionDuration","transitionTimingFunction","willChange","content"]
@@ -11,6 +11,8 @@ import isPlainObject from './util/isPlainObject'
11
11
  import transformThemeValue from './util/transformThemeValue'
12
12
  import { version as tailwindVersion } from '../package.json'
13
13
  import log from './util/log'
14
+ import { normalizeScreens } from './util/normalizeScreens'
15
+ import { formatBoxShadowValue, parseBoxShadowValue } from './util/parseBoxShadowValue'
14
16
 
15
17
  export let variantPlugins = {
16
18
  pseudoElementVariants: ({ addVariant }) => {
@@ -22,6 +24,8 @@ export let variantPlugins = {
22
24
 
23
25
  addVariant('file', '&::file-selector-button')
24
26
 
27
+ addVariant('placeholder', '&::placeholder')
28
+
25
29
  addVariant('before', ({ container }) => {
26
30
  container.walkRules((rule) => {
27
31
  let foundContent = false
@@ -155,13 +159,17 @@ export let variantPlugins = {
155
159
  },
156
160
 
157
161
  screenVariants: ({ theme, addVariant }) => {
158
- for (let screen in theme('screens')) {
159
- let size = theme('screens')[screen]
160
- let query = buildMediaQuery(size)
162
+ for (let screen of normalizeScreens(theme('screens'))) {
163
+ let query = buildMediaQuery(screen)
161
164
 
162
- addVariant(screen, `@media ${query}`)
165
+ addVariant(screen.name, `@media ${query}`)
163
166
  }
164
167
  },
168
+
169
+ orientationVariants: ({ addVariant }) => {
170
+ addVariant('portrait', '@media (orientation: portrait)')
171
+ addVariant('landscape', '@media (orientation: landscape)')
172
+ },
165
173
  }
166
174
 
167
175
  export let corePlugins = {
@@ -179,24 +187,10 @@ export let corePlugins = {
179
187
  },
180
188
 
181
189
  container: (() => {
182
- function extractMinWidths(breakpoints) {
183
- return Object.values(breakpoints ?? {}).flatMap((breakpoints) => {
184
- if (typeof breakpoints === 'string') {
185
- breakpoints = { min: breakpoints }
186
- }
187
-
188
- if (!Array.isArray(breakpoints)) {
189
- breakpoints = [breakpoints]
190
- }
191
-
192
- return breakpoints
193
- .filter((breakpoint) => {
194
- return breakpoint?.hasOwnProperty?.('min') || breakpoint?.hasOwnProperty('min-width')
195
- })
196
- .map((breakpoint) => {
197
- return breakpoint['min-width'] ?? breakpoint.min
198
- })
199
- })
190
+ function extractMinWidths(breakpoints = []) {
191
+ return breakpoints
192
+ .flatMap((breakpoint) => breakpoint.values.map((breakpoint) => breakpoint.min))
193
+ .filter((v) => v !== undefined)
200
194
  }
201
195
 
202
196
  function mapMinWidthsToPadding(minWidths, screens, paddings) {
@@ -225,16 +219,11 @@ export let corePlugins = {
225
219
  }
226
220
 
227
221
  for (let minWidth of minWidths) {
228
- for (let [screen, value] of Object.entries(screens)) {
229
- let screenMinWidth =
230
- typeof value === 'object' && value !== null ? value.min || value['min-width'] : value
231
-
232
- if (`${screenMinWidth}` === `${minWidth}`) {
233
- mapping.push({
234
- screen,
235
- minWidth,
236
- padding: paddings[screen],
237
- })
222
+ for (let screen of screens) {
223
+ for (let { min } of screen.values) {
224
+ if (min === minWidth) {
225
+ mapping.push({ minWidth, padding: paddings[screen.name] })
226
+ }
238
227
  }
239
228
  }
240
229
  }
@@ -243,12 +232,12 @@ export let corePlugins = {
243
232
  }
244
233
 
245
234
  return function ({ addComponents, theme }) {
246
- let screens = theme('container.screens', theme('screens'))
235
+ let screens = normalizeScreens(theme('container.screens', theme('screens')))
247
236
  let minWidths = extractMinWidths(screens)
248
237
  let paddings = mapMinWidthsToPadding(minWidths, screens, theme('container.padding'))
249
238
 
250
239
  let generatePaddingFor = (minWidth) => {
251
- let paddingConfig = paddings.find((padding) => `${padding.minWidth}` === `${minWidth}`)
240
+ let paddingConfig = paddings.find((padding) => padding.minWidth === minWidth)
252
241
 
253
242
  if (!paddingConfig) {
254
243
  return {}
@@ -514,27 +503,31 @@ export let corePlugins = {
514
503
  ],
515
504
  { supportsNegativeValues: true }
516
505
  ),
517
- scale: createUtilityPlugin('scale', [
506
+ scale: createUtilityPlugin(
507
+ 'scale',
518
508
  [
519
- 'scale',
520
509
  [
521
- ['@defaults transform', {}],
522
- '--tw-scale-x',
523
- '--tw-scale-y',
524
- ['transform', 'var(--tw-transform)'],
525
- ],
526
- ],
527
- [
528
- [
529
- 'scale-x',
530
- [['@defaults transform', {}], '--tw-scale-x', ['transform', 'var(--tw-transform)']],
510
+ 'scale',
511
+ [
512
+ ['@defaults transform', {}],
513
+ '--tw-scale-x',
514
+ '--tw-scale-y',
515
+ ['transform', 'var(--tw-transform)'],
516
+ ],
531
517
  ],
532
518
  [
533
- 'scale-y',
534
- [['@defaults transform', {}], '--tw-scale-y', ['transform', 'var(--tw-transform)']],
519
+ [
520
+ 'scale-x',
521
+ [['@defaults transform', {}], '--tw-scale-x', ['transform', 'var(--tw-transform)']],
522
+ ],
523
+ [
524
+ 'scale-y',
525
+ [['@defaults transform', {}], '--tw-scale-y', ['transform', 'var(--tw-transform)']],
526
+ ],
535
527
  ],
536
528
  ],
537
- ]),
529
+ { supportsNegativeValues: true }
530
+ ),
538
531
 
539
532
  transform: ({ addBase, addUtilities }) => {
540
533
  addBase({
@@ -618,17 +611,54 @@ export let corePlugins = {
618
611
 
619
612
  cursor: createUtilityPlugin('cursor'),
620
613
 
621
- touchAction: ({ addUtilities }) => {
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
+ },
622
+ })
623
+
622
624
  addUtilities({
623
625
  '.touch-auto': { 'touch-action': 'auto' },
624
626
  '.touch-none': { 'touch-action': 'none' },
625
- '.touch-pan-x': { 'touch-action': 'pan-x' },
626
- '.touch-pan-left': { 'touch-action': 'pan-left' },
627
- '.touch-pan-right': { 'touch-action': 'pan-right' },
628
- '.touch-pan-y': { 'touch-action': 'pan-y' },
629
- '.touch-pan-up': { 'touch-action': 'pan-up' },
630
- '.touch-pan-down': { 'touch-action': 'pan-down' },
631
- '.touch-pinch-zoom': { 'touch-action': 'pinch-zoom' },
627
+ '.touch-pan-x': {
628
+ '@defaults touch-action': {},
629
+ '--tw-pan-x': 'pan-x',
630
+ 'touch-action': 'var(--tw-touch-action)',
631
+ },
632
+ '.touch-pan-left': {
633
+ '@defaults touch-action': {},
634
+ '--tw-pan-x': 'pan-left',
635
+ 'touch-action': 'var(--tw-touch-action)',
636
+ },
637
+ '.touch-pan-right': {
638
+ '@defaults touch-action': {},
639
+ '--tw-pan-x': 'pan-right',
640
+ 'touch-action': 'var(--tw-touch-action)',
641
+ },
642
+ '.touch-pan-y': {
643
+ '@defaults touch-action': {},
644
+ '--tw-pan-y': 'pan-y',
645
+ 'touch-action': 'var(--tw-touch-action)',
646
+ },
647
+ '.touch-pan-up': {
648
+ '@defaults touch-action': {},
649
+ '--tw-pan-y': 'pan-up',
650
+ 'touch-action': 'var(--tw-touch-action)',
651
+ },
652
+ '.touch-pan-down': {
653
+ '@defaults touch-action': {},
654
+ '--tw-pan-y': 'pan-down',
655
+ 'touch-action': 'var(--tw-touch-action)',
656
+ },
657
+ '.touch-pinch-zoom': {
658
+ '@defaults touch-action': {},
659
+ '--tw-pinch-zoom': 'pinch-zoom',
660
+ 'touch-action': 'var(--tw-touch-action)',
661
+ },
632
662
  '.touch-manipulation': { 'touch-action': 'manipulation' },
633
663
  })
634
664
  },
@@ -1370,8 +1400,10 @@ export let corePlugins = {
1370
1400
 
1371
1401
  boxDecorationBreak: ({ addUtilities }) => {
1372
1402
  addUtilities({
1373
- '.decoration-slice': { 'box-decoration-break': 'slice' },
1374
- '.decoration-clone': { 'box-decoration-break': 'clone' },
1403
+ '.decoration-slice': { 'box-decoration-break': 'slice' }, // Deprecated
1404
+ '.decoration-clone': { 'box-decoration-break': 'clone' }, // Deprecated
1405
+ '.box-decoration-slice': { 'box-decoration-break': 'slice' },
1406
+ '.box-decoration-clone': { 'box-decoration-break': 'clone' },
1375
1407
  })
1376
1408
  },
1377
1409
 
@@ -1629,6 +1661,7 @@ export let corePlugins = {
1629
1661
  textDecoration: ({ addUtilities }) => {
1630
1662
  addUtilities({
1631
1663
  '.underline': { 'text-decoration': 'underline' },
1664
+ '.overline': { 'text-decoration': 'overline' },
1632
1665
  '.line-through': { 'text-decoration': 'line-through' },
1633
1666
  '.no-underline': { 'text-decoration': 'none' },
1634
1667
  })
@@ -1641,10 +1674,32 @@ export let corePlugins = {
1641
1674
  return { 'text-decoration-color': toColorValue(value) }
1642
1675
  },
1643
1676
  },
1644
- { values: flattenColorPalette(theme('textDecorationColor')), type: ['color', 'any'] }
1677
+ { values: flattenColorPalette(theme('textDecorationColor')), type: ['color'] }
1645
1678
  )
1646
1679
  },
1647
1680
 
1681
+ textDecorationStyle: ({ addUtilities }) => {
1682
+ addUtilities({
1683
+ '.decoration-solid': { 'text-decoration-style': 'solid' },
1684
+ '.decoration-double': { 'text-decoration-style': 'double' },
1685
+ '.decoration-dotted': { 'text-decoration-style': 'dotted' },
1686
+ '.decoration-dashed': { 'text-decoration-style': 'dashed' },
1687
+ '.decoration-wavy': { 'text-decoration-style': 'wavy' },
1688
+ })
1689
+ },
1690
+
1691
+ textDecorationThickness: createUtilityPlugin(
1692
+ 'textDecorationThickness',
1693
+ [['decoration', ['text-decoration-thickness']]],
1694
+ { type: ['length', 'percentage'] }
1695
+ ),
1696
+
1697
+ textUnderlineOffset: createUtilityPlugin(
1698
+ 'textUnderlineOffset',
1699
+ [['underline-offset', ['text-underline-offset']]],
1700
+ { type: ['length', 'percentage'] }
1701
+ ),
1702
+
1648
1703
  fontSmoothing: ({ addUtilities }) => {
1649
1704
  addUtilities({
1650
1705
  '.antialiased': {
@@ -1774,6 +1829,7 @@ export let corePlugins = {
1774
1829
  '--tw-ring-offset-shadow': '0 0 #0000',
1775
1830
  '--tw-ring-shadow': '0 0 #0000',
1776
1831
  '--tw-shadow': '0 0 #0000',
1832
+ '--tw-shadow-colored': '0 0 #0000',
1777
1833
  },
1778
1834
  })
1779
1835
 
@@ -1782,18 +1838,43 @@ export let corePlugins = {
1782
1838
  shadow: (value) => {
1783
1839
  value = transformValue(value)
1784
1840
 
1841
+ let ast = parseBoxShadowValue(value)
1842
+ for (let shadow of ast) {
1843
+ // Don't override color if the whole shadow is a variable
1844
+ if (!shadow.valid) {
1845
+ continue
1846
+ }
1847
+
1848
+ shadow.color = 'var(--tw-shadow-color)'
1849
+ }
1850
+
1785
1851
  return {
1786
1852
  '@defaults box-shadow': {},
1787
1853
  '--tw-shadow': value === 'none' ? '0 0 #0000' : value,
1854
+ '--tw-shadow-colored': value === 'none' ? '0 0 #0000' : formatBoxShadowValue(ast),
1788
1855
  'box-shadow': defaultBoxShadow,
1789
1856
  }
1790
1857
  },
1791
1858
  },
1792
- { values: theme('boxShadow') }
1859
+ { values: theme('boxShadow'), type: ['shadow'] }
1793
1860
  )
1794
1861
  }
1795
1862
  })(),
1796
1863
 
1864
+ boxShadowColor: ({ matchUtilities, theme }) => {
1865
+ matchUtilities(
1866
+ {
1867
+ shadow: (value) => {
1868
+ return {
1869
+ '--tw-shadow-color': toColorValue(value),
1870
+ '--tw-shadow': 'var(--tw-shadow-colored)',
1871
+ }
1872
+ },
1873
+ },
1874
+ { values: flattenColorPalette(theme('boxShadowColor')), type: ['color'] }
1875
+ )
1876
+ },
1877
+
1797
1878
  outlineStyle: ({ addUtilities }) => {
1798
1879
  addUtilities({
1799
1880
  '.outline-none': {
@@ -1844,6 +1925,7 @@ export let corePlugins = {
1844
1925
  '--tw-ring-offset-shadow': '0 0 #0000',
1845
1926
  '--tw-ring-shadow': '0 0 #0000',
1846
1927
  '--tw-shadow': '0 0 #0000',
1928
+ '--tw-shadow-colored': '0 0 #0000',
1847
1929
  },
1848
1930
  })
1849
1931
 
@@ -288,7 +288,8 @@ legend {
288
288
  }
289
289
 
290
290
  ol,
291
- ul {
291
+ ul,
292
+ menu {
292
293
  list-style: none;
293
294
  margin: 0;
294
295
  padding: 0;
@@ -2,6 +2,23 @@ export default function (_context) {
2
2
  return (root, result) => {
3
3
  let found = false
4
4
 
5
+ root.walkAtRules('tailwind', (node) => {
6
+ if (found) return false
7
+
8
+ if (node.parent && node.parent.type !== 'root') {
9
+ found = true
10
+ node.warn(
11
+ result,
12
+ [
13
+ 'Nested @tailwind rules were detected, but are not supported.',
14
+ "Consider using a prefix to scope Tailwind's classes: https://tailwindcss.com/docs/configuration#prefix",
15
+ 'Alternatively, use the important selector strategy: https://tailwindcss.com/docs/configuration#selector-strategy',
16
+ ].join('\n')
17
+ )
18
+ return false
19
+ }
20
+ })
21
+
5
22
  root.walkRules((rule) => {
6
23
  if (found) return false
7
24
 
@@ -9,10 +26,12 @@ export default function (_context) {
9
26
  found = true
10
27
  nestedRule.warn(
11
28
  result,
12
- // TODO: Improve this warning message
13
- 'Nested CSS detected, checkout the docs on how to support nesting: https://tailwindcss.com/docs/using-with-preprocessors#nesting'
29
+ [
30
+ 'Nested CSS was detected, but CSS nesting has not been configured correctly.',
31
+ 'Please enable a CSS nesting plugin *before* Tailwind in your configuration.',
32
+ 'See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting',
33
+ ].join('\n')
14
34
  )
15
-
16
35
  return false
17
36
  })
18
37
  })
@@ -2,6 +2,7 @@ import dlv from 'dlv'
2
2
  import didYouMean from 'didyoumean'
3
3
  import transformThemeValue from '../util/transformThemeValue'
4
4
  import parseValue from 'postcss-value-parser'
5
+ import { normalizeScreens } from '../util/normalizeScreens'
5
6
  import buildMediaQuery from '../util/buildMediaQuery'
6
7
  import { toPath } from '../util/toPath'
7
8
 
@@ -173,12 +174,14 @@ export default function ({ tailwindConfig: config }) {
173
174
  },
174
175
  screen: (node, screen) => {
175
176
  screen = screen.replace(/^['"]+/g, '').replace(/['"]+$/g, '')
177
+ let screens = normalizeScreens(config.theme.screens)
178
+ let screenDefinition = screens.find(({ name }) => name === screen)
176
179
 
177
- if (config.theme.screens[screen] === undefined) {
180
+ if (!screenDefinition) {
178
181
  throw node.error(`The '${screen}' screen does not exist in your theme.`)
179
182
  }
180
183
 
181
- return buildMediaQuery(config.theme.screens[screen])
184
+ return buildMediaQuery(screenDefinition)
182
185
  },
183
186
  }
184
187
  return (root) => {
@@ -15,6 +15,8 @@ const PATTERNS = [
15
15
  /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")]
16
16
  /([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
17
17
  /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
18
+ /([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]`
19
+ /([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']`
18
20
  /([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50`
19
21
  /([^<>"'`\s]*[^"'`\s:])/.source, // `px-1.5`, `uppercase` but not `uppercase:`
20
22
  ].join('|')
@@ -6,6 +6,9 @@ import prefixSelector from '../util/prefixSelector'
6
6
  import { updateAllClasses } from '../util/pluginUtils'
7
7
  import log from '../util/log'
8
8
  import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector'
9
+ import { asClass } from '../util/nameClass'
10
+ import { normalize } from '../util/dataTypes'
11
+ import isValidArbitraryValue from '../util/isValidArbitraryValue'
9
12
 
10
13
  let classNameParser = selectorParser((selectors) => {
11
14
  return selectors.first.filter(({ type }) => type === 'class').pop().value
@@ -245,11 +248,42 @@ function parseRules(rule, cache, options = {}) {
245
248
  return [cache.get(rule), options]
246
249
  }
247
250
 
251
+ function extractArbitraryProperty(classCandidate, context) {
252
+ let [, property, value] = classCandidate.match(/^\[([a-zA-Z0-9-_]+):(\S+)\]$/) ?? []
253
+
254
+ if (value === undefined) {
255
+ return null
256
+ }
257
+
258
+ let normalized = normalize(value)
259
+
260
+ if (!isValidArbitraryValue(normalized)) {
261
+ return null
262
+ }
263
+
264
+ return [
265
+ [
266
+ { sort: context.arbitraryPropertiesSort, layer: 'utilities' },
267
+ () => ({
268
+ [asClass(classCandidate)]: {
269
+ [property]: normalized,
270
+ },
271
+ }),
272
+ ],
273
+ ]
274
+ }
275
+
248
276
  function* resolveMatchedPlugins(classCandidate, context) {
249
277
  if (context.candidateRuleMap.has(classCandidate)) {
250
278
  yield [context.candidateRuleMap.get(classCandidate), 'DEFAULT']
251
279
  }
252
280
 
281
+ yield* (function* (arbitraryPropertyRule) {
282
+ if (arbitraryPropertyRule !== null) {
283
+ yield [arbitraryPropertyRule, 'DEFAULT']
284
+ }
285
+ })(extractArbitraryProperty(classCandidate, context))
286
+
253
287
  let candidatePrefix = classCandidate
254
288
  let negative = false
255
289
 
@@ -18,6 +18,7 @@ import { env } from './sharedState'
18
18
  import { toPath } from '../util/toPath'
19
19
  import log from '../util/log'
20
20
  import negateValue from '../util/negateValue'
21
+ import isValidArbitraryValue from '../util/isValidArbitraryValue'
21
22
 
22
23
  function parseVariantFormatString(input) {
23
24
  if (input.includes('{')) {
@@ -130,64 +131,6 @@ function withIdentifiers(styles) {
130
131
  })
131
132
  }
132
133
 
133
- let matchingBrackets = new Map([
134
- ['{', '}'],
135
- ['[', ']'],
136
- ['(', ')'],
137
- ])
138
- let inverseMatchingBrackets = new Map(
139
- Array.from(matchingBrackets.entries()).map(([k, v]) => [v, k])
140
- )
141
-
142
- let quotes = new Set(['"', "'", '`'])
143
-
144
- // Arbitrary values must contain balanced brackets (), [] and {}. Escaped
145
- // values don't count, and brackets inside quotes also don't count.
146
- //
147
- // E.g.: w-[this-is]w-[weird-and-invalid]
148
- // E.g.: w-[this-is\\]w-\\[weird-but-valid]
149
- // E.g.: content-['this-is-also-valid]-weirdly-enough']
150
- function isValidArbitraryValue(value) {
151
- let stack = []
152
- let inQuotes = false
153
-
154
- for (let i = 0; i < value.length; i++) {
155
- let char = value[i]
156
-
157
- // Non-escaped quotes allow us to "allow" anything in between
158
- if (quotes.has(char) && value[i - 1] !== '\\') {
159
- inQuotes = !inQuotes
160
- }
161
-
162
- if (inQuotes) continue
163
- if (value[i - 1] === '\\') continue // Escaped
164
-
165
- if (matchingBrackets.has(char)) {
166
- stack.push(char)
167
- } else if (inverseMatchingBrackets.has(char)) {
168
- let inverse = inverseMatchingBrackets.get(char)
169
-
170
- // Nothing to pop from, therefore it is unbalanced
171
- if (stack.length <= 0) {
172
- return false
173
- }
174
-
175
- // Popped value must match the inverse value, otherwise it is unbalanced
176
- if (stack.pop() !== inverse) {
177
- return false
178
- }
179
- }
180
- }
181
-
182
- // If there is still something on the stack, it is also unbalanced
183
- if (stack.length > 0) {
184
- return false
185
- }
186
-
187
- // All good, totally balanced!
188
- return true
189
- }
190
-
191
134
  function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offsets, classList }) {
192
135
  function getConfigValue(path, defaultValue) {
193
136
  return path ? dlv(tailwindConfig, path, defaultValue) : tailwindConfig
@@ -575,6 +518,7 @@ function resolvePlugins(context, root) {
575
518
  variantPlugins['darkVariants'],
576
519
  variantPlugins['printVariant'],
577
520
  variantPlugins['screenVariants'],
521
+ variantPlugins['orientationVariants'],
578
522
  ]
579
523
 
580
524
  return [...corePluginList, ...beforeVariants, ...userPlugins, ...afterVariants, ...layerPlugins]
@@ -617,6 +561,10 @@ function registerPlugins(plugins, context) {
617
561
  ])
618
562
  let reservedBits = BigInt(highestOffset.toString(2).length)
619
563
 
564
+ // A number one less than the top range of the highest offset area
565
+ // so arbitrary properties are always sorted at the end.
566
+ context.arbitraryPropertiesSort = ((1n << reservedBits) << 0n) - 1n
567
+
620
568
  context.layerOrder = {
621
569
  base: (1n << reservedBits) << 0n,
622
570
  components: (1n << reservedBits) << 1n,
@@ -1,16 +1,19 @@
1
+ import { normalizeScreens } from '../util/normalizeScreens'
1
2
  import buildMediaQuery from '../util/buildMediaQuery'
2
3
 
3
4
  export default function ({ tailwindConfig: { theme } }) {
4
5
  return function (css) {
5
6
  css.walkAtRules('screen', (atRule) => {
6
- const screen = atRule.params
7
+ let screen = atRule.params
8
+ let screens = normalizeScreens(theme.screens)
9
+ let screenDefinition = screens.find(({ name }) => name === screen)
7
10
 
8
- if (!theme.screens?.hasOwnProperty?.(screen)) {
11
+ if (!screenDefinition) {
9
12
  throw atRule.error(`No \`${screen}\` screen found.`)
10
13
  }
11
14
 
12
15
  atRule.name = 'media'
13
- atRule.params = buildMediaQuery(theme.screens[screen])
16
+ atRule.params = buildMediaQuery(screenDefinition)
14
17
  })
15
18
  }
16
19
  }
@@ -1,24 +1,20 @@
1
1
  export default function buildMediaQuery(screens) {
2
- if (typeof screens === 'string') {
3
- screens = { min: screens }
4
- }
5
-
6
- if (!Array.isArray(screens)) {
7
- screens = [screens]
8
- }
2
+ screens = Array.isArray(screens) ? screens : [screens]
9
3
 
10
4
  return screens
11
- .map((screen) => {
12
- if (screen?.hasOwnProperty?.('raw')) {
13
- return screen.raw
14
- }
5
+ .map((screen) =>
6
+ screen.values.map((screen) => {
7
+ if (screen.raw !== undefined) {
8
+ return screen.raw
9
+ }
15
10
 
16
- return Object.entries(screen)
17
- .map(([feature, value]) => {
18
- feature = { min: 'min-width', max: 'max-width' }[feature] ?? feature
19
- return `(${feature}: ${value})`
20
- })
21
- .join(' and ')
22
- })
11
+ return [
12
+ screen.min && `(min-width: ${screen.min})`,
13
+ screen.max && `(max-width: ${screen.max})`,
14
+ ]
15
+ .filter(Boolean)
16
+ .join(' and ')
17
+ })
18
+ )
23
19
  .join(', ')
24
20
  }