diff --git a/theatre/shared/src/utils/color.ts b/theatre/shared/src/utils/color.ts index 93a022c..655a648 100644 --- a/theatre/shared/src/utils/color.ts +++ b/theatre/shared/src/utils/color.ts @@ -1,10 +1,29 @@ import {clamp} from 'lodash-es' +/** + * Robust check for a valid hex value (without the "#") in a string + * + * @remarks + * + * Supports all the syntax variants of + * {@link https://google.com}: + * + * + * ```javascript + * #RGB // The three-value syntax + * #RGBA // The four-value syntax + * #RRGGBB // The six-value syntax + * #RRGGBBAA // The eight-value syntax + * ``` + */ +export const validHexRegExp = /^#*([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i + export function parseRgbaFromHex(rgba: string) { rgba = rgba.trim().toLowerCase() - const hex = rgba.match(/^#?([0-9a-f]{8})$/i) - if (!hex) { + const match = rgba.match(validHexRegExp) + + if (!match) { return { r: 0, g: 0, @@ -13,12 +32,13 @@ export function parseRgbaFromHex(rgba: string) { } } - const match = hex[1] + const hex = _hexInEightValueSyntax(match[1]) + return { - r: parseInt(match.substr(0, 2), 16) / 255, - g: parseInt(match.substr(2, 2), 16) / 255, - b: parseInt(match.substr(4, 2), 16) / 255, - a: parseInt(match.substr(6, 2), 16) / 255, + r: parseInt(hex.substr(0, 2), 16) / 255, + g: parseInt(hex.substr(2, 2), 16) / 255, + b: parseInt(hex.substr(4, 2), 16) / 255, + a: parseInt(hex.substr(6, 2), 16) / 255, } } @@ -126,3 +146,21 @@ export type Laba = { b: number alpha: number } + +/** + * Returns a hex string in the eight-value syntax + */ +function _hexInEightValueSyntax(hex: string): string { + switch (hex.length) { + case 3: + return `${hex.repeat(2)}ff` + case 4: + const rgb = hex.substr(0, 3) + const alpha = hex[3] + return `${rgb.repeat(2)}${alpha.repeat(2)}` + case 6: + return `${hex}ff` + } + + return hex +} diff --git a/theatre/studio/src/propEditors/simpleEditors/RgbaPropEditor.tsx b/theatre/studio/src/propEditors/simpleEditors/RgbaPropEditor.tsx index 67b879e..424ffb6 100644 --- a/theatre/studio/src/propEditors/simpleEditors/RgbaPropEditor.tsx +++ b/theatre/studio/src/propEditors/simpleEditors/RgbaPropEditor.tsx @@ -1,5 +1,6 @@ import type {PropTypeConfig_Rgba} from '@theatre/core/propTypes' -import type {Rgba} from '@theatre/shared/utils/color' +import type {Rgba} from '@theatre/shared/utils/color'; +import { validHexRegExp} from '@theatre/shared/utils/color' import { decorateRgba, rgba2hex, @@ -114,7 +115,7 @@ function RgbaPropEditor({ temporarilySetValue={noop} discardTemporaryValue={noop} permanentlySetValue={onChange} - isValid={(v) => !!v.match(/^#?([0-9a-f]{8})$/i)} + isValid={(v) => !!v.match(validHexRegExp)} /> {popoverNode}