Skip to content

Commit d5c87f9

Browse files
committed
Merge branch 'hsl-spaces'
2 parents 05e4cee + be4aa93 commit d5c87f9

File tree

5 files changed

+106
-109
lines changed

5 files changed

+106
-109
lines changed

package-lock.json

Lines changed: 11 additions & 65 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@
7070
"arg": "^5.0.1",
7171
"chalk": "^4.1.2",
7272
"chokidar": "^3.5.2",
73-
"color": "^4.0.1",
7473
"cosmiconfig": "^7.0.1",
74+
"culori": "^0.19.1",
7575
"detective": "^5.2.0",
7676
"didyoumean": "^1.2.2",
7777
"dlv": "^1.1.3",

src/util/pluginUtils.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import selectorParser from 'postcss-selector-parser'
22
import postcss from 'postcss'
3-
import createColor from 'color'
3+
import * as culori from 'culori'
44
import escapeCommas from './escapeCommas'
55
import { withAlphaValue } from './withAlphaVariable'
66
import isKeyframeRule from './isKeyframeRule'
@@ -222,12 +222,7 @@ function splitAlpha(modifier) {
222222
}
223223

224224
function isColor(value) {
225-
try {
226-
createColor(value)
227-
return true
228-
} catch (e) {
229-
return false
230-
}
225+
return culori.parse(value) !== undefined
231226
}
232227

