diff --git a/package.json b/package.json index 73588fb..b3724fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "my-weekly-todo-list", - "version": "1.73.0", + "version": "1.73.1", "description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view", "main": "index.js", "scripts": { diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index b50cb82..48a5dbe 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -3969,8 +3969,25 @@ export default function WeeklyView() { }; }, []); // eslint-disable-line react-hooks/exhaustive-deps - // Touch long-press drag-to-create: touchmove + touchend on document - useEffect(() => { + // Touch long-press drag-to-create: touchmove + touchend handlers + // Stored as refs so the onTouchStart can attach/detach them only when needed + // (avoids a permanent non-passive touchmove listener that breaks scroll/sticky) + const touchMoveHandlerRef = useRef<((e: TouchEvent) => void) | null>(null); + const touchEndHandlerRef = useRef<(() => void) | null>(null); + const cleanupTouchListeners = useCallback(() => { + if (touchMoveHandlerRef.current) { + document.removeEventListener('touchmove', touchMoveHandlerRef.current); + touchMoveHandlerRef.current = null; + } + if (touchEndHandlerRef.current) { + document.removeEventListener('touchend', touchEndHandlerRef.current); + document.removeEventListener('touchcancel', touchEndHandlerRef.current); + touchEndHandlerRef.current = null; + } + }, []); + const attachTouchListeners = useCallback(() => { + cleanupTouchListeners(); + const handleTouchMove = (e: TouchEvent) => { const lp = touchLongPressRef.current; if (!lp) return; @@ -3981,6 +3998,7 @@ export default function WeeklyView() { if (Math.abs(touch.clientX - lp.startX) > 10 || Math.abs(touch.clientY - lp.startY) > 10) { clearTimeout(lp.timerId); touchLongPressRef.current = null; + cleanupTouchListeners(); } return; } @@ -4010,6 +4028,7 @@ export default function WeeklyView() { clearTimeout(lp.timerId); touchLongPressRef.current = null; } + cleanupTouchListeners(); const drag = slotDragRef.current; slotDragRef.current = null; @@ -4038,16 +4057,12 @@ export default function WeeklyView() { }); }; - // Use passive: false for touchmove so we can preventDefault after long-press activates + touchMoveHandlerRef.current = handleTouchMove; + touchEndHandlerRef.current = handleTouchEnd; document.addEventListener('touchmove', handleTouchMove, { passive: false }); document.addEventListener('touchend', handleTouchEnd); document.addEventListener('touchcancel', handleTouchEnd); - return () => { - document.removeEventListener('touchmove', handleTouchMove); - document.removeEventListener('touchend', handleTouchEnd); - document.removeEventListener('touchcancel', handleTouchEnd); - }; - }, []); // eslint-disable-line react-hooks/exhaustive-deps + }, [cleanupTouchListeners]); // Handle recurring event drag confirm (this/all) const handleRecurringDragConfirm = async (editMode: 'this' | 'future' | 'all') => { @@ -7980,6 +7995,7 @@ export default function WeeklyView() { slot: slotName, activated: false, }; + attachTouchListeners(); }} onDragOver={(e) => !isProtected && !isOccupiedByTask &&