Skip to content

Commit

Permalink
feat(VColorPicker): support emitting rgb() and hsl() strings
Browse files Browse the repository at this point in the history
closes #20944
  • Loading branch information
KaelWD committed Feb 3, 2025
1 parent d062e71 commit a5efcf1
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 4 deletions.
2 changes: 1 addition & 1 deletion packages/docs/src/pages/en/components/color-pickers.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ You can specify which input modes are available to your users with the `modes` p

#### Model

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.
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.

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ describe('VColorPicker Utils', () => {
[red, { h: 0, s: 1, v: 1 }, { h: 0, s: 1, v: 1 }],
[red, { h: 0, s: 1, v: 1, a: 0.5 }, { h: 0, s: 1, v: 1, a: 1 }],
[red, undefined, '#FF0000'],
[red, 'hsl(0 0 0 / 1)', 'hsl(0 100 50)'],
[{ ...red, a: 0.5 }, 'hsl(0 0 0 / 1)', 'hsl(0 100 50 / 0.5)'],
] as const

it.each(cases)('When given %p and %p, extractColor util should return %p', (...args) => {
Expand Down
9 changes: 9 additions & 0 deletions packages/vuetify/src/components/VColorPicker/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ function stripAlpha (color: any, stripAlpha: boolean) {

export function extractColor (color: HSV, input: any) {
if (input == null || typeof input === 'string') {
const hasA = color.a !== 1
if (input?.startsWith('rgb(')) {
const { r, g, b, a } = HSVtoRGB(color)
return `rgb(${r} ${g} ${b}` + (hasA ? ` / ${a})` : ')')
} else if (input?.startsWith('hsl(')) {
const { h, s, l, a } = HSVtoHSL(color)
return `hsl(${h} ${Math.round(s * 100)} ${Math.round(l * 100)}` + (hasA ? ` / ${a})` : ')')
}

const hex = HSVtoHex(color)

if (color.a === 1) return hex.slice(0, 7)
Expand Down
3 changes: 3 additions & 0 deletions packages/vuetify/src/util/__tests__/colorUtils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ describe('parseColor', () => {

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

it('should parse rgb object', () => {
Expand Down
10 changes: 7 additions & 3 deletions packages/vuetify/src/util/colorUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@ export function parseColor (color: Color): RGB {
} else if (typeof color === 'string' && cssColorRe.test(color)) {
const { groups } = color.match(cssColorRe)!
const { fn, values } = groups as { fn: keyof typeof mappers, values: string }
const realValues = values.split(/,\s*/)
.map(v => {
if (v.endsWith('%') && ['hsl', 'hsla', 'hsv', 'hsva'].includes(fn)) {
const realValues = values.split(/,\s*|\s*\/\s*|\s+/)
.map((v, i) => {
if (
v.endsWith('%') ||
// unitless slv are %
(i > 0 && i < 3 && ['hsl', 'hsla', 'hsv', 'hsva'].includes(fn))
) {
return parseFloat(v) / 100
} else {
return parseFloat(v)
Expand Down

0 comments on commit a5efcf1

Please sign in to comment.