233228
export function asColor(modifier, lookup = {}, tailwindConfig = {}) {

src/util/withAlphaVariable.js

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,42 @@
1-
import createColor from 'color'
1+
import * as culori from 'culori'
22
import _ from 'lodash'
33

4-
function hasAlpha(color) {
5-
return (
6-
color.startsWith('rgba(') ||
7-
color.startsWith('hsla(') ||
8-
(color.startsWith('#') && color.length === 9) ||
9-
(color.startsWith('#') && color.length === 5)
10-
)
11-
}
12-
13-
export function toRgba(color) {
14-
const [r, g, b, a] = createColor(color).rgb().array()
15-
16-
return [r, g, b, a === undefined && hasAlpha(color) ? 1 : a]
17-
}
18-
19-
export function toHsla(color) {
20-
const [h, s, l, a] = createColor(color).hsl().array()
21-
22-
return [h, `${s}%`, `${l}%`, a === undefined && hasAlpha(color) ? 1 : a]
4+
function isValidColor(color) {
5+
return culori.parse(color) !== undefined
236
}
247

258
export function withAlphaValue(color, alphaValue, defaultValue) {
269
if (_.isFunction(color)) {
2710
return color({ opacityValue: alphaValue })
2811
}
2912

30-
try {
31-
const isHSL = color.startsWith('hsl')
32-
const [i, j, k] = isHSL ? toHsla(color) : toRgba(color)
33-
return `${isHSL ? 'hsla' : 'rgba'}(${i}, ${j}, ${k}, ${alphaValue})`
34-
} catch {
35-
return defaultValue
13+
if (isValidColor(color)) {
14+
// Parse color
15+
const parsed = culori.parse(color)
16+
17+
// Apply alpha value
18+
parsed.alpha = alphaValue
19+
20+
// Format string
21+
let value
22+
if (parsed.mode === 'hsl') {
23+
value = culori.formatHsl(parsed)
24+
} else {
25+
value = culori.formatRgb(parsed)
26+
}
27+
28+
// Correctly apply CSS variable alpha value
29+
if (typeof alphaValue === 'string' && alphaValue.startsWith('var(') && value.endsWith('NaN)')) {
30+
value = value.replace('NaN)', `${alphaValue})`)
31+
}
32+
33+
// Color could not be formatted correctly
34+
if (!value.includes('NaN')) {
35+
return value
36+
}
3637
}
38+
39+
return defaultValue
3740
}
3841

3942
export default function withAlphaVariable({ color, property, variable }) {
@@ -44,24 +47,29 @@ export default function withAlphaVariable({ color, property, variable }) {
4447
}
4548
}
4649

47-
try {
48-
const isHSL = color.startsWith('hsl')
49-
50-
const [i, j, k, a] = isHSL ? toHsla(color) : toRgba(color)
50+
if (isValidColor(color)) {
51+
const parsed = culori.parse(color)
5152

52-
if (a !== undefined) {
53+
if ('alpha' in parsed) {
54+
// Has an alpha value, return color as-is
5355
return {
5456
[property]: color,
5557
}
5658
}
5759

60+
const formatFn = parsed.mode === 'hsl' ? 'formatHsl' : 'formatRgb'
61+
const value = culori[formatFn]({
62+
...parsed,
63+
alpha: NaN, // intentionally set to `NaN` for replacing
64+
}).replace('NaN)', `var(${variable}))`)
65+
5866
return {
5967
[variable]: '1',
60-
[property]: `${isHSL ? 'hsla' : 'rgba'}(${i}, ${j}, ${k}, var(${variable}))`,
61-
}
62-
} catch (error) {
63-
return {
64-
[property]: color,
68+
[property]: value,
6569
}
6670
}
71+
72+
return {
73+
[property]: color,
74+
}
6775
}

tests/withAlphaVariable.test.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ test('it adds the right custom property', () => {
77
'--tw-text-opacity': '1',
88
color: 'rgba(255, 0, 0, var(--tw-text-opacity))',
99
})
10+
expect(
11+
withAlphaVariable({
12+
color: 'hsl(240 100% 50%)',
13+
property: 'color',
14+
variable: '--tw-text-opacity',
15+
})
16+
).toEqual({
17+
'--tw-text-opacity': '1',
18+
color: 'hsla(240, 100%, 50%, var(--tw-text-opacity))',
19+
})
1020
})
1121

1222
test('it ignores colors that cannot be parsed', () => {
@@ -76,6 +86,15 @@ test('it ignores colors that already have an alpha channel', () => {
7686
).toEqual({
7787
'background-color': 'rgba(255, 255, 255, 0.5)',
7888
})
89+
expect(
90+
withAlphaVariable({
91+
color: 'rgba(255 255 255 / 0.5)',
92+
property: 'background-color',
93+
variable: '--tw-bg-opacity',
94+
})
95+
).toEqual({
96+
'background-color': 'rgba(255 255 255 / 0.5)',
97+
})
7998
expect(
8099
withAlphaVariable({
81100
color: 'hsla(240, 100%, 50%, 1)',
@@ -94,6 +113,15 @@ test('it ignores colors that already have an alpha channel', () => {
94113
).toEqual({
95114
'background-color': 'hsla(240, 100%, 50%, 0.5)',
96115
})
116+
expect(
117+
withAlphaVariable({
118+
color: 'hsl(240 100% 50% / 0.5)',
119+
property: 'background-color',
120+
variable: '--tw-bg-opacity',
121+
})
122+
).toEqual({
123+
'background-color': 'hsl(240 100% 50% / 0.5)',
124+
})
97125
})
98126

99127
test('it allows a closure to be passed', () => {
@@ -130,6 +158,16 @@ test('it transforms rgb and hsl to rgba and hsla', () => {
130158
'--tw-bg-opacity': '1',
131159
'background-color': 'rgba(50, 50, 50, var(--tw-bg-opacity))',
132160
})
161+
expect(
162+
withAlphaVariable({
163+
color: 'rgb(50 50 50)',
164+
property: 'background-color',
165+
variable: '--tw-bg-opacity',
166+
})
167+
).toEqual({
168+
'--tw-bg-opacity': '1',
169+
'background-color': 'rgba(50, 50, 50, var(--tw-bg-opacity))',
170+
})
133171
expect(
134172
withAlphaVariable({
135173
color: 'hsl(50, 50%, 50%)',
@@ -140,4 +178,14 @@ test('it transforms rgb and hsl to rgba and hsla', () => {
140178
'--tw-bg-opacity': '1',
141179
'background-color': 'hsla(50, 50%, 50%, var(--tw-bg-opacity))',
142180
})
181+
expect(
182+
withAlphaVariable({
183+
color: 'hsl(50 50% 50%)',
184+
property: 'background-color',
185+
variable: '--tw-bg-opacity',
186+
})
187+
).toEqual({
188+
'--tw-bg-opacity': '1',
189+
'background-color': 'hsla(50, 50%, 50%, var(--tw-bg-opacity))',
190+
})
143191
})

0 commit comments

Comments
 (0)