From 187b1b39d3daff28dc3ca033536fb2be9d54f830 Mon Sep 17 00:00:00 2001 From: DuckieTM Date: Sat, 8 Mar 2025 13:21:13 +0100 Subject: [PATCH] :up: Update for Draggable Window Moving the touchstart listener to the native DOM element (elementRef.current) and explicitly setting { passive: true } --- .../draggable-window/DraggableWindow.tsx | 198 +++++++----------- 1 file changed, 77 insertions(+), 121 deletions(-) diff --git a/src/common/draggable-window/DraggableWindow.tsx b/src/common/draggable-window/DraggableWindow.tsx index 076f67e..e069bb0 100644 --- a/src/common/draggable-window/DraggableWindow.tsx +++ b/src/common/draggable-window/DraggableWindow.tsx @@ -10,8 +10,7 @@ const POS_MEMORY: Map = new Map(); const BOUNDS_THRESHOLD_TOP: number = 0; const BOUNDS_THRESHOLD_LEFT: number = 0; -export interface DraggableWindowProps -{ +export interface DraggableWindowProps { uniqueKey?: Key; handleSelector?: string; windowPosition?: string; @@ -22,8 +21,7 @@ export interface DraggableWindowProps children?: ReactNode; } -export const DraggableWindow: FC = props => -{ +export const DraggableWindow: FC = props => { const { uniqueKey = null, handleSelector = '.drag-handler', windowPosition = DraggableWindowPosition.CENTER, disableDrag = false, dragStyle = {}, children = null, offsetLeft = 0, offsetTop = 0 } = props; const [ delta, setDelta ] = useState<{ x: number, y: number }>(null); const [ offset, setOffset ] = useState<{ x: number, y: number }>(null); @@ -32,106 +30,73 @@ export const DraggableWindow: FC = props => const [ dragHandler, setDragHandler ] = useState(null); const elementRef = useRef(); - const bringToTop = useCallback(() => - { + const bringToTop = useCallback(() => { let zIndex = 400; - - for(const existingWindow of CURRENT_WINDOWS) - { + for (const existingWindow of CURRENT_WINDOWS) { zIndex += 1; - existingWindow.style.zIndex = zIndex.toString(); } }, []); - const moveCurrentWindow = useCallback(() => - { + const moveCurrentWindow = useCallback(() => { const index = CURRENT_WINDOWS.indexOf(elementRef.current); - - if(index === -1) - { + if (index === -1) { CURRENT_WINDOWS.push(elementRef.current); - } - - else if(index === (CURRENT_WINDOWS.length - 1)) return; - - else if(index >= 0) - { + } else if (index === (CURRENT_WINDOWS.length - 1)) return; + else if (index >= 0) { CURRENT_WINDOWS.splice(index, 1); - CURRENT_WINDOWS.push(elementRef.current); } - bringToTop(); }, [ bringToTop ]); - const onMouseDown = useCallback((event: ReactMouseEvent) => - { + const onMouseDown = useCallback((event: ReactMouseEvent) => { moveCurrentWindow(); }, [ moveCurrentWindow ]); - const onTouchStart = useCallback((event: ReactTouchEvent) => - { + const onTouchDownHandler = useCallback((event: TouchEvent) => { moveCurrentWindow(); }, [ moveCurrentWindow ]); - const startDragging = useCallback((startX: number, startY: number) => - { + const startDragging = useCallback((startX: number, startY: number) => { setStart({ x: startX, y: startY }); setIsDragging(true); }, []); - const onDragMouseDown = useCallback((event: MouseEvent) => - { + const onDragMouseDown = useCallback((event: MouseEvent) => { startDragging(event.clientX, event.clientY); }, [ startDragging ]); - const onTouchDown = useCallback((event: TouchEvent) => - { + const onTouchDown = useCallback((event: TouchEvent) => { const touch = event.touches[0]; - startDragging(touch.clientX, touch.clientY); }, [ startDragging ]); - const onDragMouseMove = useCallback((event: MouseEvent) => - { + const onDragMouseMove = useCallback((event: MouseEvent) => { setDelta({ x: (event.clientX - start.x), y: (event.clientY - start.y) }); }, [ start ]); - const onDragTouchMove = useCallback((event: TouchEvent) => - { + const onDragTouchMove = useCallback((event: TouchEvent) => { const touch = event.touches[0]; - setDelta({ x: (touch.clientX - start.x), y: (touch.clientY - start.y) }); }, [ start ]); - const completeDrag = useCallback(() => - { - if(!elementRef.current || !dragHandler) return; - + const completeDrag = useCallback(() => { + if (!elementRef.current || !dragHandler) return; let offsetX = (offset.x + delta.x); let offsetY = (offset.y + delta.y); - const left = elementRef.current.offsetLeft + offsetX; const top = elementRef.current.offsetTop + offsetY; - if(top < BOUNDS_THRESHOLD_TOP) - { + if (top < BOUNDS_THRESHOLD_TOP) { offsetY = -elementRef.current.offsetTop; - } - - else if((top + dragHandler.offsetHeight) >= (document.body.offsetHeight - BOUNDS_THRESHOLD_TOP)) - { + } else if ((top + dragHandler.offsetHeight) >= (document.body.offsetHeight - BOUNDS_THRESHOLD_TOP)) { offsetY = (document.body.offsetHeight - elementRef.current.offsetHeight) - elementRef.current.offsetTop; } - if((left + elementRef.current.offsetWidth) < BOUNDS_THRESHOLD_LEFT) - { + if ((left + elementRef.current.offsetWidth) < BOUNDS_THRESHOLD_LEFT) { offsetX = -elementRef.current.offsetLeft; - } - - else if(left >= (document.body.offsetWidth - BOUNDS_THRESHOLD_LEFT)) - { + } else if (left >= (document.body.offsetWidth - BOUNDS_THRESHOLD_LEFT)) { offsetX = (document.body.offsetWidth - elementRef.current.offsetWidth) - elementRef.current.offsetLeft; } @@ -139,42 +104,33 @@ export const DraggableWindow: FC = props => setOffset({ x: offsetX, y: offsetY }); setIsDragging(false); - if(uniqueKey !== null) POS_MEMORY.set(uniqueKey, { - x: offsetX, y: offsetY }); - }, [ dragHandler, delta, offset, uniqueKey ]); + if (uniqueKey !== null) POS_MEMORY.set(uniqueKey, { x: offsetX, y: offsetY }); + }, [ dragHandler, delta, offset, uniqueKey ]); - const onDragMouseUp = useCallback((event: MouseEvent) => - { + const onDragMouseUp = useCallback((event: MouseEvent) => { completeDrag(); }, [ completeDrag ]); - const onDragTouchUp = useCallback((event: TouchEvent) => - { + const onDragTouchUp = useCallback((event: TouchEvent) => { completeDrag(); }, [ completeDrag ]); - useEffect(() => - { - const element = (elementRef.current as HTMLElement); - - if(!element) return; + useEffect(() => { + const element = elementRef.current; + if (!element) return; CURRENT_WINDOWS.push(element); - bringToTop(); - if(!disableDrag) - { - const handle = (element.querySelector(handleSelector) as HTMLElement); - - if(handle) setDragHandler(handle); + if (!disableDrag) { + const handle = element.querySelector(handleSelector) as HTMLElement; + if (handle) setDragHandler(handle); } let offsetX = 0; let offsetY = 0; - switch(windowPosition) - { + switch (windowPosition) { case DraggableWindowPosition.TOP_CENTER: element.style.top = 50 + offsetTop + 'px'; element.style.left = `calc(50vw - ${ (element.offsetWidth / 2 + offsetLeft) }px)`; @@ -188,13 +144,10 @@ export const DraggableWindow: FC = props => element.style.left = 50 + offsetLeft + 'px'; break; } - - if(uniqueKey !== null) - { - const memory = POS_MEMORY.get(uniqueKey); - if(memory) - { + if (uniqueKey !== null) { + const memory = POS_MEMORY.get(uniqueKey); + if (memory) { offsetX = memory.x; offsetY = memory.y; } @@ -203,74 +156,77 @@ export const DraggableWindow: FC = props => setDelta({ x: 0, y: 0 }); setOffset({ x: offsetX, y: offsetY }); - return () => - { + return () => { const index = CURRENT_WINDOWS.indexOf(element); - - if(index >= 0) CURRENT_WINDOWS.splice(index, 1); - } + if (index >= 0) CURRENT_WINDOWS.splice(index, 1); + }; }, [ handleSelector, windowPosition, uniqueKey, disableDrag, offsetLeft, offsetTop, bringToTop ]); - useEffect(() => - { - if(!offset && !delta) return; - - const element = (elementRef.current as HTMLElement); - - if(!element) return; - + useEffect(() => { + if (!offset && !delta) return; + const element = elementRef.current; + if (!element) return; element.style.transform = `translate(${ offset.x + delta.x }px, ${ offset.y + delta.y }px)`; element.style.visibility = 'visible'; }, [ offset, delta ]); - useEffect(() => - { - if(!dragHandler) return; - + useEffect(() => { + if (!dragHandler) return; dragHandler.addEventListener(MouseEventType.MOUSE_DOWN, onDragMouseDown); - dragHandler.addEventListener(TouchEventType.TOUCH_START, onTouchDown); + dragHandler.addEventListener(TouchEventType.TOUCH_START, onTouchDown, { passive: true }); - return () => - { + return () => { dragHandler.removeEventListener(MouseEventType.MOUSE_DOWN, onDragMouseDown); dragHandler.removeEventListener(TouchEventType.TOUCH_START, onTouchDown); - } + }; }, [ dragHandler, onDragMouseDown, onTouchDown ]); - useEffect(() => - { - if(!isDragging) return; - + useEffect(() => { + if (!isDragging) return; document.addEventListener(MouseEventType.MOUSE_UP, onDragMouseUp); document.addEventListener(TouchEventType.TOUCH_END, onDragTouchUp); document.addEventListener(MouseEventType.MOUSE_MOVE, onDragMouseMove); document.addEventListener(TouchEventType.TOUCH_MOVE, onDragTouchMove); - return () => - { + return () => { document.removeEventListener(MouseEventType.MOUSE_UP, onDragMouseUp); document.removeEventListener(TouchEventType.TOUCH_END, onDragTouchUp); document.removeEventListener(MouseEventType.MOUSE_MOVE, onDragMouseMove); document.removeEventListener(TouchEventType.TOUCH_MOVE, onDragTouchMove); - } + }; }, [ isDragging, onDragMouseUp, onDragMouseMove, onDragTouchUp, onDragTouchMove ]); - useEffect(() => - { - if(!uniqueKey) return; + useEffect(() => { + const element = elementRef.current; + if (!element) return; + element.addEventListener('touchstart', onTouchDownHandler, { passive: true }); + + return () => { + element.removeEventListener('touchstart', onTouchDownHandler); + }; + }, [ onTouchDownHandler ]); + + useEffect(() => { + if (!uniqueKey) return; const localStorage = GetLocalStorage(`nitro.windows.${ uniqueKey }`); - - if(!localStorage || !localStorage.offset) return; - + if (!localStorage || !localStorage.offset) return; setDelta({ x: 0, y: 0 }); - if(localStorage.offset) setOffset(localStorage.offset); + if (localStorage.offset) setOffset(localStorage.offset); }, [ uniqueKey ]); return ( createPortal( - - { children } - , document.getElementById('draggable-windows-container')) + + {children} + , + document.getElementById('draggable-windows-container') + ) ); -} +}; \ No newline at end of file