eleven / ocho Public

mac: only the visible space's feed is a drop target — hidden panes swallowed drops (#618)

RootView keeps every visited space alive in its ZStack, hidden with
opacity(0) + allowsHitTesting(false) — but AppKit's drag-destination
targeting consults neither, so once a second space had been opened, a
hidden pane could claim a drop-to-attach, return true (green + badge),
and stage the file invisibly in the OTHER space's composer. Gate the
feed's onDrop on isActive the same way the default-command case already
empties the type list, mirroring the swipe monitor's existing
hidden-panes guard.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 6e90cda91459bed6d9b9f65ee15364731cef7c8e parent 3f3e96e
1 file changed, +7 −2
  • ios/LChatMac/NativeFeedView.swift +7 −2
diff --git a/ios/LChatMac/NativeFeedView.swift b/ios/LChatMac/NativeFeedView.swift
index c79aa33..8b43ba7 100644
--- a/ios/LChatMac/NativeFeedView.swift
+++ b/ios/LChatMac/NativeFeedView.swift
@@ -430,8 +430,13 @@ struct NativeFeedView: View {
// accept list bounced them), movies. No overlay chrome: the system's
// own + drag badge is the affordance (Paul's call — idiomatic macOS).
// In a default-command thread (text-only surface) the type list is
- // empty, so the feed is not a drop target at all.
- .onDrop(of: defaultCommand == nil ? Self.droppableTypes : [], isTargeted: nil) { providers in
+ // empty, so the feed is not a drop target at all. Same for a HIDDEN
+ // pane: RootView keeps every visited space alive in its ZStack, and
+ // AppKit's drag targeting ignores opacity/allowsHitTesting — without
+ // this gate the hidden space claims the drop and stages the file
+ // invisibly in ITS composer (the swipe monitor learned this first).
+ .onDrop(of: (isActive && defaultCommand == nil) ? Self.droppableTypes : [], isTargeted: nil) { providers in
+ guard isActive else { return false }
stageProviders(providers)
return true
}