Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refractored ParseValue and Simplified cycleColorSpace Logic #29840

Open
wants to merge 1 commit into
base: next
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 59 additions & 42 deletions code/lib/blocks/src/controls/Color.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,52 +142,55 @@ const stringToArgs = (value: string) => {
return [x, y, z, a].map(Number);
};

const parseValue = (value: string): ParsedColor | undefined => {
if (!value) {
return undefined;
}
let valid = true;

if (RGB_REGEXP.test(value)) {
const [r, g, b, a] = stringToArgs(value);
const [h, s, l] = convert.rgb.hsl([r, g, b]) || [0, 0, 0];
return {
valid,
value,
keyword: convert.rgb.keyword([r, g, b]),
colorSpace: ColorSpace.RGB,
[ColorSpace.RGB]: value,
[ColorSpace.HSL]: `hsla(${h}, ${s}%, ${l}%, ${a})`,
[ColorSpace.HEX]: `#${convert.rgb.hex([r, g, b]).toLowerCase()}`,
};
}
const parseRgb = (value: string): ParsedColor | undefined => {
if (!RGB_REGEXP.test(value)) return undefined;

const [r, g, b, a] = stringToArgs(value);
const [h, s, l] = convert.rgb.hsl([r, g, b]) || [0, 0, 0];
Comment on lines +148 to +149
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: potential undefined access when convert.rgb.hsl returns null - should handle this case explicitly


return {
valid: true,
value,
keyword: convert.rgb.keyword([r, g, b]),
colorSpace: ColorSpace.RGB,
[ColorSpace.RGB]: value,
[ColorSpace.HSL]: `hsla(${h}, ${s}%, ${l}%, ${a})`,
[ColorSpace.HEX]: `#${convert.rgb.hex([r, g, b]).toLowerCase()}`,
};
};

if (HSL_REGEXP.test(value)) {
const [h, s, l, a] = stringToArgs(value);
const [r, g, b] = convert.hsl.rgb([h, s, l]) || [0, 0, 0];
return {
valid,
value,
keyword: convert.hsl.keyword([h, s, l]),
colorSpace: ColorSpace.HSL,
[ColorSpace.RGB]: `rgba(${r}, ${g}, ${b}, ${a})`,
[ColorSpace.HSL]: value,
[ColorSpace.HEX]: `#${convert.hsl.hex([h, s, l]).toLowerCase()}`,
};
}
const parseHsl = (value: string): ParsedColor | undefined => {
if (!HSL_REGEXP.test(value)) return undefined;

const [h, s, l, a] = stringToArgs(value);
const [r, g, b] = convert.hsl.rgb([h, s, l]) || [0, 0, 0];
Comment on lines +165 to +166
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: potential undefined access when convert.hsl.rgb returns null - should handle this case explicitly


return {
valid: true,
value,
keyword: convert.hsl.keyword([h, s, l]),
colorSpace: ColorSpace.HSL,
[ColorSpace.RGB]: `rgba(${r}, ${g}, ${b}, ${a})`,
[ColorSpace.HSL]: value,
[ColorSpace.HEX]: `#${convert.hsl.hex([h, s, l]).toLowerCase()}`,
};
};

const parseHexOrKeyword = (value: string): ParsedColor | undefined => {
const plain = value.replace('#', '');
// Try interpreting as keyword or hex
const rgb = convert.keyword.rgb(plain as any) || convert.hex.rgb(plain);
const hsl = convert.rgb.hsl(rgb);
Comment on lines 182 to 183
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: casting to 'any' here bypasses type safety - consider using proper type checking


let mapped = value;

if (/[^#a-f0-9]/i.test(value)) {
// Possibly a keyword
mapped = plain;
} else if (HEX_REGEXP.test(value)) {
mapped = `#${plain}`;
}

let valid = true;
if (mapped.startsWith('#')) {
valid = HEX_REGEXP.test(mapped);
} else {
Expand All @@ -209,6 +212,21 @@ const parseValue = (value: string): ParsedColor | undefined => {
};
};

const parseValue = (value: string): ParsedColor | undefined => {
if (!value) return undefined;

// Try RGB
const rgbColor = parseRgb(value);
if (rgbColor) return rgbColor;

// Try HSL
const hslColor = parseHsl(value);
if (hslColor) return hslColor;

// Try HEX/Keyword
return parseHexOrKeyword(value);
};

const getRealValue = (value: string, color: ParsedColor, colorSpace: ColorSpace) => {
if (!value || !color?.valid) {
return fallbackColor[colorSpace];
Expand Down Expand Up @@ -279,15 +297,14 @@ const useColorInput = (
);

const cycleColorSpace = useCallback(() => {
let next = COLOR_SPACES.indexOf(colorSpace) + 1;

if (next >= COLOR_SPACES.length) {
next = 0;
}
setColorSpace(COLOR_SPACES[next]);
const update = color?.[COLOR_SPACES[next]] || '';
setValue(update);
onChange(update);
const currentIndex = COLOR_SPACES.indexOf(colorSpace);
const nextIndex = (currentIndex + 1) % COLOR_SPACES.length;
const nextSpace = COLOR_SPACES[nextIndex];

setColorSpace(nextSpace);
const updatedValue = color?.[nextSpace] || '';
setValue(updatedValue);
onChange(updatedValue);
Comment on lines +305 to +307
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: setValue and onChange could be batched together to avoid multiple rerenders

}, [color, colorSpace, onChange]);

return { value, realValue, updateValue, color, colorSpace, cycleColorSpace };
Expand Down
Loading