From 3ec6f55a77bc3794dd3252700a885dff5d61f313 Mon Sep 17 00:00:00 2001 From: "joan.teriihoania" Date: Thu, 11 Sep 2025 17:20:48 +0200 Subject: [PATCH] Refactor ColorPicker to only trigger onChange callback when component-tied internal change was made. Do not trigger it due to external change (aka: init, or value prop change) --- packages/color-picker/index.tsx | 38 ++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/color-picker/index.tsx b/packages/color-picker/index.tsx index d50e25c0..af677487 100644 --- a/packages/color-picker/index.tsx +++ b/packages/color-picker/index.tsx @@ -69,6 +69,18 @@ export const ColorPicker = ({ const selectedColor = Color(value); const defaultColor = Color(defaultValue); + /** + * As long as value wasn't triggered by an internal interaction + * we do not trigger the onChange callback. + */ + const isDirty = useRef(false) + const markAsDirty = () => { + isDirty.current = true + } + const markAsClean = () => { + isDirty.current = false + } + const [hue, setHue] = useState( selectedColor.hue() || defaultColor.hue() || 0 ); @@ -88,6 +100,10 @@ export const ColorPicker = ({ if (value) { const color = Color.rgb(value).rgb().object(); + // Changes to the value prop are considered external changes + // and should not trigger an onChange event. + markAsClean() + setHue(color.r); setSaturation(color.g); setLightness(color.b); @@ -97,7 +113,7 @@ export const ColorPicker = ({ // Notify parent of changes useEffect(() => { - if (onChange) { + if (onChange && isDirty.current) { const color = Color.hsl(hue, saturation, lightness).alpha(alpha / 100); const rgba = color.rgb().array(); @@ -113,10 +129,22 @@ export const ColorPicker = ({ lightness, alpha, mode, - setHue, - setSaturation, - setLightness, - setAlpha, + setHue: (...args) => { + markAsDirty(); + setHue(...args) + }, + setSaturation: (...args) => { + markAsDirty(); + setSaturation(...args) + }, + setLightness: (...args) => { + markAsDirty(); + setLightness(...args) + }, + setAlpha: (...args) => { + markAsDirty(); + setAlpha(...args) + }, setMode, }} >