Implement Finder file drops
Files from Finder land on the board per 04-interactions.md § Drag & drop: - Dropped on a card, they copy into its attachments/ (any type, multi-file), the face highlighting while hovered; the hovered card is resolved by hit-testing the same analytic masonry frames the card zones are built from, so attach-beats-create adds no drop region and cannot drift from the dispatch. - Dropped on lane empty space, one card per file — filename minus extension as the title (a blank stem omits the key), fresh GUID, rank at the drop position through the ordinary insertion machinery, the file attached — all in one bracket; a failed import removes the just-minted card, so creating-then-abandoning never leaves an empty card behind. - Every board drop surface now declares .fileURL beside the two board types (the single-target-dispatch rule); tombstoned surfaces are inert; file sessions ride a distinct session mode with their own watchdog and no hysteresis, leaving the board-drag machinery untouched. - Also: four empty fixture directories pinned with .keep files so git preserves them, and a test-only visibility fix in DragSessionTests. 811 unit tests (12 new). Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -125,9 +125,10 @@ struct BoardView: View {
|
||||
.onGeometryChange(for: CGRect.self) { $0.frame(in: .global) } action: { laneDrops.stripFrame = $0 }
|
||||
// **The strip's drop target** — the backdrop, the gaps, the outer margin, and the trash
|
||||
// column's footprint, which is never a landing spot of its own (04-interactions.md ▸ The
|
||||
// trash) and so simply falls through to here. It accepts *both* board types and routes
|
||||
// internally, because single-target dispatch has no fall-through (DRAG-REORDER.md).
|
||||
.onDrop(of: boardDragTypes, delegate: StripDropDelegate(context: dropContext))
|
||||
// trash) and so simply falls through to here. It accepts *every* session type — ours and
|
||||
// external Finder file drags alike — and routes internally, because single-target
|
||||
// dispatch has no fall-through (DRAG-REORDER.md).
|
||||
.onDrop(of: boardDropTypes, delegate: StripDropDelegate(context: dropContext))
|
||||
}
|
||||
.background(boardBackground)
|
||||
// The window-level fallback, *behind* the specific targets: a release over any in-window
|
||||
@@ -135,7 +136,7 @@ struct BoardView: View {
|
||||
// cancel-snapback — the drop lands where the shadows show, which is what the shadows promise.
|
||||
.background {
|
||||
Color.clear
|
||||
.onDrop(of: boardDragTypes, delegate: BoardFallbackDropDelegate(context: dropContext))
|
||||
.onDrop(of: boardDropTypes, delegate: BoardFallbackDropDelegate(context: dropContext))
|
||||
}
|
||||
// **The committed-overlay hold's hand-off** (DRAG-REORDER.md § The committed-overlay hold):
|
||||
// the overlay stands in for an arrangement that is on disk but not yet in the snapshot, and
|
||||
|
||||
Reference in New Issue
Block a user