Skip to content

feat: public read API on ClipboardBinding#24480

Draft
Artur- wants to merge 7 commits into
mainfrom
feature/clipboard-read
Draft

feat: public read API on ClipboardBinding#24480
Artur- wants to merge 7 commits into
mainfrom
feature/clipboard-read

Conversation

@Artur-
Copy link
Copy Markdown
Member

@Artur- Artur- commented May 29, 2026

Clipboard.onClick(button).read(onPayload, onError) — and the
single-field convenience variants readText / readHtml — make the
read side reachable from the same binding entry point as the write
side, instead of forcing callers to instantiate the internal
ReadFromClipboardAction themselves.

ClipboardPayload moves out of trigger.internal into the public
clipboard package so it can sit in the read methods' signatures
without leaking an internal type, mirroring how ClipboardContent
already lives there for the write side. The private bind() helper
on ClipboardBinding is generalised to accept any Action so it can
route both write and read actions.

The read IT view is restructured into headed sections and gains
two new buttons (read-text, read-html); the IT picks up matching
scenarios that use the existing resolving-clipboard shim.

Artur- added 7 commits May 29, 2026 18:57
Adds writeImage(Component) — fire-and-forget and observed flavours — on
ClipboardBinding, plus image(Component) on ClipboardContent for the
multi-format path. The source can be any rasterisable image
({@code image/png}, {@code image/jpeg}, {@code image/svg+xml}, ...) with
intrinsic dimensions; cross-origin sources need
{@code crossorigin="anonymous"} on the {@code <img>} plus matching CORS
headers, otherwise the canvas is tainted and the write fails.

Internals:
  - ImageBlobInput extends Action.Input<Object>; its toJs yields the
    source <img> element verbatim.
  - WriteToClipboardAction gains a third (image) slot; the rendered
    helper call is writePayload($0(event), $1(event), $2(event)).
  - The TS helper writeClipboardPayload takes an HTMLImageElement third
    argument and re-encodes it via imageToPngBlob (canvas + toBlob).
    The resulting Promise<Blob> is fed directly to ClipboardItem so the
    navigator.clipboard.write call stays synchronous inside the user
    gesture — Safari otherwise loses activation on the first await.

Tests cover the image/png slot and the multi-format case with all three
slots together.
…ardAction

Restores the original 2-arg (text, html) and 4-arg observed constructors
that main had, and adds matching 1-arg (image) and 3-arg observed image
constructors. The 3-arg / 5-arg multi-format constructors stay as the
underlying implementation that the dedicated overloads delegate into
via this(...). Callers in the typical text-only, html-only, or image-only
shapes no longer need to pass null placeholders for the unused slots.

ClipboardBinding's write* methods, SignalInput/LiteralInput Javadoc
snippets, SignalInputTest and TriggerWriteToClipboardView are all
adjusted to use the dedicated overloads.
ClipboardContent is now a passive data holder with public slot getters;
WriteToClipboardAction gains constructors that accept a ClipboardContent
and read its slots. The text+html and image dedicated constructors
delegate into private 3-arg / 5-arg primitives, so the previously
public multi-format Action.Input constructors disappear from the API
surface.

ClipboardBinding.write(content[, callbacks]) now constructs the action
as new WriteToClipboardAction(content[, …]). The two existing test
cases that called the input-based 3-arg constructor directly now go
through ClipboardContent.
Adds writeImage(DownloadHandler) and its observed counterpart on
ClipboardBinding so server-defined image bytes can be copied to the
clipboard without the caller having to add a hidden Image to the page
themselves. The overload appends a display:none <img> child to the
trigger host, bound to the handler via the same setAttribute path
Image.setSrc(DownloadHandler) uses, then routes it through
ImageBlobInput.

ImageBlobInput gains an Element-accepting constructor so the binding
can hand it the freshly built <img> element without wrapping it in a
Component.

The browser begins fetching the image as soon as the binding is set
up, so the bytes are typically decoded before the user clicks. If the
click races the load, ImageBlobInput's canvas converter falls back to
the <img>'s load event before drawing.
Adds three IT scenarios to TriggerWriteToClipboardView/IT:
  - writeImage(Image) with an in-DOM data-URL <img>
  - write(ClipboardContent.text + image) packing both into one
    ClipboardItem
  - writeImage(DownloadHandler) with a server-served PNG generated
    at view-class load via ImageIO

The recording shim in the IT awaits Promise<Blob> entries from the
ClipboardItem and normalises them to {type, size}, so the assertions
can inspect the resulting image/png blob without dealing with binary
content.
Restructures TriggerWriteToClipboardView into headed sections, each
with a one-line description of what should land in the clipboard so a
manual tester can paste into an external app and verify. Adds:
  - visible 32x32 image sources (was 4x4; too small to see)
  - a distinct blue image for writeImage(DownloadHandler), so a
    pasted result makes it obvious which button was used
  - a "Copy text + html + image" button exercising all three slots in
    one ClipboardItem, with a matching IT case
Clipboard.onClick(button).read(onPayload, onError) — and the
single-field convenience variants readText / readHtml — make the
read side reachable from the same binding entry point as the write
side, instead of forcing callers to instantiate the internal
ReadFromClipboardAction themselves.

ClipboardPayload moves out of trigger.internal into the public
clipboard package so it can sit in the read methods' signatures
without leaking an internal type, mirroring how ClipboardContent
already lives there for the write side. The private bind() helper
on ClipboardBinding is generalised to accept any Action so it can
route both write and read actions.

The read IT view is restructured into headed sections and gains
two new buttons (read-text, read-html); the IT picks up matching
scenarios that use the existing resolving-clipboard shim.
@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown

Test Results

 1 430 files  ± 0   1 430 suites  ±0   1h 26m 58s ⏱️ + 2m 14s
10 068 tests +16  10 000 ✅ +16  68 💤 ±0  0 ❌ ±0 
10 540 runs  +16  10 471 ✅ +16  69 💤 ±0  0 ❌ ±0 

Results for commit 9f2f2c5. ± Comparison against base commit b238ec1.

@mshabarov mshabarov self-requested a review June 1, 2026 11:35
@Artur- Artur- marked this pull request as draft June 1, 2026 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant