From cf040ff8dd959b927d1fdf105d0bb19dfe95a6c6 Mon Sep 17 00:00:00 2001 From: nmemmert Date: Wed, 12 Aug 2026 09:14:33 -0400 Subject: [PATCH] Fix alternating stroke drop on iPadOS with Apple Pencil MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setPointerCapture/hasPointerCapture is unreliable on iPadOS — Safari sometimes fires pointercancel which releases capture, causing every other stroke's pointermove events to be discarded. Replace with a simple isDrawingRef boolean that is set on pointerdown and cleared on pointerup, avoiding the capture API entirely. Co-Authored-By: Claude Sonnet 4.6 --- src/pages/DrawCanvas.jsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/DrawCanvas.jsx b/src/pages/DrawCanvas.jsx index 291fab0..4439e15 100644 --- a/src/pages/DrawCanvas.jsx +++ b/src/pages/DrawCanvas.jsx @@ -20,6 +20,7 @@ export default function DrawCanvas({ strokes, onStrokesChange, onDone, headerCon const canvasRef = useRef(null); const activeStrokeRef = useRef([]); + const isDrawingRef = useRef(false); // Refs prevent stale closures in stable callbacks const strokesRef = useRef(strokes); @@ -69,15 +70,14 @@ export default function DrawCanvas({ strokes, onStrokesChange, onDone, headerCon const onPointerDown = useCallback((e) => { if (e.pointerType === 'touch') return; - e.preventDefault(); - canvasRef.current?.setPointerCapture(e.pointerId); + isDrawingRef.current = true; activeStrokeRef.current = [getPoint(e)]; render(); }, [getPoint, render]); const onPointerMove = useCallback((e) => { if (e.pointerType === 'touch') return; - if (!canvasRef.current?.hasPointerCapture(e.pointerId)) return; + if (!isDrawingRef.current) return; e.preventDefault(); const pt = getPoint(e); activeStrokeRef.current = [...activeStrokeRef.current, pt]; @@ -95,6 +95,8 @@ export default function DrawCanvas({ strokes, onStrokesChange, onDone, headerCon const onPointerUp = useCallback((e) => { if (e.pointerType === 'touch') return; + if (!isDrawingRef.current) return; + isDrawingRef.current = false; const pts = activeStrokeRef.current; if (drawToolRef.current !== 'eraser' && pts.length > 1) { onStrokesChangeRef.current([