Fix alternating stroke drop on iPadOS with Apple Pencil

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 <noreply@anthropic.com>
This commit is contained in:
nmemmert
2026-08-12 09:14:33 -04:00
parent 0a2def9b60
commit cf040ff8dd
+5 -3
View File
@@ -20,6 +20,7 @@ export default function DrawCanvas({ strokes, onStrokesChange, onDone, headerCon
const canvasRef = useRef(null); const canvasRef = useRef(null);
const activeStrokeRef = useRef([]); const activeStrokeRef = useRef([]);
const isDrawingRef = useRef(false);
// Refs prevent stale closures in stable callbacks // Refs prevent stale closures in stable callbacks
const strokesRef = useRef(strokes); const strokesRef = useRef(strokes);
@@ -69,15 +70,14 @@ export default function DrawCanvas({ strokes, onStrokesChange, onDone, headerCon
const onPointerDown = useCallback((e) => { const onPointerDown = useCallback((e) => {
if (e.pointerType === 'touch') return; if (e.pointerType === 'touch') return;
e.preventDefault(); isDrawingRef.current = true;
canvasRef.current?.setPointerCapture(e.pointerId);
activeStrokeRef.current = [getPoint(e)]; activeStrokeRef.current = [getPoint(e)];
render(); render();
}, [getPoint, render]); }, [getPoint, render]);
const onPointerMove = useCallback((e) => { const onPointerMove = useCallback((e) => {
if (e.pointerType === 'touch') return; if (e.pointerType === 'touch') return;
if (!canvasRef.current?.hasPointerCapture(e.pointerId)) return; if (!isDrawingRef.current) return;
e.preventDefault(); e.preventDefault();
const pt = getPoint(e); const pt = getPoint(e);
activeStrokeRef.current = [...activeStrokeRef.current, pt]; activeStrokeRef.current = [...activeStrokeRef.current, pt];
@@ -95,6 +95,8 @@ export default function DrawCanvas({ strokes, onStrokesChange, onDone, headerCon
const onPointerUp = useCallback((e) => { const onPointerUp = useCallback((e) => {
if (e.pointerType === 'touch') return; if (e.pointerType === 'touch') return;
if (!isDrawingRef.current) return;
isDrawingRef.current = false;
const pts = activeStrokeRef.current; const pts = activeStrokeRef.current;
if (drawToolRef.current !== 'eraser' && pts.length > 1) { if (drawToolRef.current !== 'eraser' && pts.length > 1) {
onStrokesChangeRef.current([ onStrokesChangeRef.current([