3.2 KiB
manager/helpers.ts
Purpose
Pure helpers shared between manager.ts and operations.ts. Keeps both
files under the line budget by housing the navigator / window resolution,
the structured failure builder, the focus-error detector, and the
ClipboardItem build + read pipelines in a single, side-effect-free
module that tests can exercise directly.
Features
resolveNavigator(nav?)— caller, global, or empty shim.resolveWindow(win?)— caller, global, orundefined.failure(code, message, method)— typedClipboardResultfailure.isFocusError(cause)— detects the canonical focus-required rejection.buildClipboardItems(data)— MIME →Blobmap forClipboardItem.readClipboardItems(items, sanitizer?)— pulls text / html / image / blobs out of a list ofClipboardIteminstances.
Usage: Basic
import { failure, CLIPBOARD_CODES } from "@suaveplan/clipboard";
const r = failure(CLIPBOARD_CODES.NO_CONTENT, "empty", "api");
Usage: Advanced
import {
buildClipboardItems,
readClipboardItems,
} from "@suaveplan/clipboard";
const items = buildClipboardItems({
text: "hello",
html: "<b>hi</b>",
image: pngBlob,
blobs: { "application/json": jsonBlob },
});
const clipboardItem = new ClipboardItem(items);
await navigator.clipboard.write([clipboardItem]);
// Round-trip back:
const read = await navigator.clipboard.read();
const data = await readClipboardItems(read, (html) => html.trim());
API Reference
resolveNavigator(nav?: ClipboardNavigator): ClipboardNavigator
Returns nav when defined, otherwise the global navigator, otherwise
the empty object {}.
resolveWindow(win?: ClipboardWindowLike): ClipboardWindowLike | undefined
Returns win when defined, otherwise the global window, otherwise
undefined.
failure<T>(code, message, method): ClipboardResult<T>
Returns { success: false, error: message, code, method }. Generic over
T so call sites compose with their own result types.
isFocusError(cause: unknown): boolean
Returns true when cause is an Error whose name === "NotAllowedError"
and whose message (case-insensitively) contains "focus". The browser
signals "Clipboard needs page focus" with this exact shape.
buildClipboardItems(data: ClipboardData): Record<string, Blob>
Builds a MIME → Blob map for new ClipboardItem(...). Skips empty
text and html. Defaults a typeless image blob to image/png.
readClipboardItems(items, sanitizer?): Promise<ClipboardData>
Iterates every entry of every ClipboardItem, populating text,
html, image, and blobs. The first image-typed entry wins. The
sanitizer (when supplied) is applied to the raw text/html payload
before returning.
Implementation Notes
The helpers are intentionally side-effect-free and free of telemetry
calls so the same code runs from runCopyText, runCopyRich, etc.,
without double-recording counters. buildClipboardItems and
readClipboardItems are mirror images of each other — every MIME slot
that buildClipboardItems writes is read back by readClipboardItems
into the same ClipboardData shape. The focus-error detector matches
both Chromium ("Document is not focused.") and WebKit ("Document not
focused.") wording.