Skip to content

Upgrade drag-out to a native drag session with real multi-file payloads - #97

Open
alvst wants to merge 1 commit into
momenbasel:mainfrom
alvst:alvie/pr-drag-clips-out
Open

Upgrade drag-out to a native drag session with real multi-file payloads#97
alvst wants to merge 1 commit into
momenbasel:mainfrom
alvst:alvie/pr-drag-clips-out

Conversation

@alvst

@alvst alvst commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #73, which added drag-out via SwiftUI's .onDrag. That API hands over a single payload and gives the bar no visibility into where the drag actually is, which caps what drag-out can do. This swaps in a native NSDraggingSession and fixes the capture-side gap underneath it.

What changed

  • ClipDragSource replaces .onDrag for every clip type. Tracking the drag's position on screen is what lets the bar stay open while a drag is still hovering over it — dragging onto a Pinboard tab, for instance — and only get out of the way once the drag has genuinely left the bar's window for whatever is underneath.
  • ClipDragProvider builds the pasteboard payload per clip type: one file URL per item for multi-file .file clips, so they drag out as that many items, matching Finder's own multi-selection hand-off. Everything else (text, rich text, links, colors, images) is a single NSPasteboardItem built directly rather than through NSItemProvider, which isn't NSPasteboardWriting-conformant outside SwiftUI's private .onDrag bridging.
  • Capture now records every file in a multi-file copy, not just the first. Some sources put each copied file in its own pasteboard item; others only fill the legacy NSFilenamesPboardType array and leave a single URL item behind. The monitor reads both and keeps whichever list is longer.

Screenshots

Before:
00-baseline screenshots bar.png

After:
16-drag-clips-out screenshots after.png

The capture half has no visual delta — it changes what a multi-file clip records, not how it draws. Its effect is only observable as the drag above producing several files instead of one.

Notes for review

  • The capture change is what makes the rest testable, not scope creep: a clip that only ever recorded one file could never drag out as several, so the multi-item hand-off had nothing to exercise it. Copying three files in Finder and dragging the clip out now produces three files.
  • Verified intact after the switch away from .onDrag: multi-select taps still reproduce, right-click/context menu still works, and VoiceOver actions are unaffected (accessibility actions don't route through the overlay's hitTest).
  • No dependencies; merges in any order.

This feature should be bundled into v2.

Part of #80.

Adds a native NSDraggingSession-based drag source (ClipDragSource) used
for every clip type, replacing SwiftUI's .onDrag - a single-payload API
with no visibility into where the drag actually is on screen. Tracking
that position is what lets the bar stay open while a drag is still
hovering over it (e.g. onto a Pinboard tab) and only drop once the drag
has genuinely left the bar's window for whatever's underneath.

ClipDragProvider builds the pasteboard payload per clip type: one file
URL per item for multi-file .file clips (dragging out as that many
items, matching Finder's own multi-selection hand-off), or a single
NSPasteboardItem for everything else (text, rich text, links, colors,
images) built directly rather than through NSItemProvider, since
NSItemProvider isn't NSPasteboardWriting-conformant outside of
SwiftUI's private .onDrag bridging.

Capture now records every file in a multi-file copy, not just the first.
Some sources put each copied file in its own pasteboard item while others
only fill the legacy NSFilenamesPboardType array and leave a single URL
item behind, so the monitor reads both and keeps whichever list is
longer. Without that half, a clip that only ever recorded one file could
never drag out as several, and the multi-item hand-off above would have
nothing to exercise it.
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