Skip to content

fix(drag): end HTML5 drags like a browser and support drop offsets in drag_to - #343

Merged
route merged 2 commits into
mainfrom
feat/drag-to-offsets
Oct 16, 2026
Merged

route merged 2 commits into
mainfrom
feat/drag-to-offsets

Conversation

@route

@route route commented Oct 16, 2026

Copy link
Copy Markdown
Member

Fixes #325.

Summary

  • drag.js ends a drag like a browser. The target gets drop if it accepted the drag, otherwise dragleave, never both. The script ported from Capybara fired dragleave right before drop. Pragmatic drag and drop reads a dragleave without relatedTarget as the drag leaving the window, clears its drop targets and drops onto nothing.
  • Two bugs the port kept on purpose are fixed: rectPt.top in pointOnRect was always undefined (so the entry point was NaN when coming from above or below a target), and key leaked as a global.
  • drag_to(other, x:, y:, offset:) drops at an offset from the target. It works like click: both x: and y: are required, and the offset is measured from the center or the top left, following offset: or Capybara.w3c_click_offset. This works on both the HTML5 simulation and the mouse path, so drop targets that tell the upper half from the lower one can be driven.

The JS simulation stays the default for draggable elements, same as Capybara. A real Chrome drag is available with html5: false since Ferrum 0.19.1 (rubycdp/ferrum#646).

Capybara's shared spec #drag_to HTML5 should preserve clientX/Y from last dragover event requires DragLeave together with Drop, so it's skipped with that reason.

Verification

Against a page using Pragmatic drag and drop with closest-edge hitboxes:

Before After
drag_to(c) dropped on nothing dropped on c
drag_to(c, x: 0, y: -20) / y: 20 not supported top / bottom
same with html5: false not supported top / bottom
  • New specs in spec/features/session_spec.rb with spec/support/views/html5_drag.erb. The accept-target spec fails without the fix, and the 6 offset specs fail without the feature.
  • Full suite: 1862 examples, 1 failure, 17 pending. The failure, driver_spec.rb:1783 "can get the frames url", also fails on main with Ferrum 0.19.1, which no longer passes --disable-web-security (fix(browser): drop --disable-web-security from default Chrome flags ferrum#649). It needs a separate fix.

route added 2 commits October 16, 2026 17:49
…owser

drag.js fired dragleave right before drop on the target, so Pragmatic drag and drop treated the drag as having left
the window and dropped onto nothing. Also fix the entry point from above or below a target and the leaked key global.
Capybara's shared spec that requires dragleave alongside drop is skipped.
Measured from the target's center or top left like click, following offset: or Capybara.w3c_click_offset, on both
the HTML5 and the mouse path, so drop targets that tell the upper half from the lower one can be driven [#325].
@route
route merged commit 989d444 into main Oct 16, 2026
7 checks passed
@route
route deleted the feat/drag-to-offsets branch October 16, 2026 16:42
navidemad added a commit to navidemad/capybara-lightpanda that referenced this pull request Oct 17, 2026
HTML5_DRAG_JS fired dragleave on the target and then drop when the last
dragover was cancelled. A browser fires drop if the target accepted the
drag, otherwise dragleave. Pragmatic drag and drop reads a
relatedTarget-less dragleave as the drag leaving the window, clears its
drop targets and drops onto nothing.

Also fixes two port bugs kept on purpose until now: pointOnRect read
rectPt.top (a DOMPoint has none, so a target entered from above or below
got the source's center as entry point), and key leaked as a global.

Ports rubycdp/cuprite#343. Capybara's shared spec 'should preserve
clientX/Y from last dragover event' asserts both events, so it is skipped
with that reason.

Co-authored-by: Claude <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.

drag_to(html5: true) doesn't drive Pragmatic drag-and-drop; CDP drag interception would

1 participant