Skip to content

[P2-36] Add portable clipboard and data-transfer APIs #42

Description

@phranck

Problem

PasteButton, ShareLink, dropDestination, pasteDestination, onCopyCommand, and related portable data-transfer semantics have no owner. Issue #5 may consume copy/paste actions but must not create a second payload or clipboard stack.

Proposed solution

  • Add environment-injected clipboard, share, and data-transfer services for portable text, byte, and file payloads.
  • Add applicable SwiftUI PasteButton, ShareLink, copy/cut/paste command, pasteDestination, and dropDestination APIs with exact signatures or reviewed terminal exceptions.
  • Reuse keyed identity, data flow, and control styles; integrate drag/drop with the shared input and hit-test model.
  • Define Swift 6.0 concurrency, cancellation, Sendable, and error semantics for asynchronous payload loading, decoding, and sharing.
  • Classify Apple-only item-provider and UI integrations explicitly instead of leaking them into the portable API.
  • On macOS, expose the exact CoreTransferable.Transferable, UniformTypeIdentifiers.UTType, and applicable NSItemProvider contracts. Swift 6.0.3 Linux provides none of those modules/types, so Linux uses a reviewed availability exception plus TUIkit-owned portable payload protocols; do not recreate Apple framework types under Apple names.
  • Adapt ShareLink/SharePreview to a terminal destination picker backed by environment-registered share handlers. Absence, cancellation, success, and handler errors must be explicit; no Apple share-sheet behavior is implied.
  • Keep gesture recognition/hit testing in [P1-35] Add terminal input, hit-testing, and gesture semantics #41, clipboard/share/data-transfer payloads and Drop* here, shortcut resolution in [P2-28] Add terminal accessibility, search, refresh, and application actions #33, and document codecs/filesystem workflows in [P2-37] Add portable file and document workflows #43.
  • Preserve the exact per-platform availability of copyable, cuttable, and pasteDestination, which already exist on macOS 13 and gain additional platform surface in OS 27. Only DropSession.reorderDestination is wholly OS-27-only. Reorder behavior integrates with container ownership in [P1-19] Align List, Section, Menu, Table, and navigation containers with SwiftUI #24.
  • Replace the existing blocking pbcopy/pbpaste/xclip/xsel calls and silent failures with the injected service and structured diagnostics.

Acceptance criteria

  • Representative supported APIs compile under Swift 6.0 and map to one manifest owner and contract.
  • Copy, paste, and drop round trips preserve declared content types and ordering; share reports deterministic success or error, and unsupported payloads fail explicitly.
  • Services are per app and mockable; no singleton or global clipboard state is introduced.
  • PasteButton and the terminal-adapted ShareLink are real Views with body: some View, never body: Never.
  • Drag/drop target routing uses the committed hit-test tree and cancels cleanly on removal or shutdown.
  • Tests use only injected clipboard/share backends and never read from or mutate the user's real clipboard.
  • Build, tests, SwiftLint strict, and DocC remain warning-free on macOS and Linux.

Dependencies

Depends on runtime #8, event loop #9, stable identity #10, keyed collections #12, core API #17, data flow #18, and modifiers #21. PasteButton follows controls #23; reorder semantics coordinate with #24; drag/drop follows terminal input and hit testing in #41; #5 consumes the shared command actions.

Parallelization

Clipboard/share services and portable payload representation can proceed before drag/drop. PasteButton and drag/drop integrations use separate file groups after their dependencies are ready.

Commit structure

  • Split this issue into small, thematic, independently revertible commits wherever the work can remain coherent.
  • Every commit must build and keep its applicable tests/gates green. Do not commit an intentionally failing regression test; land it with the smallest fix.
  • Keep characterization/fixtures, mechanical renames or moves, semantic changes, and documentation/migration updates separate when each step remains green.
  • The issue boundary is not a commit boundary; multiple commits are expected for independently reversible changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestparallel-readyCan proceed independently of the current critical pathpriority: mediumImportant follow-up after critical and high dependencies

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions