Replace rgb and hsl helpers with <alpha-value> placeholder for colors with custom properties (#8501)

* implement <alpha-value>

* remove `rgb`/`hsl` helpers, use `<alpha-value>` instead

* never pass undefined to `withAlphaValue`

* WIP

* WIP

* WIP

* WIP

* Update changelog

* Cleanup

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This commit is contained in:
Jordan Pittman 2022-06-02 10:21:20 -04:00 committed by GitHub
parent 1f74568352
commit 64b4e6df7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 145 additions and 86 deletions

View File

@ -37,7 +37,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Add `rgb` and `hsl` color helpers for CSS variables ([#7665](https://github.com/tailwindlabs/tailwindcss/pull/7665))
- Support PostCSS `Document` nodes ([#7291](https://github.com/tailwindlabs/tailwindcss/pull/7291))
- Add `text-start` and `text-end` utilities ([#6656](https://github.com/tailwindlabs/tailwindcss/pull/6656))
- Support customizing class name when using `darkMode: 'class'` ([#5800](https://github.com/tailwindlabs/tailwindcss/pull/5800))
@ -54,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add opacity support when referencing colors with `theme` function ([#8416](https://github.com/tailwindlabs/tailwindcss/pull/8416))
- Add `postcss-import` support to the CLI ([#8437](https://github.com/tailwindlabs/tailwindcss/pull/8437))
- Add `optional` variant ([#8486](https://github.com/tailwindlabs/tailwindcss/pull/8486))
- Add `<alpha-value>` placeholder support for custom colors ([#8501](https://github.com/tailwindlabs/tailwindcss/pull/8501))
## [3.0.24] - 2022-04-12

View File

@ -1988,6 +1988,10 @@ export let corePlugins = {
let ringOpacityDefault = theme('ringOpacity.DEFAULT', '0.5')
if (!theme('ringColor')?.DEFAULT) {
return `rgb(147 197 253 / ${ringOpacityDefault})`
}
return withAlphaValue(
theme('ringColor')?.DEFAULT,
ringOpacityDefault,

View File

@ -6,6 +6,7 @@ import { normalizeScreens } from '../util/normalizeScreens'
import buildMediaQuery from '../util/buildMediaQuery'
import { toPath } from '../util/toPath'
import { withAlphaValue } from '../util/withAlphaVariable'
import { parseColorFormat } from '../util/pluginUtils'
function isObject(input) {
return typeof input === 'object' && input !== null
@ -181,6 +182,7 @@ export default function ({ tailwindConfig: config }) {
}
if (alpha !== undefined) {
value = parseColorFormat(value)
value = withAlphaValue(value, alpha, value)
}

View File

@ -95,9 +95,19 @@ function splitAlpha(modifier) {
return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
}
export function parseColorFormat(value) {
if (typeof value === 'string' && value.includes('<alpha-value>')) {
let oldValue = value
return ({ opacityValue = 1 }) => oldValue.replace('<alpha-value>', opacityValue)
}
return value
}
export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
if (options.values?.[modifier] !== undefined) {
return options.values?.[modifier]
return parseColorFormat(options.values?.[modifier])
}
let [color, alpha] = splitAlpha(modifier)
@ -110,6 +120,8 @@ export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
return undefined
}
normalizedColor = parseColorFormat(normalizedColor)
if (isArbitraryValue(alpha)) {
return withAlphaValue(normalizedColor, alpha.slice(1, -1))
}

View File

@ -8,7 +8,9 @@ import { toPath } from './toPath'
import { normalizeConfig } from './normalizeConfig'
import isPlainObject from './isPlainObject'
import { cloneDeep } from './cloneDeep'
import { parseColorFormat } from './pluginUtils'
import { withAlphaValue } from './withAlphaVariable'
import toColorValue from './toColorValue'
function isFunction(input) {
return typeof input === 'function'
@ -67,36 +69,6 @@ const configUtils = {
{}
)
},
rgb(property) {
if (!property.startsWith('--')) {
throw new Error(
'The rgb() helper requires a custom property name to be passed as the first argument.'
)
}
return ({ opacityValue }) => {
if (opacityValue === undefined || opacityValue === 1) {
return `rgb(var(${property}) / 1.0)`
}
return `rgb(var(${property}) / ${opacityValue})`
}
},
hsl(property) {
if (!property.startsWith('--')) {
throw new Error(
'The hsl() helper requires a custom property name to be passed as the first argument.'
)
}
return ({ opacityValue }) => {
if (opacityValue === undefined || opacityValue === 1) {
return `hsl(var(${property}) / 1)`
}
return `hsl(var(${property}) / ${opacityValue})`
}
},
}
function value(valueToResolve, ...args) {
@ -215,7 +187,9 @@ function resolveFunctionKeys(object) {
if (val !== undefined) {
if (path.alpha !== undefined) {
return withAlphaValue(val, path.alpha)
let normalized = parseColorFormat(val)
return withAlphaValue(normalized, path.alpha, toColorValue(normalized))
}
if (isPlainObject(val)) {
@ -229,8 +203,6 @@ function resolveFunctionKeys(object) {
return defaultValue
}
// colors.red.500/50
Object.assign(resolvePath, {
theme: resolvePath,
...configUtils,

View File

@ -5,7 +5,7 @@ export function withAlphaValue(color, alphaValue, defaultValue) {
return color({ opacityValue: alphaValue })
}
let parsed = parseColor(color)
let parsed = parseColor(color, { loose: true })
if (parsed === null) {
return defaultValue

View File

@ -982,11 +982,11 @@ test('Theme function can extract alpha values for colors (7)', () => {
return runFull(input, {
theme: {
colors: ({ rgb }) => ({
colors: {
blue: {
500: rgb('--foo'),
500: 'rgb(var(--foo) / <alpha-value>)',
},
}),
},
},
}).then((result) => {
expect(result.css).toMatchCss(output)
@ -1009,11 +1009,11 @@ test('Theme function can extract alpha values for colors (8)', () => {
return runFull(input, {
theme: {
colors: ({ rgb }) => ({
colors: {
blue: {
500: rgb('--foo'),
500: 'rgb(var(--foo) / <alpha-value>)',
},
}),
},
opacity: {
myalpha: '50%',

View File

@ -96,7 +96,7 @@ test('colors defined as functions work when opacity plugins are disabled', () =>
})
})
it('can use rgb helper when defining custom properties for colors (opacity plugins enabled)', () => {
it('can use <alpha-value> defining custom properties for colors (opacity plugins enabled)', () => {
let config = {
content: [
{
@ -117,9 +117,9 @@ it('can use rgb helper when defining custom properties for colors (opacity plugi
},
],
theme: {
colors: ({ rgb }) => ({
primary: rgb('--color-primary'),
}),
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
}
@ -192,9 +192,9 @@ it('can use rgb helper when defining custom properties for colors (opacity plugi
},
],
theme: {
colors: ({ rgb }) => ({
primary: rgb('--color-primary'),
}),
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
corePlugins: {
backgroundOpacity: false,
@ -269,9 +269,9 @@ it('can use hsl helper when defining custom properties for colors (opacity plugi
},
],
theme: {
colors: ({ hsl }) => ({
primary: hsl('--color-primary'),
}),
colors: {
primary: 'hsl(var(--color-primary) / <alpha-value>)',
},
},
}
@ -344,9 +344,9 @@ it('can use hsl helper when defining custom properties for colors (opacity plugi
},
],
theme: {
colors: ({ hsl }) => ({
primary: hsl('--color-primary'),
}),
colors: {
primary: 'hsl(var(--color-primary) / <alpha-value>)',
},
},
corePlugins: {
backgroundOpacity: false,
@ -400,34 +400,6 @@ it('can use hsl helper when defining custom properties for colors (opacity plugi
})
})
it('the rgb helper throws when not passing custom properties', () => {
let config = {
theme: {
colors: ({ rgb }) => ({
primary: rgb('anything else'),
}),
},
}
return expect(run('@tailwind utilities', config)).rejects.toThrow(
'The rgb() helper requires a custom property name to be passed as the first argument.'
)
})
it('the hsl helper throws when not passing custom properties', () => {
let config = {
theme: {
colors: ({ hsl }) => ({
primary: hsl('anything else'),
}),
},
}
return expect(run('@tailwind utilities', config)).rejects.toThrow(
'The hsl() helper requires a custom property name to be passed as the first argument.'
)
})
test('Theme function in JS can apply alpha values to colors (1)', () => {
let input = css`
@tailwind utilities;
@ -611,11 +583,11 @@ test('Theme function in JS can apply alpha values to colors (7)', () => {
content: [{ raw: html`text-foo` }],
corePlugins: { textOpacity: false },
theme: {
colors: ({ rgb }) => ({
colors: {
blue: {
500: rgb('--foo'),
500: 'rgb(var(--foo) / <alpha-value>)',
},
}),
},
extend: {
textColor: ({ theme }) => ({
foo: theme('colors.blue.500 / var(--my-alpha)'),
@ -659,3 +631,100 @@ test('Theme function prefers existing values in config', () => {
expect(result.warnings().length).toBe(0)
})
})
it('should be possible to use an <alpha-value> as part of the color definition', () => {
let config = {
content: [
{
raw: html` <div class="bg-primary"></div> `,
},
],
corePlugins: ['backgroundColor', 'backgroundOpacity'],
theme: {
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
}
return run('@tailwind utilities', config).then((result) => {
expect(result.css).toMatchCss(css`
.bg-primary {
--tw-bg-opacity: 1;
background-color: rgb(var(--color-primary) / var(--tw-bg-opacity));
}
`)
})
})
it('should be possible to use an <alpha-value> as part of the color definition with an opacity modifiers', () => {
let config = {
content: [
{
raw: html` <div class="bg-primary/50"></div> `,
},
],
corePlugins: ['backgroundColor', 'backgroundOpacity'],
theme: {
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
}
return run('@tailwind utilities', config).then((result) => {
expect(result.css).toMatchCss(css`
.bg-primary\/50 {
background-color: rgb(var(--color-primary) / 0.5);
}
`)
})
})
it('should be possible to use an <alpha-value> as part of the color definition with an opacity modifiers', () => {
let config = {
content: [
{
raw: html` <div class="bg-primary"></div> `,
},
],
corePlugins: ['backgroundColor'],
theme: {
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
}
return run('@tailwind utilities', config).then((result) => {
expect(result.css).toMatchCss(css`
.bg-primary {
background-color: rgb(var(--color-primary) / 1);
}
`)
})
})
it('should be possible to use <alpha-value> inside arbitrary values', () => {
let config = {
content: [
{
raw: html` <div class="bg-[rgb(var(--color-primary)/<alpha-value>)]/50"></div> `,
},
],
corePlugins: ['backgroundColor', 'backgroundOpacity'],
theme: {
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
}
return run('@tailwind utilities', config).then((result) => {
expect(result.css).toMatchCss(css`
.bg-\[rgb\(var\(--color-primary\)\/\<alpha-value\>\)\]\/50 {
background-color: rgb(var(--color-primary) / 0.5);
}
`)
})
})