From 8342bf345215ed621f15936069ecb599a5f43d12 Mon Sep 17 00:00:00 2001 From: Wondermarin <33459274+Wondermarin@users.noreply.github.com> Date: Sat, 12 Aug 2023 23:37:18 +0300 Subject: [PATCH] fix: Add reposition support (#60) --- src/components/alpha/alpha.component.tsx | 4 +-- src/components/hue/hue.component.tsx | 4 +-- .../interactive/interactive.component.tsx | 6 ++-- .../saturation/saturation.component.tsx | 2 +- .../use-bounding-client-rect.hook.ts | 28 ++++++++++++++++--- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/components/alpha/alpha.component.tsx b/src/components/alpha/alpha.component.tsx index b9a8362..4e6d47d 100644 --- a/src/components/alpha/alpha.component.tsx +++ b/src/components/alpha/alpha.component.tsx @@ -12,7 +12,7 @@ interface IAlphaProps { } export const Alpha = memo(({ color, onChange }: IAlphaProps) => { - const [alphaRef, { width = 1 }] = useBoundingClientRect(); + const [alphaRef, { width }] = useBoundingClientRect(); const position = useMemo(() => { const x = color.hsv.a * width; @@ -29,7 +29,7 @@ export const Alpha = memo(({ color, onChange }: IAlphaProps) => { onChange(nextColor); }, - [width, color.hsv, onChange] + [color.hsv, width, onChange] ); const rgb = useMemo(() => [color.rgb.r, color.rgb.g, color.rgb.b].join(" "), [color.rgb.r, color.rgb.g, color.rgb.b]); diff --git a/src/components/hue/hue.component.tsx b/src/components/hue/hue.component.tsx index d4f08b8..2236cce 100644 --- a/src/components/hue/hue.component.tsx +++ b/src/components/hue/hue.component.tsx @@ -12,7 +12,7 @@ interface IHueProps { } export const Hue = memo(({ color, onChange }: IHueProps) => { - const [hueRef, { width = 1 }] = useBoundingClientRect(); + const [hueRef, { width }] = useBoundingClientRect(); const position = useMemo(() => { const x = (color.hsv.h / 360) * width; @@ -29,7 +29,7 @@ export const Hue = memo(({ color, onChange }: IHueProps) => { onChange(nextColor); }, - [width, color.hsv, onChange] + [color.hsv, width, onChange] ); const hsl = useMemo(() => [color.hsv.h, "100%", "50%"].join(" "), [color.hsv.h]); diff --git a/src/components/interactive/interactive.component.tsx b/src/components/interactive/interactive.component.tsx index 9e0d002..bc69498 100644 --- a/src/components/interactive/interactive.component.tsx +++ b/src/components/interactive/interactive.component.tsx @@ -10,16 +10,18 @@ interface IInteractiveProps { } export const Interactive = memo(({ onCoordinateChange, children }: IInteractiveProps) => { - const [interactiveRef, { width = 1, height = 1, left = 1, top = 1 }] = useBoundingClientRect(); + const [interactiveRef, { width, height }, getPosition] = useBoundingClientRect(); const move = useCallback( (event: React.PointerEvent | PointerEvent) => { + const { left, top } = getPosition(); + const x = clamp(event.clientX - left, 0, width); const y = clamp(event.clientY - top, 0, height); onCoordinateChange(x, y); }, - [width, height, left, top, onCoordinateChange] + [width, height, getPosition, onCoordinateChange] ); const onPointerDown = useCallback( diff --git a/src/components/saturation/saturation.component.tsx b/src/components/saturation/saturation.component.tsx index 052f81b..f94583f 100644 --- a/src/components/saturation/saturation.component.tsx +++ b/src/components/saturation/saturation.component.tsx @@ -13,7 +13,7 @@ interface ISaturationProps { } export const Saturation = memo(({ height, color, onChange }: ISaturationProps) => { - const [saturationRef, { width = 1 }] = useBoundingClientRect(); + const [saturationRef, { width }] = useBoundingClientRect(); const position = useMemo(() => { const x = (color.hsv.s / 100) * width; diff --git a/src/hooks/use-bounding-client-rect/use-bounding-client-rect.hook.ts b/src/hooks/use-bounding-client-rect/use-bounding-client-rect.hook.ts index ffe87ec..93fdb19 100644 --- a/src/hooks/use-bounding-client-rect/use-bounding-client-rect.hook.ts +++ b/src/hooks/use-bounding-client-rect/use-bounding-client-rect.hook.ts @@ -1,6 +1,18 @@ import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; -export function useBoundingClientRect(): [React.RefObject, DOMRect] { +interface ISize { + readonly width: number; + readonly height: number; +} + +interface IPosition { + readonly left: number; + readonly right: number; + readonly top: number; + readonly bottom: number; +} + +export function useBoundingClientRect(): [React.RefObject, ISize, () => IPosition] { const ref = useRef(null); const [resizeCounter, setResizeCounter] = useState(0); @@ -20,10 +32,18 @@ export function useBoundingClientRect(): [React.RefObject }; }, [onResize]); - return useMemo(() => { - const domRect = ref.current?.getBoundingClientRect() ?? ({} as DOMRect); + const size = useMemo(() => { + const { width = 1, height = 1 } = ref.current?.getBoundingClientRect() ?? ({} as DOMRect); - return [ref, domRect]; + return { width, height }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [resizeCounter]); + + const getPosition = useCallback(() => { + const { left = 1, right = 1, top = 1, bottom = 1 } = ref.current?.getBoundingClientRect() ?? ({} as DOMRect); + + return { left, right, top, bottom }; + }, []); + + return [ref, size, getPosition]; }