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(...)]`
This commit is contained in:
Robin Malfait 2021-09-24 16:13:16 +02:00 committed by GitHub
parent a4d1bdb7fa
commit abcd9acd18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 31 additions and 4 deletions

View File

@ -17,6 +17,7 @@ import {
transformAllClasses,
transformLastClasses,
asLength,
asURL,
asLookupValue,
} from './util/pluginUtils'
import packageJson from '../package.json'
@ -1361,7 +1362,7 @@ export let backgroundOpacity = createUtilityPlugin('backgroundOpacity', [
export let backgroundImage = createUtilityPlugin(
'backgroundImage',
[['bg', ['background-image']]],
{ resolveArbitraryValue: asLookupValue }
{ resolveArbitraryValue: [asLookupValue, asURL] }
)
export let gradientColorStops = (() => {
function transparentTo(value) {
@ -1482,7 +1483,7 @@ export let stroke = ({ matchUtilities, theme }) => {
}
export let strokeWidth = createUtilityPlugin('strokeWidth', [['stroke', ['stroke-width']]], {
resolveArbitraryValue: asLength,
resolveArbitraryValue: [asLength, asURL],
})
export let objectFit = ({ addUtilities }) => {

View File

@ -7,6 +7,8 @@ let env = sharedState.env
let contentMatchCache = sharedState.contentMatchCache
const PATTERNS = [
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
/([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
/([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
/([^<>"'`\s]*\[[^"'`\s]+\])/.source, // `fill-[#bada55]`

View File

@ -1,11 +1,12 @@
import transformThemeValue from './transformThemeValue'
import { asValue, asColor, asAngle, asLength, asLookupValue } from '../util/pluginUtils'
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'],
])
@ -38,7 +39,9 @@ export default function createUtilityPlugin(
Object.entries(theme(themeKey) ?? {}).filter(([modifier]) => modifier !== 'DEFAULT')
)
: theme(themeKey),
type: asMap.get(resolveArbitraryValue) ?? 'any',
type: Array.isArray(resolveArbitraryValue)
? resolveArbitraryValue.map((typeResolver) => asMap.get(typeResolver) ?? 'any')
: asMap.get(resolveArbitraryValue) ?? 'any',
}
)
}

View File

@ -175,6 +175,9 @@ export function asValue(modifier, lookup = {}, { validate = () => true } = {}) {
.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,
@ -236,6 +239,12 @@ 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,
@ -271,6 +280,7 @@ let typeMap = {
color: asColor,
angle: asAngle,
length: asLength,
url: asURL,
lookup: asLookupValue,
}

View File

@ -275,6 +275,12 @@
.bg-opacity-\[var\(--value\)\] {
--tw-bg-opacity: var(--value);
}
.bg-\[url\(\'\/path-to-image\.png\'\)\] {
background-image: url('/path-to-image.png');
}
.bg-\[url\:var\(--url\)\] {
background-image: var(--url);
}
.from-\[\#da5b66\] {
--tw-gradient-from: #da5b66;
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgb(218 91 102 / 0));
@ -305,6 +311,9 @@
.stroke-\[\#da5b66\] {
stroke: #da5b66;
}
.stroke-\[url\(\#icon-gradient\)\] {
stroke-width: url(#icon-gradient);
}
.object-\[50\%\2c 50\%\] {
object-position: 50% 50%;
}

View File

@ -11,6 +11,7 @@
<div class="bg-[#0f0] bg-[#ff0000] bg-[#0000ffcc]"></div>
<div class="bg-[rgb(123,123,123)] bg-[rgba(123,123,123,0.5)]"></div>
<div class="bg-[hsl(0,100%,50%)] bg-[hsla(0,100%,50%,0.3)]"></div>
<div class="bg-[url('/path-to-image.png')] bg-[url:var(--url)]"></div>
<div class="bg-opacity-[0.11]"></div>
<div class="bg-opacity-[var(--value)]"></div>
<div class="border-[#f00]"></div>
@ -116,6 +117,7 @@
<div class="object-[top,right]"></div>
<div class="object-[var(--position)]"></div>
<div class="stroke-[#da5b66]"></div>
<div class="stroke-[url(#icon-gradient)]"></div>
<div class="leading-[var(--leading)]"></div>
<div class="tracking-[var(--tracking)]"></div>
<div class="placeholder-[var(--placeholder)]"></div>