Skip to content

Commit abcd9ac

Browse files
authored
Support URL in arbitrary values (#5587)
* add url to resolveArbitraryValue list * add `asURL` data type * add `bg-[url('..')]` regex * allow for `resolveArbitraryValue` to be an array * prevent spaces around `-` when in a `url` * add tests to verify `bg-[url('...')]` and `stroke-[url(...)]`
1 parent a4d1bdb commit abcd9ac

File tree

6 files changed

+31
-4
lines changed

6 files changed

+31
-4
lines changed

src/corePlugins.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
transformAllClasses,
1818
transformLastClasses,
1919
asLength,
20+
asURL,
2021
asLookupValue,
2122
} from './util/pluginUtils'
2223
import packageJson from '../package.json'
@@ -1361,7 +1362,7 @@ export let backgroundOpacity = createUtilityPlugin('backgroundOpacity', [
13611362
export let backgroundImage = createUtilityPlugin(
13621363
'backgroundImage',
13631364
[['bg', ['background-image']]],
1364-
{ resolveArbitraryValue: asLookupValue }
1365+
{ resolveArbitraryValue: [asLookupValue, asURL] }
13651366
)
13661367
export let gradientColorStops = (() => {
13671368
function transparentTo(value) {
@@ -1482,7 +1483,7 @@ export let stroke = ({ matchUtilities, theme }) => {
14821483
}
14831484

14841485
export let strokeWidth = createUtilityPlugin('strokeWidth', [['stroke', ['stroke-width']]], {
1485-
resolveArbitraryValue: asLength,
1486+
resolveArbitraryValue: [asLength, asURL],
14861487
})
14871488

14881489
export let objectFit = ({ addUtilities }) => {

src/lib/expandTailwindAtRules.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ let env = sharedState.env
77
let contentMatchCache = sharedState.contentMatchCache
88

99
const PATTERNS = [
10+
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
11+
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
1012
/([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
1113
/([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
1214
/([^<>"'`\s]*\[[^"'`\s]+\])/.source, // `fill-[#bada55]`

src/util/createUtilityPlugin.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import transformThemeValue from './transformThemeValue'
2-
import { asValue, asColor, asAngle, asLength, asLookupValue } from '../util/pluginUtils'
2+
import { asValue, asColor, asAngle, asLength, asURL, asLookupValue } from '../util/pluginUtils'
33

44
let asMap = new Map([
55
[asValue, 'any'],
66
[asColor, 'color'],
77
[asAngle, 'angle'],
88
[asLength, 'length'],
9+
[asURL, 'url'],
910
[asLookupValue, 'lookup'],
1011
])
1112

@@ -38,7 +39,9 @@ export default function createUtilityPlugin(
3839
Object.entries(theme(themeKey) ?? {}).filter(([modifier]) => modifier !== 'DEFAULT')
3940
)
4041
: theme(themeKey),
41-
type: asMap.get(resolveArbitraryValue) ?? 'any',
42+
type: Array.isArray(resolveArbitraryValue)
43+
? resolveArbitraryValue.map((typeResolver) => asMap.get(typeResolver) ?? 'any')
44+
: asMap.get(resolveArbitraryValue) ?? 'any',
4245
}
4346
)
4447
}

src/util/pluginUtils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ export function asValue(modifier, lookup = {}, { validate = () => true } = {}) {
175175
.replace(/^_/g, ' ')
176176
.replace(/\\_/g, '_')
177177

178+
// Keep raw strings if it starts with `url(`
179+
if (value.startsWith('url(')) return value
180+
178181
// add spaces around operators inside calc() that do not follow an operator or (
179182
return value.replace(
180183
/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,
@@ -236,6 +239,12 @@ export function asAngle(modifier, lookup = {}) {
236239
return asUnit(modifier, ['deg', 'grad', 'rad', 'turn'], lookup)
237240
}
238241

242+
export function asURL(modifier, lookup = {}) {
243+
return asValue(modifier, lookup, {
244+
validate: (value) => value.startsWith('url('),
245+
})
246+
}
247+
239248
export function asLength(modifier, lookup = {}) {
240249
return asUnit(
241250
modifier,
@@ -271,6 +280,7 @@ let typeMap = {
271280
color: asColor,
272281
angle: asAngle,
273282
length: asLength,
283+
url: asURL,
274284
lookup: asLookupValue,
275285
}
276286

tests/arbitrary-values.test.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,12 @@
275275
.bg-opacity-\[var\(--value\)\] {
276276
--tw-bg-opacity: var(--value);
277277
}
278+
.bg-\[url\(\'\/path-to-image\.png\'\)\] {
279+
background-image: url('/path-to-image.png');
280+
}
281+
.bg-\[url\:var\(--url\)\] {
282+
background-image: var(--url);
283+
}
278284
.from-\[\#da5b66\] {
279285
--tw-gradient-from: #da5b66;
280286
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgb(218 91 102 / 0));
@@ -305,6 +311,9 @@
305311
.stroke-\[\#da5b66\] {
306312
stroke: #da5b66;
307313
}
314+
.stroke-\[url\(\#icon-gradient\)\] {
315+
stroke-width: url(#icon-gradient);
316+
}
308317
.object-\[50\%\2c 50\%\] {
309318
object-position: 50% 50%;
310319
}

tests/arbitrary-values.test.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<div class="bg-[#0f0] bg-[#ff0000] bg-[#0000ffcc]"></div>
1212
<div class="bg-[rgb(123,123,123)] bg-[rgba(123,123,123,0.5)]"></div>
1313
<div class="bg-[hsl(0,100%,50%)] bg-[hsla(0,100%,50%,0.3)]"></div>
14+
<div class="bg-[url('/path-to-image.png')] bg-[url:var(--url)]"></div>
1415
<div class="bg-opacity-[0.11]"></div>
1516
<div class="bg-opacity-[var(--value)]"></div>
1617
<div class="border-[#f00]"></div>
@@ -116,6 +117,7 @@
116117
<div class="object-[top,right]"></div>
117118
<div class="object-[var(--position)]"></div>
118119
<div class="stroke-[#da5b66]"></div>
120+
<div class="stroke-[url(#icon-gradient)]"></div>
119121
<div class="leading-[var(--leading)]"></div>
120122
<div class="tracking-[var(--tracking)]"></div>
121123
<div class="placeholder-[var(--placeholder)]"></div>

0 commit comments

Comments
 (0)