mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
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:
parent
1f74568352
commit
64b4e6df7b
@ -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
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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))
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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%',
|
||||
|
||||
@ -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);
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user