Skip to content

Commit 64b4e6d

Browse files
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 <[email protected]>
1 parent 1f74568 commit 64b4e6d

8 files changed

+145
-86
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3737

3838
### Added
3939

40-
- Add `rgb` and `hsl` color helpers for CSS variables ([#7665](https://github.com/tailwindlabs/tailwindcss/pull/7665))
4140
- Support PostCSS `Document` nodes ([#7291](https://github.com/tailwindlabs/tailwindcss/pull/7291))
4241
- Add `text-start` and `text-end` utilities ([#6656](https://github.com/tailwindlabs/tailwindcss/pull/6656))
4342
- 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
5453
- Add opacity support when referencing colors with `theme` function ([#8416](https://github.com/tailwindlabs/tailwindcss/pull/8416))
5554
- Add `postcss-import` support to the CLI ([#8437](https://github.com/tailwindlabs/tailwindcss/pull/8437))
5655
- Add `optional` variant ([#8486](https://github.com/tailwindlabs/tailwindcss/pull/8486))
56+
- Add `<alpha-value>` placeholder support for custom colors ([#8501](https://github.com/tailwindlabs/tailwindcss/pull/8501))
5757

5858
## [3.0.24] - 2022-04-12
5959

src/corePlugins.js

+4
Original file line numberDiff line numberDiff line change
@@ -1988,6 +1988,10 @@ export let corePlugins = {
19881988

19891989
let ringOpacityDefault = theme('ringOpacity.DEFAULT', '0.5')
19901990

1991+
if (!theme('ringColor')?.DEFAULT) {
1992+
return `rgb(147 197 253 / ${ringOpacityDefault})`
1993+
}
1994+
19911995
return withAlphaValue(
19921996
theme('ringColor')?.DEFAULT,
19931997
ringOpacityDefault,

src/lib/evaluateTailwindFunctions.js

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { normalizeScreens } from '../util/normalizeScreens'
66
import buildMediaQuery from '../util/buildMediaQuery'
77
import { toPath } from '../util/toPath'
88
import { withAlphaValue } from '../util/withAlphaVariable'
9+
import { parseColorFormat } from '../util/pluginUtils'
910

1011
function isObject(input) {
1112
return typeof input === 'object' && input !== null
@@ -181,6 +182,7 @@ export default function ({ tailwindConfig: config }) {
181182
}
182183

183184
if (alpha !== undefined) {
185+
value = parseColorFormat(value)
184186
value = withAlphaValue(value, alpha, value)
185187
}
186188

src/util/pluginUtils.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,19 @@ function splitAlpha(modifier) {
9595
return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
9696
}
9797

98+
export function parseColorFormat(value) {
99+
if (typeof value === 'string' && value.includes('<alpha-value>')) {
100+
let oldValue = value
101+
102+
return ({ opacityValue = 1 }) => oldValue.replace('<alpha-value>', opacityValue)
103+
}
104+
105+
return value
106+
}
107+
98108
export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
99109
if (options.values?.[modifier] !== undefined) {
100-
return options.values?.[modifier]
110+
return parseColorFormat(options.values?.[modifier])
101111
}
102112

103113
let [color, alpha] = splitAlpha(modifier)
@@ -110,6 +120,8 @@ export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
110120
return undefined
111121
}
112122

123+
normalizedColor = parseColorFormat(normalizedColor)
124+
113125
if (isArbitraryValue(alpha)) {
114126
return withAlphaValue(normalizedColor, alpha.slice(1, -1))
115127
}

src/util/resolveConfig.js

+5-33
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import { toPath } from './toPath'
88
import { normalizeConfig } from './normalizeConfig'
99
import isPlainObject from './isPlainObject'
1010
import { cloneDeep } from './cloneDeep'
11+
import { parseColorFormat } from './pluginUtils'
1112
import { withAlphaValue } from './withAlphaVariable'
13+
import toColorValue from './toColorValue'
1214

1315
function isFunction(input) {
1416
return typeof input === 'function'
@@ -67,36 +69,6 @@ const configUtils = {
6769
{}
6870
)
6971
},
70-
rgb(property) {
71-
if (!property.startsWith('--')) {
72-
throw new Error(
73-
'The rgb() helper requires a custom property name to be passed as the first argument.'
74-
)
75-
}
76-
77-
return ({ opacityValue }) => {
78-
if (opacityValue === undefined || opacityValue === 1) {
79-
return `rgb(var(${property}) / 1.0)`
80-
}
81-
82-
return `rgb(var(${property}) / ${opacityValue})`
83-
}
84-
},
85-
hsl(property) {
86-
if (!property.startsWith('--')) {
87-
throw new Error(
88-
'The hsl() helper requires a custom property name to be passed as the first argument.'
89-
)
90-
}
91-
92-
return ({ opacityValue }) => {
93-
if (opacityValue === undefined || opacityValue === 1) {
94-
return `hsl(var(${property}) / 1)`
95-
}
96-
97-
return `hsl(var(${property}) / ${opacityValue})`
98-
}
99-
},
10072
}
10173

10274
function value(valueToResolve, ...args) {
@@ -215,7 +187,9 @@ function resolveFunctionKeys(object) {
215187

216188
if (val !== undefined) {
217189
if (path.alpha !== undefined) {
218-
return withAlphaValue(val, path.alpha)
190+
let normalized = parseColorFormat(val)
191+
192+
return withAlphaValue(normalized, path.alpha, toColorValue(normalized))
219193
}
220194

221195
if (isPlainObject(val)) {
@@ -229,8 +203,6 @@ function resolveFunctionKeys(object) {
229203
return defaultValue
230204
}
231205

232-
// colors.red.500/50
233-
234206
Object.assign(resolvePath, {
235207
theme: resolvePath,
236208
...configUtils,

src/util/withAlphaVariable.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export function withAlphaValue(color, alphaValue, defaultValue) {
55
return color({ opacityValue: alphaValue })
66
}
77

8-
let parsed = parseColor(color)
8+
let parsed = parseColor(color, { loose: true })
99

1010
if (parsed === null) {
1111
return defaultValue

tests/evaluateTailwindFunctions.test.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -982,11 +982,11 @@ test('Theme function can extract alpha values for colors (7)', () => {
982982

983983
return runFull(input, {
984984
theme: {
985-
colors: ({ rgb }) => ({
985+
colors: {
986986
blue: {
987-
500: rgb('--foo'),
987+
500: 'rgb(var(--foo) / <alpha-value>)',
988988
},
989-
}),
989+
},
990990
},
991991
}).then((result) => {
992992
expect(result.css).toMatchCss(output)
@@ -1009,11 +1009,11 @@ test('Theme function can extract alpha values for colors (8)', () => {
10091009

10101010
return runFull(input, {
10111011
theme: {
1012-
colors: ({ rgb }) => ({
1012+
colors: {
10131013
blue: {
1014-
500: rgb('--foo'),
1014+
500: 'rgb(var(--foo) / <alpha-value>)',
10151015
},
1016-
}),
1016+
},
10171017

10181018
opacity: {
10191019
myalpha: '50%',

tests/opacity.test.js

+113-44
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ test('colors defined as functions work when opacity plugins are disabled', () =>
9696
})
9797
})
9898

99-
it('can use rgb helper when defining custom properties for colors (opacity plugins enabled)', () => {
99+
it('can use <alpha-value> defining custom properties for colors (opacity plugins enabled)', () => {
100100
let config = {
101101
content: [
102102
{
@@ -117,9 +117,9 @@ it('can use rgb helper when defining custom properties for colors (opacity plugi
117117
},
118118
],
119119
theme: {
120-
colors: ({ rgb }) => ({
121-
primary: rgb('--color-primary'),
122-
}),
120+
colors: {
121+
primary: 'rgb(var(--color-primary) / <alpha-value>)',
122+
},
123123
},
124124
}
125125

@@ -192,9 +192,9 @@ it('can use rgb helper when defining custom properties for colors (opacity plugi
192192
},
193193
],
194194
theme: {
195-
colors: ({ rgb }) => ({
196-
primary: rgb('--color-primary'),
197-
}),
195+
colors: {
196+
primary: 'rgb(var(--color-primary) / <alpha-value>)',
197+
},
198198
},
199199
corePlugins: {
200200
backgroundOpacity: false,
@@ -269,9 +269,9 @@ it('can use hsl helper when defining custom properties for colors (opacity plugi
269269
},
270270
],
271271
theme: {
272-
colors: ({ hsl }) => ({
273-
primary: hsl('--color-primary'),
274-
}),
272+
colors: {
273+
primary: 'hsl(var(--color-primary) / <alpha-value>)',
274+
},
275275
},
276276
}
277277

@@ -344,9 +344,9 @@ it('can use hsl helper when defining custom properties for colors (opacity plugi
344344
},
345345
],
346346
theme: {
347-
colors: ({ hsl }) => ({
348-
primary: hsl('--color-primary'),
349-
}),
347+
colors: {
348+
primary: 'hsl(var(--color-primary) / <alpha-value>)',
349+
},
350350
},
351351
corePlugins: {
352352
backgroundOpacity: false,
@@ -400,34 +400,6 @@ it('can use hsl helper when defining custom properties for colors (opacity plugi
400400
})
401401
})
402402

403-
it('the rgb helper throws when not passing custom properties', () => {
404-
let config = {
405-
theme: {
406-
colors: ({ rgb }) => ({
407-
primary: rgb('anything else'),
408-
}),
409-
},
410-
}
411-
412-
return expect(run('@tailwind utilities', config)).rejects.toThrow(
413-
'The rgb() helper requires a custom property name to be passed as the first argument.'
414-
)
415-
})
416-
417-
it('the hsl helper throws when not passing custom properties', () => {
418-
let config = {
419-
theme: {
420-
colors: ({ hsl }) => ({
421-
primary: hsl('anything else'),
422-
}),
423-
},
424-
}
425-
426-
return expect(run('@tailwind utilities', config)).rejects.toThrow(
427-
'The hsl() helper requires a custom property name to be passed as the first argument.'
428-
)
429-
})
430-
431403
test('Theme function in JS can apply alpha values to colors (1)', () => {
432404
let input = css`
433405
@tailwind utilities;
@@ -611,11 +583,11 @@ test('Theme function in JS can apply alpha values to colors (7)', () => {
611583
content: [{ raw: html`text-foo` }],
612584
corePlugins: { textOpacity: false },
613585
theme: {
614-
colors: ({ rgb }) => ({
586+
colors: {
615587
blue: {
616-
500: rgb('--foo'),
588+
500: 'rgb(var(--foo) / <alpha-value>)',
617589
},
618-
}),
590+
},
619591
extend: {
620592
textColor: ({ theme }) => ({
621593
foo: theme('colors.blue.500 / var(--my-alpha)'),
@@ -659,3 +631,100 @@ test('Theme function prefers existing values in config', () => {
659631
expect(result.warnings().length).toBe(0)
660632
})
661633
})
634+
635+
it('should be possible to use an <alpha-value> as part of the color definition', () => {
636+
let config = {
637+
content: [
638+
{
639+
raw: html` <div class="bg-primary"></div> `,
640+
},
641+
],
642+
corePlugins: ['backgroundColor', 'backgroundOpacity'],
643+
theme: {
644+
colors: {
645+
primary: 'rgb(var(--color-primary) / <alpha-value>)',
646+
},
647+
},
648+
}
649+
650+
return run('@tailwind utilities', config).then((result) => {
651+
expect(result.css).toMatchCss(css`
652+
.bg-primary {
653+
--tw-bg-opacity: 1;
654+
background-color: rgb(var(--color-primary) / var(--tw-bg-opacity));
655+
}
656+
`)
657+
})
658+
})
659+
660+
it('should be possible to use an <alpha-value> as part of the color definition with an opacity modifiers', () => {
661+
let config = {
662+
content: [
663+
{
664+
raw: html` <div class="bg-primary/50"></div> `,
665+
},
666+
],
667+
corePlugins: ['backgroundColor', 'backgroundOpacity'],
668+
theme: {
669+
colors: {
670+
primary: 'rgb(var(--color-primary) / <alpha-value>)',
671+
},
672+
},
673+
}
674+
675+
return run('@tailwind utilities', config).then((result) => {
676+
expect(result.css).toMatchCss(css`
677+
.bg-primary\/50 {
678+
background-color: rgb(var(--color-primary) / 0.5);
679+
}
680+
`)
681+
})
682+
})
683+
684+
it('should be possible to use an <alpha-value> as part of the color definition with an opacity modifiers', () => {
685+
let config = {
686+
content: [
687+
{
688+
raw: html` <div class="bg-primary"></div> `,
689+
},
690+
],
691+
corePlugins: ['backgroundColor'],
692+
theme: {
693+
colors: {
694+
primary: 'rgb(var(--color-primary) / <alpha-value>)',
695+
},
696+
},
697+
}
698+
699+
return run('@tailwind utilities', config).then((result) => {
700+
expect(result.css).toMatchCss(css`
701+
.bg-primary {
702+
background-color: rgb(var(--color-primary) / 1);
703+
}
704+
`)
705+
})
706+
})
707+
708+
it('should be possible to use <alpha-value> inside arbitrary values', () => {
709+
let config = {
710+
content: [
711+
{
712+
raw: html` <div class="bg-[rgb(var(--color-primary)/<alpha-value>)]/50"></div> `,
713+
},
714+
],
715+
corePlugins: ['backgroundColor', 'backgroundOpacity'],
716+
theme: {
717+
colors: {
718+
primary: 'rgb(var(--color-primary) / <alpha-value>)',
719+
},
720+
},
721+
}
722+
723+
return run('@tailwind utilities', config).then((result) => {
724+
expect(result.css).toMatchCss(css`
725+
.bg-\[rgb\(var\(--color-primary\)\/\<alpha-value\>\)\]\/50 {
726+
background-color: rgb(var(--color-primary) / 0.5);
727+
}
728+
`)
729+
})
730+
})

0 commit comments

Comments
 (0)