The card window's ⌘V drops its picture branch — the attachments header now offers one instead

Raw image data on a card window's ⌘V was a keyboard shortcut with no visible
trigger; the sidebar's Attachments header now grows a quiet control — beside
the existing add affordance, present only while the pasteboard holds a
picture this card could take — that pastes it through the exact seam the
retired branch used (ClipboardStore.pasteImage(intoCard:in:), the board's
"Paste Image into Card" row's own call). The file-URL branch stays on ⌘V; a
Finder copy is still unambiguous. CardBodyTextView's paste-yield mechanism
needed no change at all — it forwards by capability, not by picture-specific
logic, so a screenshot ⌘V with the body editor focused is now a genuine
no-op there, served by the new control instead.

The pasteboard's re-read gains a fourth checkpoint — a window becoming key —
alongside menu-tracking, ⌘-down and app activation: a persistent visible
control has to read true continuously while its window is frontmost, not
only at the instant a menu or chord probes it.

Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
2026-08-09 10:37:55 -04:00
parent 546fd2840f
commit 200fbce276
8 changed files with 343 additions and 49 deletions
+12
View File
@@ -76,6 +76,18 @@ public final class CardAttachments {
/// gesture was issued on (13-native-undo.md Rules two levels).
public var setHeroFile: ((String?) -> Void)?
/// **The header's paste-image affordance's write** filled by the host with `ClipboardStore
/// .pasteImage(intoCard:in:)`, the same call the card window's own V used before the control
/// replaced it, and the board's "Paste Image into Card" context-menu row still uses
/// (04-interactions.md Clipboard, re-ruled 2026-08-09). One import path behind three pointers
/// at it now, none of them a second implementation.
public var pasteImage: (() -> Void)?
/// **Whether the affordance shows at all** filled by the host with `CardPasteImageAffordance
/// .isVisible(clipboard:cardID:in:)`, read fresh on every view evaluation rather than cached, so
/// the control's presence and `pasteImage()`'s success can never disagree.
public var canPasteImage: (() -> Bool)?
public init() {}
// MARK: - Derived