From 87da0a1266646a6b88808b0d37bebbebdb32670b Mon Sep 17 00:00:00 2001
From: Robin Malfait
Date: Fri, 24 Sep 2021 16:55:24 +0200
Subject: [PATCH 1/9] simplify `inset` plugin
---
src/corePlugins.js | 42 +++++++++++++-----------------------------
1 file changed, 13 insertions(+), 29 deletions(-)
diff --git a/src/corePlugins.js b/src/corePlugins.js
index e801e4624e68..930b5433bb2e 100644
--- a/src/corePlugins.js
+++ b/src/corePlugins.js
@@ -520,35 +520,19 @@ export let position = ({ addUtilities }) => {
})
}
-export let inset = ({ matchUtilities, theme }) => {
- let options = {
- values: theme('inset'),
- type: 'any',
- }
-
- matchUtilities(
- { inset: (value) => ({ top: value, right: value, bottom: value, left: value }) },
- options
- )
-
- matchUtilities(
- {
- 'inset-x': (value) => ({ left: value, right: value }),
- 'inset-y': (value) => ({ top: value, bottom: value }),
- },
- options
- )
-
- matchUtilities(
- {
- top: (top) => ({ top }),
- right: (right) => ({ right }),
- bottom: (bottom) => ({ bottom }),
- left: (left) => ({ left }),
- },
- options
- )
-}
+export let inset = createUtilityPlugin('inset', [
+ ['inset', ['top', 'right', 'bottom', 'left']],
+ [
+ ['inset-x', ['left', 'right']],
+ ['inset-y', ['top', 'bottom']],
+ ],
+ [
+ ['top', ['top']],
+ ['right', ['right']],
+ ['bottom', ['bottom']],
+ ['left', ['left']],
+ ],
+])
export let isolation = ({ addUtilities }) => {
addUtilities({
From a45967d9ddf4c0207d48a9c8b1a9113641f61503 Mon Sep 17 00:00:00 2001
From: Robin Malfait
Date: Fri, 24 Sep 2021 16:56:49 +0200
Subject: [PATCH 2/9] run `prettier` on stub file
---
stubs/defaultConfig.stub.js | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/stubs/defaultConfig.stub.js b/stubs/defaultConfig.stub.js
index 3ce4b4e5504e..98f7fc9b699c 100644
--- a/stubs/defaultConfig.stub.js
+++ b/stubs/defaultConfig.stub.js
@@ -111,9 +111,9 @@ module.exports = {
bounce: 'bounce 1s infinite',
},
aspectRatio: {
- 'auto': 'auto',
- 'square': '1 / 1',
- 'video': '16 / 9',
+ auto: 'auto',
+ square: '1 / 1',
+ video: '16 / 9',
},
backdropBlur: (theme) => theme('blur'),
backdropBrightness: (theme) => theme('brightness'),
@@ -847,10 +847,10 @@ module.exports = {
max: 'max-content',
}),
willChange: {
- 'auto': 'auto',
- 'scroll': 'scroll-position',
- 'contents': 'contents',
- 'transform': 'transform',
+ auto: 'auto',
+ scroll: 'scroll-position',
+ contents: 'contents',
+ transform: 'transform',
},
zIndex: {
auto: 'auto',
From 640026ca215dc779601b74342f259383d330cfe9 Mon Sep 17 00:00:00 2001
From: Robin Malfait
Date: Fri, 24 Sep 2021 16:58:08 +0200
Subject: [PATCH 3/9] simplify `align` utility
---
src/corePlugins.js | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/src/corePlugins.js b/src/corePlugins.js
index 930b5433bb2e..e832367e0f1f 100644
--- a/src/corePlugins.js
+++ b/src/corePlugins.js
@@ -1518,14 +1518,7 @@ export let verticalAlign = ({ addUtilities, matchUtilities }) => {
'.align-super': { 'vertical-align': 'super' },
})
- matchUtilities(
- {
- align: (value) => ({
- 'vertical-align': value,
- }),
- },
- { values: {}, type: 'any' }
- )
+ matchUtilities({ align: (value) => ({ 'vertical-align': value }) })
}
export let fontFamily = createUtilityPlugin('fontFamily', [['font', ['fontFamily']]], {
From 5f45020036ea957e12c4f5e49dde036692f38157 Mon Sep 17 00:00:00 2001
From: Robin Malfait
Date: Fri, 24 Sep 2021 16:59:38 +0200
Subject: [PATCH 4/9] improve arbitrary support for outline
This will allow us to use `outline-[OUTLINE,OPTIONAL_OFFSET]`
Input:
```html
outline-[2px_solid_black]
```
Output:
```css
.outline-\[2px_solid_black\] {
outline: 2px solid black;
outline-offset: 0;
}
```
---
Input:
```html
outline-[2px_solid_black,2px]
```
Output:
```css
.outline-\[2px_solid_black\2c 2px\] {
outline: 2px solid black;
outline-offset: 2px;
}
```
---
src/corePlugins.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/corePlugins.js b/src/corePlugins.js
index e832367e0f1f..e82341f5df30 100644
--- a/src/corePlugins.js
+++ b/src/corePlugins.js
@@ -1776,6 +1776,7 @@ export let outline = ({ matchUtilities, theme }) => {
matchUtilities(
{
outline: (value) => {
+ value = Array.isArray(value) ? value : value.split(',')
let [outline, outlineOffset = '0'] = Array.isArray(value) ? value : [value]
return { outline, 'outline-offset': outlineOffset }
From 0ca42fe1ddace8828f7187ae45e4a6b5c33c4dff Mon Sep 17 00:00:00 2001
From: Robin Malfait
Date: Fri, 24 Sep 2021 17:00:55 +0200
Subject: [PATCH 5/9] remove default `type`
---
src/corePlugins.js | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/src/corePlugins.js b/src/corePlugins.js
index e82341f5df30..aea8c0c8bd32 100644
--- a/src/corePlugins.js
+++ b/src/corePlugins.js
@@ -976,7 +976,7 @@ export let space = ({ matchUtilities, addUtilities, theme }) => {
}
},
},
- { values: theme('space'), type: 'any' }
+ { values: theme('space') }
)
addUtilities({
@@ -1073,7 +1073,7 @@ export let divideOpacity = ({ matchUtilities, theme }) => {
return { [`& > :not([hidden]) ~ :not([hidden])`]: { '--tw-divide-opacity': value } }
},
},
- { values: theme('divideOpacity'), type: 'any' }
+ { values: theme('divideOpacity') }
)
}
@@ -1668,7 +1668,7 @@ export let placeholderOpacity = ({ matchUtilities, theme }) => {
return { ['&::placeholder']: { '--tw-placeholder-opacity': value } }
},
},
- { values: theme('placeholderOpacity'), type: 'any' }
+ { values: theme('placeholderOpacity') }
)
}
@@ -1782,7 +1782,7 @@ export let outline = ({ matchUtilities, theme }) => {
return { outline, 'outline-offset': outlineOffset }
},
},
- { values: theme('outline'), type: 'any' }
+ { values: theme('outline') }
)
}
@@ -1886,7 +1886,7 @@ export let blur = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('blur'), type: 'any' }
+ { values: theme('blur') }
)
}
@@ -1901,7 +1901,7 @@ export let brightness = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('brightness'), type: 'any' }
+ { values: theme('brightness') }
)
}
@@ -1916,7 +1916,7 @@ export let contrast = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('contrast'), type: 'any' }
+ { values: theme('contrast') }
)
}
@@ -1948,7 +1948,7 @@ export let grayscale = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('grayscale'), type: 'any' }
+ { values: theme('grayscale') }
)
}
@@ -1963,7 +1963,7 @@ export let hueRotate = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('hueRotate'), type: 'any' }
+ { values: theme('hueRotate') }
)
}
@@ -1978,7 +1978,7 @@ export let invert = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('invert'), type: 'any' }
+ { values: theme('invert') }
)
}
@@ -1993,7 +1993,7 @@ export let saturate = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('saturate'), type: 'any' }
+ { values: theme('saturate') }
)
}
@@ -2008,7 +2008,7 @@ export let sepia = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('sepia'), type: 'any' }
+ { values: theme('sepia') }
)
}
@@ -2054,7 +2054,7 @@ export let backdropBlur = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('backdropBlur'), type: 'any' }
+ { values: theme('backdropBlur') }
)
}
@@ -2069,7 +2069,7 @@ export let backdropBrightness = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('backdropBrightness'), type: 'any' }
+ { values: theme('backdropBrightness') }
)
}
@@ -2084,7 +2084,7 @@ export let backdropContrast = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('backdropContrast'), type: 'any' }
+ { values: theme('backdropContrast') }
)
}
@@ -2099,7 +2099,7 @@ export let backdropGrayscale = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('backdropGrayscale'), type: 'any' }
+ { values: theme('backdropGrayscale') }
)
}
@@ -2114,7 +2114,7 @@ export let backdropHueRotate = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('backdropHueRotate'), type: 'any' }
+ { values: theme('backdropHueRotate') }
)
}
@@ -2129,7 +2129,7 @@ export let backdropInvert = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('backdropInvert'), type: 'any' }
+ { values: theme('backdropInvert') }
)
}
@@ -2144,7 +2144,7 @@ export let backdropOpacity = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('backdropOpacity'), type: 'any' }
+ { values: theme('backdropOpacity') }
)
}
@@ -2159,7 +2159,7 @@ export let backdropSaturate = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('backdropSaturate'), type: 'any' }
+ { values: theme('backdropSaturate') }
)
}
@@ -2174,7 +2174,7 @@ export let backdropSepia = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('backdropSepia'), type: 'any' }
+ { values: theme('backdropSepia') }
)
}
@@ -2230,7 +2230,7 @@ export let transitionProperty = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('transitionProperty'), type: 'any' }
+ { values: theme('transitionProperty') }
)
}
From 05e4099e2dfbf395669b9cf12b86966b255838e4 Mon Sep 17 00:00:00 2001
From: Robin Malfait
Date: Fri, 24 Sep 2021 17:02:44 +0200
Subject: [PATCH 6/9] simplify createUtilityPlugin, use types directly
---
src/util/createUtilityPlugin.js | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/src/util/createUtilityPlugin.js b/src/util/createUtilityPlugin.js
index 4a9dadc5c790..1760a05cdce7 100644
--- a/src/util/createUtilityPlugin.js
+++ b/src/util/createUtilityPlugin.js
@@ -1,19 +1,9 @@
import transformThemeValue from './transformThemeValue'
-import { asValue, asColor, asAngle, asLength, asURL, asLookupValue } from '../util/pluginUtils'
-
-let asMap = new Map([
- [asValue, 'any'],
- [asColor, 'color'],
- [asAngle, 'angle'],
- [asLength, 'length'],
- [asURL, 'url'],
- [asLookupValue, 'lookup'],
-])
export default function createUtilityPlugin(
themeKey,
utilityVariations = [[themeKey, [themeKey]]],
- { filterDefault = false, resolveArbitraryValue = asValue } = {}
+ { filterDefault = false, type = 'any' } = {}
) {
let transformValue = transformThemeValue(themeKey)
return function ({ matchUtilities, theme }) {
@@ -39,9 +29,7 @@ export default function createUtilityPlugin(
Object.entries(theme(themeKey) ?? {}).filter(([modifier]) => modifier !== 'DEFAULT')
)
: theme(themeKey),
- type: Array.isArray(resolveArbitraryValue)
- ? resolveArbitraryValue.map((typeResolver) => asMap.get(typeResolver) ?? 'any')
- : asMap.get(resolveArbitraryValue) ?? 'any',
+ type,
}
)
}
From 355371f0cb8c3665b7e346784667e807f82b8406 Mon Sep 17 00:00:00 2001
From: Robin Malfait
Date: Fri, 24 Sep 2021 17:13:27 +0200
Subject: [PATCH 7/9] find first matching type when coercing the value
---
src/util/pluginUtils.js | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/util/pluginUtils.js b/src/util/pluginUtils.js
index ddd499002445..6dc02bb5cde2 100644
--- a/src/util/pluginUtils.js
+++ b/src/util/pluginUtils.js
@@ -292,9 +292,7 @@ function splitAtFirst(input, delim) {
return [input.slice(0, idx), input.slice(idx + 1)]
}
-export function coerceValue(type, modifier, values, tailwindConfig) {
- let [scaleType, arbitraryType = scaleType] = [].concat(type)
-
+export function coerceValue(types, modifier, values, tailwindConfig) {
if (isArbitraryValue(modifier)) {
let [explicitType, value] = splitAtFirst(modifier.slice(1, -1), ':')
@@ -305,9 +303,13 @@ export function coerceValue(type, modifier, values, tailwindConfig) {
if (value.length > 0 && supportedTypes.includes(explicitType)) {
return [asValue(`[${value}]`, values, tailwindConfig), explicitType]
}
+ }
- return [typeMap[arbitraryType](modifier, values, tailwindConfig), arbitraryType]
+ // Find first matching type
+ for (let type of [].concat(types)) {
+ let result = typeMap[type](modifier, values, tailwindConfig)
+ if (result) return [result, type]
}
- return [typeMap[scaleType](modifier, values, tailwindConfig), scaleType]
+ return []
}
From d07a3e9cd8852e4734ad4eec2aa5b9c123dfbd46 Mon Sep 17 00:00:00 2001
From: Robin Malfait
Date: Fri, 24 Sep 2021 17:14:17 +0200
Subject: [PATCH 8/9] introduce css data types
Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
These data types will be used to "guess" the type of an arbitrary value
if there is some ambiguity going on. For example:
```
bg-[#0088cc] -> This is a `color` -> `background-color`
bg-[url('...')] -> This is a `url` -> `background-image`
```
If you are using css variables, then there is no way of knowing which
type it is referring to, in that case you can be explicit:
```
bg-[color:var(--value)] -> This is a `color` -> `background-color`
bg-[url:var(--value)] -> This is a `url` -> `background-image`
```
When you explicitly pass a data type, then we bypass the type system and
assume you are right. This is nice in a way because now we don't have to
run all of the guessing type code. On the other hand, you can introduce
runtime issues that we are not able to detect:
```
:root {
--value: 12px;
}
/* Later... */
bg-[color:var(--value)] -> Assumes `color` -> *eventually* -> `background-color: 12px`
```
---
src/corePlugins.js | 30 ++---
src/lib/expandTailwindAtRules.js | 2 +
src/util/dataTypes.js | 216 +++++++++++++++++++++++++++++++
src/util/pluginUtils.js | 105 +++++----------
4 files changed, 268 insertions(+), 85 deletions(-)
create mode 100644 src/util/dataTypes.js
diff --git a/src/corePlugins.js b/src/corePlugins.js
index aea8c0c8bd32..e8dccc8b5e25 100644
--- a/src/corePlugins.js
+++ b/src/corePlugins.js
@@ -16,9 +16,6 @@ import {
transformAllSelectors,
transformAllClasses,
transformLastClasses,
- asLength,
- asURL,
- asLookupValue,
} from './util/pluginUtils'
import packageJson from '../package.json'
import log from './util/log'
@@ -617,12 +614,15 @@ export let display = ({ addUtilities }) => {
}
export let aspectRatio = createUtilityPlugin('aspectRatio', [['aspect', ['aspect-ratio']]])
+
export let height = createUtilityPlugin('height', [['h', ['height']]])
export let maxHeight = createUtilityPlugin('maxHeight', [['max-h', ['maxHeight']]])
export let minHeight = createUtilityPlugin('minHeight', [['min-h', ['minHeight']]])
+
export let width = createUtilityPlugin('width', [['w', ['width']]])
export let minWidth = createUtilityPlugin('minWidth', [['min-w', ['minWidth']]])
export let maxWidth = createUtilityPlugin('maxWidth', [['max-w', ['maxWidth']]])
+
export let flex = createUtilityPlugin('flex')
export let flexShrink = createUtilityPlugin('flexShrink', [['flex-shrink', ['flex-shrink']]])
export let flexGrow = createUtilityPlugin('flexGrow', [['flex-grow', ['flex-grow']]])
@@ -1013,7 +1013,7 @@ export let divideWidth = ({ matchUtilities, addUtilities, theme }) => {
}
},
},
- { values: theme('divideWidth'), type: 'length' }
+ { values: theme('divideWidth'), type: ['line-width', 'length'] }
)
addUtilities({
@@ -1199,7 +1199,7 @@ export let borderWidth = createUtilityPlugin(
['border-l', [['@defaults border-width', {}], 'border-left-width']],
],
],
- { resolveArbitraryValue: asLength }
+ { type: ['line-width', 'length'] }
)
export let borderStyle = ({ addUtilities }) => {
@@ -1249,7 +1249,7 @@ export let borderColor = ({ addBase, matchUtilities, theme, corePlugins }) => {
},
{
values: (({ DEFAULT: _, ...colors }) => colors)(flattenColorPalette(theme('borderColor'))),
- type: 'color',
+ type: ['color'],
}
)
@@ -1346,7 +1346,7 @@ export let backgroundOpacity = createUtilityPlugin('backgroundOpacity', [
export let backgroundImage = createUtilityPlugin(
'backgroundImage',
[['bg', ['background-image']]],
- { resolveArbitraryValue: [asLookupValue, asURL] }
+ { type: ['lookup', 'image', 'url'] }
)
export let gradientColorStops = (() => {
function transparentTo(value) {
@@ -1399,7 +1399,7 @@ export let boxDecorationBreak = ({ addUtilities }) => {
}
export let backgroundSize = createUtilityPlugin('backgroundSize', [['bg', ['background-size']]], {
- resolveArbitraryValue: asLookupValue,
+ type: ['lookup', 'length', 'percentage'],
})
export let backgroundAttachment = ({ addUtilities }) => {
@@ -1422,7 +1422,7 @@ export let backgroundClip = ({ addUtilities }) => {
export let backgroundPosition = createUtilityPlugin(
'backgroundPosition',
[['bg', ['background-position']]],
- { resolveArbitraryValue: asLookupValue }
+ { type: ['lookup', 'position'] }
)
export let backgroundRepeat = ({ addUtilities }) => {
@@ -1462,12 +1462,12 @@ export let stroke = ({ matchUtilities, theme }) => {
return { stroke: toColorValue(value) }
},
},
- { values: flattenColorPalette(theme('stroke')), type: 'color' }
+ { values: flattenColorPalette(theme('stroke')), type: ['color', 'url'] }
)
}
export let strokeWidth = createUtilityPlugin('strokeWidth', [['stroke', ['stroke-width']]], {
- resolveArbitraryValue: [asLength, asURL],
+ type: ['length', 'number', 'percentage'],
})
export let objectFit = ({ addUtilities }) => {
@@ -1522,7 +1522,7 @@ export let verticalAlign = ({ addUtilities, matchUtilities }) => {
}
export let fontFamily = createUtilityPlugin('fontFamily', [['font', ['fontFamily']]], {
- resolveArbitraryValue: asLookupValue,
+ type: ['lookup', 'generic-name', 'family-name'],
})
export let fontSize = ({ matchUtilities, theme }) => {
@@ -1541,12 +1541,12 @@ export let fontSize = ({ matchUtilities, theme }) => {
}
},
},
- { values: theme('fontSize'), type: 'length' }
+ { values: theme('fontSize'), type: ['absolute-size', 'relative-size', 'length', 'percentage'] }
)
}
export let fontWeight = createUtilityPlugin('fontWeight', [['font', ['fontWeight']]], {
- resolveArbitraryValue: asLookupValue,
+ type: ['lookup', 'number'],
})
export let textTransform = ({ addUtilities }) => {
@@ -1859,7 +1859,7 @@ export let ringOpacity = createUtilityPlugin(
export let ringOffsetWidth = createUtilityPlugin(
'ringOffsetWidth',
[['ring-offset', ['--tw-ring-offset-width']]],
- { resolveArbitraryValue: asLength }
+ { type: 'length' }
)
export let ringOffsetColor = ({ matchUtilities, theme }) => {
diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js
index 3ecdcb3bd46a..bdc8e68d4a92 100644
--- a/src/lib/expandTailwindAtRules.js
+++ b/src/lib/expandTailwindAtRules.js
@@ -7,6 +7,8 @@ let env = sharedState.env
let contentMatchCache = sharedState.contentMatchCache
const PATTERNS = [
+ /([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif]
+ /([^<>"'`\s]*\[\w*"[^"`\s]*"?\])/.source, // font-["some_font",sans-serif]
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
/([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
diff --git a/src/util/dataTypes.js b/src/util/dataTypes.js
new file mode 100644
index 000000000000..e1b616a14867
--- /dev/null
+++ b/src/util/dataTypes.js
@@ -0,0 +1,216 @@
+import { parseColor } from './color'
+
+// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
+
+let COMMA = /,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
+let UNDERSCORE = /_(?![^(]*\))/g // Underscore separator that is not located between brackets. E.g.: `rgba(255,_255,_255)_black` these don't count.
+
+// This is not a data type, but rather a function that can normalize the
+// correct values.
+export function normalize(value) {
+ // Convert `_` to ` `, except for escaped underscores `\_`
+ value = value
+ .replace(
+ /([^\\])_+/g,
+ (fullMatch, characterBefore) => characterBefore + ' '.repeat(fullMatch.length - 1)
+ )
+ .replace(/^_/g, ' ')
+ .replace(/\\_/g, '_')
+
+ // Remove leftover whitespace
+ value = value.trim()
+
+ // Keep raw strings if it starts with `url(`
+ if (value.startsWith('url(')) return value
+
+ // Add spaces around operators inside calc() that do not follow an operator
+ // or '('.
+ return value.replace(
+ /(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,
+ '$1 $2 '
+ )
+}
+
+export function url(value) {
+ return value.startsWith('url(')
+}
+
+export function number(value) {
+ return !isNaN(Number(value))
+}
+
+export function percentage(value) {
+ return /%$/g.test(value) || /^calc\(.+?%\)/g.test(value)
+}
+
+let lengthUnits = [
+ 'cm',
+ 'mm',
+ 'Q',
+ 'in',
+ 'pc',
+ 'pt',
+ 'px',
+ 'em',
+ 'ex',
+ 'ch',
+ 'rem',
+ 'lh',
+ 'vw',
+ 'vh',
+ 'vmin',
+ 'vmax',
+]
+let lengthUnitsPattern = `(?:${lengthUnits.join('|')})`
+export function length(value) {
+ return (
+ new RegExp(`${lengthUnitsPattern}$`).test(value) ||
+ new RegExp(`^calc\\(.+?${lengthUnitsPattern}`).test(value)
+ )
+}
+
+let lineWidths = new Set(['thin', 'medium', 'thick'])
+export function lineWidth(value) {
+ return lineWidths.has(value)
+}
+
+export function color(value) {
+ let colors = 0
+
+ let result = value.split(UNDERSCORE).every((part) => {
+ part = normalize(part)
+
+ if (part.startsWith('var(')) return true
+ if (parseColor(part) !== null) return colors++, true
+
+ return false
+ })
+
+ if (!result) return false
+ return colors > 0
+}
+
+export function image(value) {
+ let images = 0
+ let result = value.split(COMMA).every((part) => {
+ part = normalize(part)
+
+ if (part.startsWith('var(')) return true
+ if (
+ url(part) ||
+ gradient(part) ||
+ ['element(', 'image(', 'cross-fade(', 'image-set('].some((fn) => part.startsWith(fn))
+ ) {
+ images++
+ return true
+ }
+
+ return false
+ })
+
+ if (!result) return false
+ return images > 0
+}
+
+let gradientTypes = new Set([
+ 'linear-gradient',
+ 'radial-gradient',
+ 'repeating-linear-gradient',
+ 'repeating-radial-gradient',
+ 'conic-gradient',
+])
+export function gradient(value) {
+ value = normalize(value)
+
+ for (let type of gradientTypes) {
+ if (value.startsWith(`${type}(`)) {
+ return true
+ }
+ }
+ return false
+}
+
+let validPositions = new Set(['center', 'top', 'right', 'bottom', 'left'])
+export function position(value) {
+ let positions = 0
+ let result = value.split(UNDERSCORE).every((part) => {
+ part = normalize(part)
+
+ if (part.startsWith('var(')) return true
+ if (validPositions.has(part) || length(part) || percentage(part)) {
+ positions++
+ return true
+ }
+
+ return false
+ })
+
+ if (!result) return false
+ return positions > 0
+}
+
+export function familyName(value) {
+ let fonts = 0
+ let result = value.split(COMMA).every((part) => {
+ part = normalize(part)
+
+ if (part.startsWith('var(')) return true
+
+ // If it contains spaces, then it should be quoted
+ if (part.includes(' ')) {
+ if (!/(['"])([^"']+)\1/g.test(part)) {
+ return false
+ }
+ }
+
+ // If it starts with a number, it's invalid
+ if (/^\d/g.test(part)) {
+ return false
+ }
+
+ fonts++
+
+ return true
+ })
+
+ if (!result) return false
+ return fonts > 0
+}
+
+let genericNames = new Set([
+ 'serif',
+ 'sans-serif',
+ 'monospace',
+ 'cursive',
+ 'fantasy',
+ 'system-ui',
+ 'ui-serif',
+ 'ui-sans-serif',
+ 'ui-monospace',
+ 'ui-rounded',
+ 'math',
+ 'emoji',
+ 'fangsong',
+])
+export function genericName(value) {
+ return genericNames.has(value)
+}
+
+let absoluteSizes = new Set([
+ 'xx-small',
+ 'x-small',
+ 'small',
+ 'medium',
+ 'large',
+ 'x-large',
+ 'x-large',
+ 'xxx-large',
+])
+export function absoluteSize(value) {
+ return absoluteSizes.has(value)
+}
+
+let relativeSizes = new Set(['larger', 'smaller'])
+export function relativeSize(value) {
+ return relativeSizes.has(value)
+}
diff --git a/src/util/pluginUtils.js b/src/util/pluginUtils.js
index 6dc02bb5cde2..73c4170a9b36 100644
--- a/src/util/pluginUtils.js
+++ b/src/util/pluginUtils.js
@@ -2,7 +2,21 @@ import selectorParser from 'postcss-selector-parser'
import escapeCommas from './escapeCommas'
import { withAlphaValue } from './withAlphaVariable'
import isKeyframeRule from './isKeyframeRule'
-import { parseColor } from './color'
+import {
+ normalize,
+ length,
+ number,
+ percentage,
+ url,
+ color as validateColor,
+ genericName,
+ familyName,
+ image,
+ absoluteSize,
+ relativeSize,
+ position,
+ lineWidth,
+} from './dataTypes'
export function applyPseudoToMarker(selector, marker, state, join) {
let states = [state]
@@ -159,7 +173,7 @@ export function asValue(modifier, lookup = {}, { validate = () => true } = {}) {
return value
}
- if (modifier[0] !== '[' || modifier[modifier.length - 1] !== ']') {
+ if (!isArbitraryValue(modifier)) {
return undefined
}
@@ -169,32 +183,7 @@ export function asValue(modifier, lookup = {}, { validate = () => true } = {}) {
return undefined
}
- // convert `_` to ` `, escept for escaped underscores `\_`
- value = value
- .replace(/([^\\])_/g, '$1 ')
- .replace(/^_/g, ' ')
- .replace(/\\_/g, '_')
-
- // Keep raw strings if it starts with `url(`
- if (value.startsWith('url(')) return value
-
- // add spaces around operators inside calc() that do not follow an operator or (
- return value.replace(
- /(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,
- '$1 $2 '
- )
-}
-
-export function asUnit(modifier, units, lookup = {}) {
- return asValue(modifier, lookup, {
- validate: (value) => {
- let unitsPattern = `(?:${units.join('|')})`
- return (
- new RegExp(`${unitsPattern}$`).test(value) ||
- new RegExp(`^calc\\(.+?${unitsPattern}`).test(value)
- )
- },
- })
+ return normalize(value)
}
function isArbitraryValue(input) {
@@ -230,58 +219,34 @@ export function asColor(modifier, lookup = {}, tailwindConfig = {}) {
return withAlphaValue(lookup[color], tailwindConfig.theme.opacity[alpha])
}
- return asValue(modifier, lookup, {
- validate: (value) => parseColor(value) !== null,
- })
-}
-
-export function asAngle(modifier, lookup = {}) {
- return asUnit(modifier, ['deg', 'grad', 'rad', 'turn'], lookup)
-}
-
-export function asURL(modifier, lookup = {}) {
- return asValue(modifier, lookup, {
- validate: (value) => value.startsWith('url('),
- })
-}
-
-export function asLength(modifier, lookup = {}) {
- return asUnit(
- modifier,
- [
- 'cm',
- 'mm',
- 'Q',
- 'in',
- 'pc',
- 'pt',
- 'px',
- 'em',
- 'ex',
- 'ch',
- 'rem',
- 'lh',
- 'vw',
- 'vh',
- 'vmin',
- 'vmax',
- '%',
- ],
- lookup
- )
+ return asValue(modifier, lookup, { validate: validateColor })
}
export function asLookupValue(modifier, lookup = {}) {
return lookup[modifier]
}
+function guess(validate) {
+ return (modifier, lookup) => {
+ return asValue(modifier, lookup, { validate })
+ }
+}
+
let typeMap = {
any: asValue,
color: asColor,
- angle: asAngle,
- length: asLength,
- url: asURL,
+ url: guess(url),
+ image: guess(image),
+ length: guess(length),
+ percentage: guess(percentage),
+ position: guess(position),
lookup: asLookupValue,
+ 'generic-name': guess(genericName),
+ 'family-name': guess(familyName),
+ number: guess(number),
+ 'line-width': guess(lineWidth),
+ 'absolute-size': guess(absoluteSize),
+ 'relative-size': guess(relativeSize),
}
let supportedTypes = Object.keys(typeMap)
From d499c59305313622255c4ba00bb7d2aae40d987f Mon Sep 17 00:00:00 2001
From: Robin Malfait
Date: Fri, 24 Sep 2021 17:17:13 +0200
Subject: [PATCH 9/9] add a bunch of new tests for advanced arbitrary values
---
tests/arbitrary-values.test.css | 461 ++++++++++++++++++++++++++++++-
tests/arbitrary-values.test.html | 345 ++++++++++++++++++-----
tests/arbitrary-values.test.js | 63 +++++
3 files changed, 793 insertions(+), 76 deletions(-)
diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css
index 6d915765da01..7bb79dbb6fa2 100644
--- a/tests/arbitrary-values.test.css
+++ b/tests/arbitrary-values.test.css
@@ -4,6 +4,64 @@
bottom: 11px;
left: 11px;
}
+.inset-\[var\(--value\)\] {
+ top: var(--value);
+ right: var(--value);
+ bottom: var(--value);
+ left: var(--value);
+}
+.inset-x-\[11px\] {
+ left: 11px;
+ right: 11px;
+}
+.inset-x-\[var\(--value\)\] {
+ left: var(--value);
+ right: var(--value);
+}
+.inset-y-\[11px\] {
+ top: 11px;
+ bottom: 11px;
+}
+.inset-y-\[var\(--value\)\] {
+ top: var(--value);
+ bottom: var(--value);
+}
+.top-\[11px\] {
+ top: 11px;
+}
+.top-\[var\(--value\)\] {
+ top: var(--value);
+}
+.right-\[11px\] {
+ right: 11px;
+}
+.right-\[var\(--value\)\] {
+ right: var(--value);
+}
+.bottom-\[11px\] {
+ bottom: 11px;
+}
+.bottom-\[var\(--value\)\] {
+ bottom: var(--value);
+}
+.left-\[11px\] {
+ left: 11px;
+}
+.left-\[var\(--value\)\] {
+ left: var(--value);
+}
+.z-\[123\] {
+ z-index: 123;
+}
+.z-\[var\(--value\)\] {
+ z-index: var(--value);
+}
+.order-\[4\] {
+ order: 4;
+}
+.order-\[var\(--value\)\] {
+ order: var(--value);
+}
.col-\[7\] {
grid-column: 7;
}
@@ -157,6 +215,25 @@
.flex-grow-\[var\(--grow\)\] {
flex-grow: var(--grow);
}
+.origin-\[50px_50px\] {
+ transform-origin: 50px 50px;
+}
+.translate-x-\[12\%\] {
+ --tw-translate-x: 12%;
+ transform: var(--tw-transform);
+}
+.translate-x-\[var\(--value\)\] {
+ --tw-translate-x: var(--value);
+ transform: var(--tw-transform);
+}
+.translate-y-\[12\%\] {
+ --tw-translate-y: 12%;
+ transform: var(--tw-transform);
+}
+.translate-y-\[var\(--value\)\] {
+ --tw-translate-y: var(--value);
+ transform: var(--tw-transform);
+}
.rotate-\[23deg\] {
--tw-rotate: 23deg;
transform: var(--tw-transform);
@@ -177,16 +254,77 @@
--tw-skew-x: 3px;
transform: var(--tw-transform);
}
+.skew-x-\[var\(--value\)\] {
+ --tw-skew-x: var(--value);
+ transform: var(--tw-transform);
+}
.skew-y-\[3px\] {
--tw-skew-y: 3px;
transform: var(--tw-transform);
}
+.skew-y-\[var\(--value\)\] {
+ --tw-skew-y: var(--value);
+ transform: var(--tw-transform);
+}
+.scale-\[0\.7\] {
+ --tw-scale-x: 0.7;
+ --tw-scale-y: 0.7;
+ transform: var(--tw-transform);
+}
+.scale-\[var\(--value\)\] {
+ --tw-scale-x: var(--value);
+ --tw-scale-y: var(--value);
+ transform: var(--tw-transform);
+}
+.scale-x-\[0\.7\] {
+ --tw-scale-x: 0.7;
+ transform: var(--tw-transform);
+}
+.scale-x-\[var\(--value\)\] {
+ --tw-scale-x: var(--value);
+ transform: var(--tw-transform);
+}
+.scale-y-\[0\.7\] {
+ --tw-scale-y: 0.7;
+ transform: var(--tw-transform);
+}
+.scale-y-\[var\(--value\)\] {
+ --tw-scale-y: var(--value);
+ transform: var(--tw-transform);
+}
+.animate-\[pong_1s_cubic-bezier\(0\2c 0\2c 0\.2\2c 1\)_infinite\] {
+ animation: pong 1s cubic-bezier(0, 0, 0.2, 1) infinite;
+}
+.animate-\[var\(--value\)\] {
+ animation: var(--value);
+}
+.cursor-\[pointer\] {
+ cursor: pointer;
+}
+.cursor-\[url\(hand\.cur\)_2_2\2c pointer\] {
+ cursor: url(hand.cur) 2 2, pointer;
+}
+.cursor-\[var\(--value\)\] {
+ cursor: var(--value);
+}
+.list-\[\'\\1f44d\'\] {
+ list-style-type: '\1F44D';
+}
+.list-\[var\(--value\)\] {
+ list-style-type: var(--value);
+}
.columns-\[20\] {
columns: 20;
}
.columns-\[var\(--columns\)\] {
columns: var(--columns);
}
+.auto-cols-\[minmax\(10px\2c auto\)\] {
+ grid-auto-columns: minmax(10px, auto);
+}
+.auto-rows-\[minmax\(10px\2c auto\)\] {
+ grid-auto-rows: minmax(10px, auto);
+}
.grid-cols-\[200px\2c repeat\(auto-fill\2c minmax\(15\%\2c 100px\)\)\2c 300px\] {
grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px;
}
@@ -196,6 +334,24 @@
.grid-rows-\[200px\2c repeat\(auto-fill\2c minmax\(15\%\2c 100px\)\)\2c 300px\] {
grid-template-rows: 200px repeat(auto-fill, minmax(15%, 100px)) 300px;
}
+.gap-\[20px\] {
+ gap: 20px;
+}
+.gap-\[var\(--value\)\] {
+ gap: var(--value);
+}
+.gap-x-\[20px\] {
+ column-gap: 20px;
+}
+.gap-x-\[var\(--value\)\] {
+ column-gap: var(--value);
+}
+.gap-y-\[20px\] {
+ row-gap: 20px;
+}
+.gap-y-\[var\(--value\)\] {
+ row-gap: var(--value);
+}
.space-x-\[20cm\] > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(20cm * var(--tw-space-x-reverse));
@@ -206,6 +362,46 @@
margin-right: calc(calc(20% - 1cm) * var(--tw-space-x-reverse));
margin-left: calc(calc(20% - 1cm) * calc(1 - var(--tw-space-x-reverse)));
}
+.space-y-\[20cm\] > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(20cm * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(20cm * var(--tw-space-y-reverse));
+}
+.space-y-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(calc(20% - 1cm) * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(calc(20% - 1cm) * var(--tw-space-y-reverse));
+}
+.divide-x-\[20cm\] > :not([hidden]) ~ :not([hidden]) {
+ --tw-divide-x-reverse: 0;
+ border-right-width: calc(20cm * var(--tw-divide-x-reverse));
+ border-left-width: calc(20cm * calc(1 - var(--tw-divide-x-reverse)));
+}
+.divide-x-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) {
+ --tw-divide-x-reverse: 0;
+ border-right-width: calc(calc(20% - 1cm) * var(--tw-divide-x-reverse));
+ border-left-width: calc(calc(20% - 1cm) * calc(1 - var(--tw-divide-x-reverse)));
+}
+.divide-y-\[20cm\] > :not([hidden]) ~ :not([hidden]) {
+ --tw-divide-y-reverse: 0;
+ border-top-width: calc(20cm * calc(1 - var(--tw-divide-y-reverse)));
+ border-bottom-width: calc(20cm * var(--tw-divide-y-reverse));
+}
+.divide-y-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) {
+ --tw-divide-y-reverse: 0;
+ border-top-width: calc(calc(20% - 1cm) * calc(1 - var(--tw-divide-y-reverse)));
+ border-bottom-width: calc(calc(20% - 1cm) * var(--tw-divide-y-reverse));
+}
+.divide-\[black\] > :not([hidden]) ~ :not([hidden]) {
+ --tw-divide-opacity: 1;
+ border-color: rgb(0 0 0 / var(--tw-divide-opacity));
+}
+.divide-opacity-\[0\.8\] > :not([hidden]) ~ :not([hidden]) {
+ --tw-divide-opacity: 0.8;
+}
+.divide-opacity-\[var\(--value\)\] > :not([hidden]) ~ :not([hidden]) {
+ --tw-divide-opacity: var(--value);
+}
.rounded-\[11px\] {
border-radius: 11px;
}
@@ -240,10 +436,77 @@
.border-\[2\.5px\] {
border-width: 2.5px;
}
+.border-\[length\:var\(--value\)\] {
+ border-width: var(--value);
+}
+.border-t-\[2\.5px\] {
+ border-top-width: 2.5px;
+}
+.border-t-\[length\:var\(--value\)\] {
+ border-top-width: var(--value);
+}
+.border-r-\[2\.5px\] {
+ border-right-width: 2.5px;
+}
+.border-r-\[length\:var\(--value\)\] {
+ border-right-width: var(--value);
+}
+.border-b-\[2\.5px\] {
+ border-bottom-width: 2.5px;
+}
+.border-b-\[length\:var\(--value\)\] {
+ border-bottom-width: var(--value);
+}
+.border-l-\[2\.5px\] {
+ border-left-width: 2.5px;
+}
+.border-l-\[length\:var\(--value\)\] {
+ border-left-width: var(--value);
+}
.border-\[\#f00\] {
--tw-border-opacity: 1;
border-color: rgb(255 0 0 / var(--tw-border-opacity));
}
+.border-\[red_black\] {
+ border-color: red black;
+}
+.border-\[color\:var\(--value\)\] {
+ border-color: var(--value);
+}
+.border-t-\[\#f00\] {
+ --tw-border-opacity: 1;
+ border-top-color: rgb(255 0 0 / var(--tw-border-opacity));
+}
+.border-t-\[color\:var\(--value\)\] {
+ border-top-color: var(--value);
+}
+.border-r-\[\#f00\] {
+ --tw-border-opacity: 1;
+ border-right-color: rgb(255 0 0 / var(--tw-border-opacity));
+}
+.border-r-\[color\:var\(--value\)\] {
+ border-right-color: var(--value);
+}
+.border-b-\[\#f00\] {
+ --tw-border-opacity: 1;
+ border-bottom-color: rgb(255 0 0 / var(--tw-border-opacity));
+}
+.border-b-\[color\:var\(--value\)\] {
+ border-bottom-color: var(--value);
+}
+.border-l-\[\#f00\] {
+ --tw-border-opacity: 1;
+ border-left-color: rgb(255 0 0 / var(--tw-border-opacity));
+}
+.border-l-\[color\:var\(--value\)\] {
+ border-left-color: var(--value);
+}
+.border-opacity-\[0\.8\] {
+ --tw-border-opacity: 0.8;
+}
+.border-opacity-\[var\(--value\)\] {
+ --tw-border-opacity: var(--value);
+}
.bg-\[\#0f0\] {
--tw-bg-opacity: 1;
background-color: rgb(0 255 0 / var(--tw-bg-opacity));
@@ -262,6 +525,13 @@
.bg-\[rgba\(123\2c 123\2c 123\2c 0\.5\)\] {
background-color: rgba(123, 123, 123, 0.5);
}
+.bg-\[rgb\(123\2c _456\2c _123\)_black\] {
+ background-color: rgb(123, 456, 123) black;
+}
+.bg-\[rgb\(123_456_789\)\] {
+ --tw-bg-opacity: 1;
+ background-color: rgb(123 456 789 / var(--tw-bg-opacity));
+}
.bg-\[hsl\(0\2c 100\%\2c 50\%\)\] {
--tw-bg-opacity: 1;
background-color: hsl(0 100% 50% / var(--tw-bg-opacity));
@@ -269,6 +539,12 @@
.bg-\[hsla\(0\2c 100\%\2c 50\%\2c 0\.3\)\] {
background-color: hsla(0, 100%, 50%, 0.3);
}
+.bg-\[\#0f0_var\(--value\)\] {
+ background-color: #0f0 var(--value);
+}
+.bg-\[color\:var\(--value1\)_var\(--value2\)\] {
+ background-color: var(--value1) var(--value2);
+}
.bg-opacity-\[0\.11\] {
--tw-bg-opacity: 0.11;
}
@@ -281,6 +557,24 @@
.bg-\[url\:var\(--url\)\] {
background-image: var(--url);
}
+.bg-\[linear-gradient\(\#eee\2c \#fff\)\] {
+ background-image: linear-gradient(#eee, #fff);
+}
+.bg-\[linear-gradient\(\#eee\2c
+ \#fff\)\2c
+ conic-gradient\(red\2c
+ orange\2c
+ yellow\2c
+ green\2c
+ blue\)\] {
+ background-image: linear-gradient(#eee, #fff), conic-gradient(red, orange, yellow, green, blue);
+}
+.bg-\[image\(\)\2c var\(--value\)\] {
+ background-image: image(), var(--value);
+}
+.bg-\[image\:var\(--value\)\2c var\(--value\)\] {
+ background-image: var(--value), var(--value);
+}
.from-\[\#da5b66\] {
--tw-gradient-from: #da5b66;
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgb(218 91 102 / 0));
@@ -302,17 +596,41 @@
.to-\[var\(--color\)\] {
--tw-gradient-to: var(--color);
}
+.bg-\[length\:200px_100px\] {
+ background-size: 200px 100px;
+}
+.bg-\[length\:var\(--value\)\] {
+ background-size: var(--value);
+}
+.bg-\[position\:200px_100px\] {
+ background-position: 200px 100px;
+}
+.bg-\[position\:var\(--value\)\] {
+ background-position: var(--value);
+}
.fill-\[\#da5b66\] {
fill: #da5b66;
}
-.fill-\[var\(--color\)\] {
- fill: var(--color);
+.fill-\[var\(--value\)\] {
+ fill: var(--value);
+}
+.fill-\[url\(\#icon-gradient\)\] {
+ fill: url(#icon-gradient);
}
.stroke-\[\#da5b66\] {
stroke: #da5b66;
}
+.stroke-\[color\:var\(--value\)\] {
+ stroke: var(--value);
+}
.stroke-\[url\(\#icon-gradient\)\] {
- stroke-width: url(#icon-gradient);
+ stroke: url(#icon-gradient);
+}
+.stroke-\[20px\] {
+ stroke-width: 20px;
+}
+.stroke-\[length\:var\(--value\)\] {
+ stroke-width: var(--value);
}
.object-\[50\%\2c 50\%\] {
object-position: 50% 50%;
@@ -323,8 +641,31 @@
.object-\[var\(--position\)\] {
object-position: var(--position);
}
-.p-\[var\(--app-padding\)\] {
- padding: var(--app-padding);
+.p-\[7px\] {
+ padding: 7px;
+}
+.px-\[7px\] {
+ padding-left: 7px;
+ padding-right: 7px;
+}
+.py-\[7px\] {
+ padding-top: 7px;
+ padding-bottom: 7px;
+}
+.pt-\[7px\] {
+ padding-top: 7px;
+}
+.pr-\[7px\] {
+ padding-right: 7px;
+}
+.pb-\[7px\] {
+ padding-bottom: 7px;
+}
+.pl-\[7px\] {
+ padding-left: 7px;
+}
+.pt-\[clamp\(30px\2c 100px\)\] {
+ padding-top: clamp(30px, 100px);
}
.indent-\[50\%\] {
text-indent: 50%;
@@ -335,40 +676,130 @@
.align-\[10em\] {
vertical-align: 10em;
}
+.font-\[Georgia\2c serif\] {
+ font-family: Georgia, serif;
+}
+.font-\[\'Gill_Sans\'\] {
+ font-family: 'Gill Sans';
+}
+.font-\[sans-serif\2c serif\] {
+ font-family: sans-serif, serif;
+}
+.font-\[family-name\:var\(--value\)\] {
+ font-family: var(--value);
+}
+.font-\[serif\2c var\(--value\)\] {
+ font-family: serif, var(--value);
+}
+.font-\[\'Some_Font\'\2c sans-serif\] {
+ font-family: 'Some Font', sans-serif;
+}
+.font-\[\'Some_Font\'\2c \'Some_Other_Font\'\] {
+ font-family: 'Some Font', 'Some Other Font';
+}
+.font-\[\'Some_Font\'\2c var\(--other-font\)\] {
+ font-family: 'Some Font', var(--other-font);
+}
.text-\[2\.23rem\] {
font-size: 2.23rem;
}
.text-\[length\:var\(--font-size\)\] {
font-size: var(--font-size);
}
+.font-\[300\] {
+ font-weight: 300;
+}
+.font-\[number\:lighter\] {
+ font-weight: lighter;
+}
+.font-\[number\:var\(--value\)\] {
+ font-weight: var(--value);
+}
.leading-\[var\(--leading\)\] {
line-height: var(--leading);
}
.tracking-\[var\(--tracking\)\] {
letter-spacing: var(--tracking);
}
+.text-\[black\] {
+ --tw-text-opacity: 1;
+ color: rgb(0 0 0 / var(--tw-text-opacity));
+}
+.text-\[rgb\(123\2c 123\2c 123\)\] {
+ --tw-text-opacity: 1;
+ color: rgb(123 123 123 / var(--tw-text-opacity));
+}
+.text-\[rgb\(123\2c _123\2c _123\)\] {
+ --tw-text-opacity: 1;
+ color: rgb(123 123 123 / var(--tw-text-opacity));
+}
+.text-\[rgb\(123_123_123\)\] {
+ --tw-text-opacity: 1;
+ color: rgb(123 123 123 / var(--tw-text-opacity));
+}
.text-\[color\:var\(--color\)\] {
color: var(--color);
}
+.text-opacity-\[0\.8\] {
+ --tw-text-opacity: 0.8;
+}
+.text-opacity-\[var\(--value\)\] {
+ --tw-text-opacity: var(--value);
+}
.placeholder-\[var\(--placeholder\)\]::placeholder {
color: var(--placeholder);
}
.placeholder-opacity-\[var\(--placeholder-opacity\)\]::placeholder {
--tw-placeholder-opacity: var(--placeholder-opacity);
}
+.caret-\[black\] {
+ caret-color: black;
+}
+.caret-\[var\(--value\)\] {
+ caret-color: var(--value);
+}
.accent-\[\#bada55\] {
accent-color: #bada55;
}
.accent-\[var\(--accent-color\)\] {
accent-color: var(--accent-color);
}
+.opacity-\[0\.8\] {
+ opacity: 0.8;
+}
.opacity-\[var\(--opacity\)\] {
opacity: var(--opacity);
}
+.shadow-\[0px_1px_2px_black\] {
+ --tw-shadow: 0px 1px 2px black;
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
+ var(--tw-shadow);
+}
+.shadow-\[var\(--value\)\] {
+ --tw-shadow: var(--value);
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
+ var(--tw-shadow);
+}
+.outline-\[2px_solid_black\] {
+ outline: 2px solid black;
+ outline-offset: 0;
+}
+.outline-\[2px_solid_black\2c 2px\] {
+ outline: 2px solid black;
+ outline-offset: 2px;
+}
.outline-\[var\(--outline\)\] {
outline: var(--outline);
outline-offset: 0;
}
+.outline-\[var\(--outline\)\2c 3px\] {
+ outline: var(--outline);
+ outline-offset: 3px;
+}
+.outline-\[2px_solid_black\2c var\(--outline-offset\)\] {
+ outline: 2px solid black;
+ outline-offset: var(--outline-offset);
+}
.ring-\[10px\] {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
var(--tw-ring-offset-color);
@@ -376,22 +807,38 @@
var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
+.ring-\[length\:\(var\(--value\)\)\] {
+ --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
+ var(--tw-ring-offset-color);
+ --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc((var(--value)) + var(--tw-ring-offset-width))
+ var(--tw-ring-color);
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
+}
.ring-\[\#76ad65\] {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(118 173 101 / var(--tw-ring-opacity));
}
+.ring-\[color\:var\(--value\)\] {
+ --tw-ring-color: var(--value);
+}
.ring-opacity-\[var\(--ring-opacity\)\] {
--tw-ring-opacity: var(--ring-opacity);
}
.ring-offset-\[19rem\] {
--tw-ring-offset-width: 19rem;
}
+.ring-offset-\[length\:var\(--value\)\] {
+ --tw-ring-offset-width: var(--value);
+}
.ring-offset-\[\#76ad65\] {
--tw-ring-offset-color: #76ad65;
}
.ring-offset-\[\#ad672f\] {
--tw-ring-offset-color: #ad672f;
}
+.ring-offset-\[color\:var\(--value\)\] {
+ --tw-ring-offset-color: var(--value);
+}
.blur-\[15px\] {
--tw-blur: blur(15px);
filter: var(--tw-filter);
@@ -404,6 +851,10 @@
--tw-contrast: contrast(2.4);
filter: var(--tw-filter);
}
+.drop-shadow-\[0px_1px_2px_black\] {
+ --tw-drop-shadow: drop-shadow(0px 1px 2px black);
+ filter: var(--tw-filter);
+}
.grayscale-\[0\.55\] {
--tw-grayscale: grayscale(0.55);
filter: var(--tw-filter);
diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html
index bab407ed8649..651aa68c856c 100644
--- a/tests/arbitrary-values.test.html
+++ b/tests/arbitrary-values.test.html
@@ -8,70 +8,142 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
diff --git a/tests/arbitrary-values.test.js b/tests/arbitrary-values.test.js
index 17252be92ef9..f264faa0c9e4 100644
--- a/tests/arbitrary-values.test.js
+++ b/tests/arbitrary-values.test.js
@@ -16,6 +16,58 @@ test('arbitrary values', () => {
})
})
+it('should support arbitrary values for various background utilities', () => {
+ let config = {
+ content: [
+ {
+ raw: html`
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ },
+ ],
+ }
+
+ return run('@tailwind utilities', config).then((result) => {
+ return expect(result.css).toMatchFormattedCss(css`
+ .bg-red-500 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(239 68 68 / var(--tw-bg-opacity));
+ }
+
+ .bg-\\[\\#ff0000\\] {
+ --tw-bg-opacity: 1;
+ background-color: rgb(255 0 0 / var(--tw-bg-opacity));
+ }
+
+ .bg-\\[color\\:var\\(--bg-color\\)\\] {
+ background-color: var(--bg-color);
+ }
+
+ .bg-gradient-to-r {
+ background-image: linear-gradient(to right, var(--tw-gradient-stops));
+ }
+
+ .bg-\\[url\\(\\'\\/image-1-0\\.png\\'\\)\\] {
+ background-image: url('/image-1-0.png');
+ }
+
+ .bg-\\[url\\:var\\(--image-url\\)\\] {
+ background-image: var(--image-url);
+ }
+ `)
+ })
+})
+
it('should not generate any css if an unknown typehint is used', () => {
let config = {
content: [
@@ -59,6 +111,8 @@ it('should convert _ to spaces', () => {
+
+
`,
},
],
@@ -113,9 +167,18 @@ it('should convert _ to spaces', () => {
--tw-drop-shadow: drop-shadow(0px 1px 3px black);
filter: var(--tw-filter);
}
+
.content-\\[_hello_world_\\] {
content: hello world;
}
+
+ .content-\\[___abc____\\] {
+ content: abc;
+ }
+
+ .content-\\[\\'__hello__world__\\'\\] {
+ content: ' hello world ';
+ }
`)
})
})