Skip to content

fix(ios): deliver canvas finger-drag (on_drag) — parity with Android#47

Merged
GenericJam merged 2 commits into
masterfrom
feat/ios-canvas-drag-gesture
Jun 21, 2026
Merged

fix(ios): deliver canvas finger-drag (on_drag) — parity with Android#47
GenericJam merged 2 commits into
masterfrom
feat/ios-canvas-drag-gesture

Conversation

@GenericJam

Copy link
Copy Markdown
Owner

Problem

On iOS, a Canvas's on_drag handle did nothing. The NIF wires props["on_drag"]
to node.onDrag (mob_nif.m), but the SwiftUI MobCanvasView rendered the draw
ops and attached no drag recognizer, so node.onDrag was never invoked. The
only gesture wiring (mobGestures) covers long-press / double-tap / swipe — not
continuous drag. Net result: finger-drawing worked on Android (MobCanvas had
detectDragGestures) but was dead on iOS.

This surfaced building a finger-drawing screen: drags onto the canvas produced
nothing on iOS.

Fix

Add a canvas-scoped DragGesture(minimumDistance: 0) to MobCanvasView that
calls node.onDrag(dx, dy, x, y, phase) with began / dragging / ended
phases (a @State flag distinguishes the first sample). The Canvas frame is
sized to the declared logical units (canvasWidth/canvasHeight) and draw ops
are drawn in that same space, so the gesture's .local location is already in
canvas coordinates — no pixel→logical rescale is needed (unlike Android,
where Compose hands back pixels). Only attached when node.onDrag != nil, so
non-interactive canvases are unaffected.

Verification

Verified on a physical iPhone (iOS 26.5) via a Sloppy Joe finger-drawing
screen — a canvas plus a color picker and thickness control:

  • real-finger drags route through node.onDragmob_send_drag
    {:drag, tag, %{x, y, dx, dy, phase}} and render strokes live;
  • per-stroke color and width are preserved;
  • taps on the color/thickness buttons and drags on the canvas coexist.

Pairs with the Android side, which already had this via detectDragGestures.

Docs

CHANGELOG.md [Unreleased] → Fixed.

🤖 Generated with Claude Code

GenericJam and others added 2 commits June 20, 2026 20:40
SwiftUI MobCanvasView rendered draw ops but attached no drag recognizer, so a
canvas's on_drag handle (wired through the NIF to node.onDrag) was never
invoked — continuous finger-drag was dead on iOS while Android's MobCanvas had
detectDragGestures.

Add a canvas-scoped DragGesture(minimumDistance: 0) that calls node.onDrag with
began/dragging/ended phases. The Canvas frame is sized to the declared logical
units and draw ops use that same space, so the gesture's local-space location
is already in canvas coordinates — no pixel→logical rescale (unlike Android).

Verified on a physical iPhone (iOS 26.5): a finger-drawing screen with a color
picker and thickness control routes drags and renders strokes correctly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nce, test on_drag wiring

Review follow-ups on the canvas on_drag fix (#47):
- Flip the dragging @State flag only on the first sample, so a fast drag
  does not invalidate MobCanvasView on every move.
- Document that minimumDistance: 0 is a deliberate divergence from Android's
  touch-slop (a stationary tap registers as a dot on iOS).
- Add renderer_test coverage for on_drag handle wiring, which was untested
  and is the prop the Swift gesture depends on. The drag-event/phase
  passthrough is already covered by event/integration_test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@GenericJam GenericJam merged commit a033f15 into master Jun 21, 2026
4 checks passed
GenericJam added a commit that referenced this pull request Jun 21, 2026
Delivers continuous finger-drag (on_drag) on the iOS Canvas, at parity with
Android, plus the review-follow-up polish and on_drag renderer test coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant