Skip to content

Commit a5efcf1

Browse files
committed
feat(VColorPicker): support emitting rgb() and hsl() strings
closes #20944
1 parent d062e71 commit a5efcf1

File tree

5 files changed

+22
-4
lines changed

5 files changed

+22
-4
lines changed

packages/docs/src/pages/en/components/color-pickers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ You can specify which input modes are available to your users with the `modes` p
5858

5959
#### Model
6060

61-
The `v-color-picker` uses the `v-model` prop to control the color displayed. It supports hex strings such as **#FF00FF** and **#FF00FF00**, and objects representing **RGBA**, **HSLA** and **HSVA** values. The component will try to emit the color in the same format that was provided. If the value is null, then the `v-color-picker` will default to emitting hex colors.
61+
The `v-color-picker` uses the `v-model` prop to control the color displayed. It supports hex strings such as **#FF00FF** and **#FF00FF00**, and objects representing **RGBA**, **HSLA** and **HSVA** values. The component will try to emit the color in the same format that was provided. If the value is null or an unsupported format, then the `v-color-picker` will default to emitting hex colors.
6262

6363
<ExamplesExample file="v-color-picker/prop-model" />
6464

packages/vuetify/src/components/VColorPicker/util/__tests__/index.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ describe('VColorPicker Utils', () => {
1717
[red, { h: 0, s: 1, v: 1 }, { h: 0, s: 1, v: 1 }],
1818
[red, { h: 0, s: 1, v: 1, a: 0.5 }, { h: 0, s: 1, v: 1, a: 1 }],
1919
[red, undefined, '#FF0000'],
20+
[red, 'hsl(0 0 0 / 1)', 'hsl(0 100 50)'],
21+
[{ ...red, a: 0.5 }, 'hsl(0 0 0 / 1)', 'hsl(0 100 50 / 0.5)'],
2022
] as const
2123

2224
it.each(cases)('When given %p and %p, extractColor util should return %p', (...args) => {

packages/vuetify/src/components/VColorPicker/util/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ function stripAlpha (color: any, stripAlpha: boolean) {
2424

2525
export function extractColor (color: HSV, input: any) {
2626
if (input == null || typeof input === 'string') {
27+
const hasA = color.a !== 1
28+
if (input?.startsWith('rgb(')) {
29+
const { r, g, b, a } = HSVtoRGB(color)
30+
return `rgb(${r} ${g} ${b}` + (hasA ? ` / ${a})` : ')')
31+
} else if (input?.startsWith('hsl(')) {
32+
const { h, s, l, a } = HSVtoHSL(color)
33+
return `hsl(${h} ${Math.round(s * 100)} ${Math.round(l * 100)}` + (hasA ? ` / ${a})` : ')')
34+
}
35+
2736
const hex = HSVtoHex(color)
2837

2938
if (color.a === 1) return hex.slice(0, 7)

packages/vuetify/src/util/__tests__/colorUtils.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,12 @@ describe('parseColor', () => {
4545

4646
it('should parse a CSS color string', () => {
4747
expect(parseColor('rgb(255, 0, 0)')).toEqual({ r: 255, g: 0, b: 0, a: undefined })
48+
expect(parseColor('rgb(255 0 0)')).toEqual({ r: 255, g: 0, b: 0, a: undefined })
4849
expect(parseColor('rgba(255, 0, 0, 0.5)')).toEqual({ r: 255, g: 0, b: 0, a: 0.5 })
50+
expect(parseColor('rgba(255 0 0 / 0.5)')).toEqual({ r: 255, g: 0, b: 0, a: 0.5 })
4951
expect(parseColor('hsl(100, 50%, 25%)')).toEqual({ r: 53, g: 96, b: 32, a: undefined })
5052
expect(parseColor('hsla(100, 50%, 25%, 0.5)')).toEqual({ r: 53, g: 96, b: 32, a: 0.5 })
53+
expect(parseColor('hsl(100 50 25 / 0.5)')).toEqual({ r: 53, g: 96, b: 32, a: 0.5 })
5154
})
5255

5356
it('should parse rgb object', () => {

packages/vuetify/src/util/colorUtils.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,13 @@ export function parseColor (color: Color): RGB {
4848
} else if (typeof color === 'string' && cssColorRe.test(color)) {
4949
const { groups } = color.match(cssColorRe)!
5050
const { fn, values } = groups as { fn: keyof typeof mappers, values: string }
51-
const realValues = values.split(/,\s*/)
52-
.map(v => {
53-
if (v.endsWith('%') && ['hsl', 'hsla', 'hsv', 'hsva'].includes(fn)) {
51+
const realValues = values.split(/,\s*|\s*\/\s*|\s+/)
52+
.map((v, i) => {
53+
if (
54+
v.endsWith('%') ||
55+
// unitless slv are %
56+
(i > 0 && i < 3 && ['hsl', 'hsla', 'hsv', 'hsva'].includes(fn))
57+
) {
5458
return parseFloat(v) / 100
5559
} else {
5660
return parseFloat(v)

0 commit comments

Comments
 (0)