From 5323710c3116122740e2d877b963d2a9d4775d82 Mon Sep 17 00:00:00 2001 From: Napatchol Thaipanich Date: Thu, 6 Apr 2023 15:36:57 +0700 Subject: [PATCH] feat: resize by arrow --- src/useResizeHandle.ts | 55 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/useResizeHandle.ts b/src/useResizeHandle.ts index ee9f48d..2fcc2d3 100644 --- a/src/useResizeHandle.ts +++ b/src/useResizeHandle.ts @@ -6,6 +6,7 @@ export default function useResizeHandle( ) { const { minWidth = "0px", maxWidth = "100%" } = options || {}; const [dragging, setDragging] = React.useState(false); + const [focusing, setFocusing] = React.useState(false); const [dragOffset, setDragOffset] = React.useState(0); const isTouchEvent = ( event: MouseEvent | TouchEvent @@ -14,6 +15,7 @@ export default function useResizeHandle( (event as TouchEvent).touches && (event as TouchEvent).touches.length ); }; + const isMouseEvent = ( event: MouseEvent | TouchEvent ): event is MouseEvent => { @@ -21,6 +23,7 @@ export default function useResizeHandle( (event as MouseEvent).clientX || (event as MouseEvent).clientX === 0 ); }; + const getClientX = React.useCallback((event: MouseEvent | TouchEvent) => { let clientX; if (isMouseEvent(event)) { @@ -31,13 +34,31 @@ export default function useResizeHandle( } return clientX as number; }, []); + const handleStart = (event: React.MouseEvent | React.TouchEvent) => { const clientX = getClientX(event.nativeEvent); const rect = (event.target as HTMLElement).getBoundingClientRect(); setDragging(true); setDragOffset(rect.width - (clientX - rect.x)); }; + + const handleFocus = () => { + setFocusing(true); + }; + + const handleBlur = () => { + setFocusing(false); + }; + React.useEffect(() => { + function setNewWidth(newWidth: number) { + if (target.current) { + target.current.style.width = `clamp(${minWidth}, ${Math.floor( + newWidth + )}px, ${maxWidth})`; + } + } + function resizeObject(event: MouseEvent | TouchEvent) { if (event.cancelable) { event.preventDefault(); @@ -46,12 +67,10 @@ export default function useResizeHandle( if (target.current && dragging && clientX) { const objectRect = target.current.getBoundingClientRect(); - const newWidth = clientX - objectRect.left + dragOffset; - target.current.style.width = `clamp(${minWidth}, ${Math.floor( - newWidth - )}px, ${maxWidth})`; + setNewWidth(clientX - objectRect.left + dragOffset); } } + function stopResize() { setDragging(false); } @@ -61,6 +80,7 @@ export default function useResizeHandle( document.addEventListener("mouseup", stopResize); document.addEventListener("touchmove", resizeObject, { passive: false }); document.addEventListener("touchend", stopResize); + return () => { document.removeEventListener("mousemove", resizeObject); document.removeEventListener("mouseup", stopResize); @@ -68,13 +88,38 @@ export default function useResizeHandle( document.removeEventListener("touchend", stopResize); }; } + + const onKeyDown = (event: KeyboardEvent) => { + if (target.current) { + const objectRect = target.current.getBoundingClientRect(); + const multiply = event.shiftKey ? (event.altKey ? 1 : 10) : 1; + setNewWidth( + objectRect.width + + (event.key === "ArrowRight" + ? 1 + : event.key === "ArrowLeft" + ? -1 + : 0) * + multiply + ); + } + }; + + if (focusing) { + document.addEventListener("keydown", onKeyDown); + return () => { + document.removeEventListener("keydown", onKeyDown); + }; + } return () => {}; - }, [dragOffset, dragging, getClientX, maxWidth, minWidth, target]); + }, [dragOffset, dragging, getClientX, maxWidth, minWidth, target, focusing]); return { dragging, getDragHandlers: () => ({ onTouchStart: handleStart, onMouseDown: handleStart, + onFocus: handleFocus, + onBlur: handleBlur, }), }; }