Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
# `fallback/fallback.ts`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Legacy clipboard fallback paths used when `navigator.clipboard` is
unavailable or rejects. Provides a hidden-textarea + `execCommand("copy")`
write path and a paste-event-based read path. Both return the same
`ClipboardResult` shape as the API path so the manager's call sites do
not branch on which mechanism actually ran. The paste-event fallback is
purpose-built for environments — older Safari, embedded WebViews, and
permission-denied contexts — where `navigator.clipboard.readText`
rejects but the user can paste manually.
## Features
- `copyTextFallback(text)` — synchronous textarea + `execCommand` copy.
- `readTextFallback(timeoutMs)` — focus + paste-event capture with a
configurable timeout.
- `dispatchSyntheticPaste(text)` — test helper that fires a synthetic
`paste` event on the most recent hidden host.
- SSR-safe — both copy and read paths return
`CLIPBOARD.DOCUMENT_UNAVAILABLE` when `document` is undefined.
- Off-screen, non-interactive host element so users never see the
textarea visibly steal focus.
## Usage: Basic
```ts
import { copyTextFallback } from "@suaveplan/clipboard";
const result = copyTextFallback("hello");
if (!result.success) {
console.warn("legacy copy failed:", result.code);
}
```
## Usage: Advanced
```ts
import {
readTextFallback,
dispatchSyntheticPaste,
} from "@suaveplan/clipboard";
async function readClipboardWithPasteFallback(): Promise<string | undefined> {
const result = await readTextFallback(2000);
return result.success ? result.data : undefined;
}
// Inside a test harness:
const promise = readTextFallback(500);
queueMicrotask(() => dispatchSyntheticPaste("from-test"));
const result = await promise;
```
## API Reference
### `copyTextFallback(text: string): ClipboardResult<string>`
Stages a hidden `<textarea>` carrying `text`, selects it, runs
`document.execCommand("copy")`, and removes the textarea on cleanup.
Returns `{ success: true, data, method: "fallback" }` on success and a
structured failure with `code: CLIPBOARD.FALLBACK_FAILED` (or
`CLIPBOARD.DOCUMENT_UNAVAILABLE` outside the browser) otherwise.
### `readTextFallback(timeoutMs: number): Promise<ClipboardResult<string>>`
Creates a hidden textarea, focuses it, listens for the first `paste`
event, and resolves with the `text/plain` payload carried by the event.
Resolves with `code: CLIPBOARD.READ_FAILED` if the timeout elapses
first and `code: CLIPBOARD.DOCUMENT_UNAVAILABLE` outside the browser.
### `dispatchSyntheticPaste(text: string): boolean`
Test helper. Locates the most recent hidden host (`textarea[aria-hidden="true"]`)
and dispatches a `paste` ClipboardEvent carrying `text` as `text/plain`.
Returns `true` when a host was found, `false` otherwise.
## Implementation Notes
The hidden textarea is positioned at `-9999px` and given `opacity: 0`
plus `aria-hidden="true"` so assistive technologies skip it. The cleanup
runs in a `finally` block — even if `execCommand` throws, the textarea is
removed. The read fallback tracks a `settled` flag so a duplicate or
post-timeout `paste` event cannot resolve the promise twice. The paste
event may carry a null `clipboardData` on some browsers; the module
falls back to an empty string in that case rather than rejecting, since
"clipboard contained nothing" is a valid outcome. The synthetic-paste
helper is exported to keep tests deterministic — production code never
calls it.