Workspace has no clipboard paste support — user can drag/drop or click to browse, but can't paste an image from another app #186

Closed
opened 2026-10-03 23:20:48 +00:00 by Mark · 1 comment
Owner

Finding

grep -rn 'paste\b\|onPaste\|clipboardData' src/ returns 1 hit — a comment in src/components/workspace/threadLibrary.ts:9 about pasting thread library text, not image paste support.

The dropzone supports:

  • Drag and drop an image
  • Click to browse and select from the file picker

It does NOT support:

  • Cmd+V / Ctrl+V to paste an image from the clipboard
  • Right-click → "Paste image" (some browsers offer this on the dropzone)

A user who screenshots a sketch in another app and wants to digitize it has to:

  1. Save the screenshot to disk
  2. Open the Workspace dropzone
  3. Click "browse" and find the screenshot

The first two steps are unnecessary — the browser's clipboard API is straightforward, and most image-aware web apps (Google Docs, Notion, Figma) support Cmd+V.

Where

src/components/workspace/CanvasArea.tsx:320-345 — the dropzone
src/components/workspace/useWorkspace.ts — handleFileChange handler

Suggested fix shape

Add a paste event listener on the workspace's document when the user is in the empty state (no image uploaded):

useEffect(() => {
  if (state.appState !== 'empty') return;
  const handler = (e: ClipboardEvent) => {
    const items = e.clipboardData?.items;
    if (!items) return;
    for (const item of items) {
      if (item.type.startsWith('image/')) {
        const blob = item.getAsFile();
        if (blob) {
          handleFileUpload(blob);
          e.preventDefault();
          return;
        }
      }
    }
  };
  document.addEventListener('paste', handler);
  return () => document.removeEventListener('paste', handler);
}, [state.appState]);

The handleFileUpload is the same function the dropzone calls. The handler is only registered when the dropzone is visible (appState='empty').

Optionally: add a small "Tip" line under the dropzone: "Or paste an image with Cmd+V" — discoverable hint.

Severity

Low. The user can use the file picker. Power users expect paste.

Discovered by

Gap analysis (2026-10-02) of workspace upload affordances.

  • #148 (closed) — Gallery upload accept list excludes BMP. The dropzone's upload path is the same; the paste handler is a sibling feature.
## Finding `grep -rn 'paste\b\|onPaste\|clipboardData' src/` returns 1 hit — a comment in `src/components/workspace/threadLibrary.ts:9` about pasting thread library text, not image paste support. The dropzone supports: - Drag and drop an image - Click to browse and select from the file picker It does NOT support: - Cmd+V / Ctrl+V to paste an image from the clipboard - Right-click → "Paste image" (some browsers offer this on the dropzone) A user who screenshots a sketch in another app and wants to digitize it has to: 1. Save the screenshot to disk 2. Open the Workspace dropzone 3. Click "browse" and find the screenshot The first two steps are unnecessary — the browser's clipboard API is straightforward, and most image-aware web apps (Google Docs, Notion, Figma) support Cmd+V. ## Where `src/components/workspace/CanvasArea.tsx:320-345` — the dropzone `src/components/workspace/useWorkspace.ts` — handleFileChange handler ## Suggested fix shape Add a `paste` event listener on the workspace's document when the user is in the `empty` state (no image uploaded): ```ts useEffect(() => { if (state.appState !== 'empty') return; const handler = (e: ClipboardEvent) => { const items = e.clipboardData?.items; if (!items) return; for (const item of items) { if (item.type.startsWith('image/')) { const blob = item.getAsFile(); if (blob) { handleFileUpload(blob); e.preventDefault(); return; } } } }; document.addEventListener('paste', handler); return () => document.removeEventListener('paste', handler); }, [state.appState]); ``` The `handleFileUpload` is the same function the dropzone calls. The handler is only registered when the dropzone is visible (appState='empty'). Optionally: add a small "Tip" line under the dropzone: "Or paste an image with Cmd+V" — discoverable hint. ## Severity Low. The user can use the file picker. Power users expect paste. ## Discovered by Gap analysis (2026-10-02) of workspace upload affordances. ## Related - #148 (closed) — Gallery upload accept list excludes BMP. The dropzone's upload path is the same; the paste handler is a sibling feature.
Author
Owner

Fixed in 1f5ca57 (fix(#186): workspace dropzone accepts pasted images (Cmd/Ctrl+V)).

  • useWorkspace.ts: window-level paste listener registered while state.appState === 'empty'. Walks e.clipboardData.items, picks the first image/* entry, hands the resulting File to the existing handleFileUpload so the MIME allowlist, 20MB cap, filename derivation, and toast messaging are reused unchanged from the dropzone / file-picker flow. Listener tears down on appState change so a stale paste can't double-fire on a populated workspace.
  • CanvasArea.tsx: added a discoverable hint line "or paste an image with ⌘V / Ctrl+V" under the existing "or click to browse" copy.
  • issue-186.test.ts: 5 new tests — paste(image/*) uploads, text-only clipboard is a no-op, mixed clipboard picks the first image, leaving empty state removes the listener, paste during 'digitizing' is a no-op.

Verified locally: tsc -p tsconfig.json --noEmit clean, eslint clean on the changed files, vitest run 833 passed / 3 pre-existing EditorCanvas failures unrelated to this work.

Fixed in 1f5ca57 (`fix(#186): workspace dropzone accepts pasted images (Cmd/Ctrl+V)`). - `useWorkspace.ts`: window-level `paste` listener registered while `state.appState === 'empty'`. Walks `e.clipboardData.items`, picks the first `image/*` entry, hands the resulting File to the existing `handleFileUpload` so the MIME allowlist, 20MB cap, filename derivation, and toast messaging are reused unchanged from the dropzone / file-picker flow. Listener tears down on appState change so a stale paste can't double-fire on a populated workspace. - `CanvasArea.tsx`: added a discoverable hint line "or paste an image with ⌘V / Ctrl+V" under the existing "or click to browse" copy. - `issue-186.test.ts`: 5 new tests — paste(image/*) uploads, text-only clipboard is a no-op, mixed clipboard picks the first image, leaving empty state removes the listener, paste during 'digitizing' is a no-op. Verified locally: `tsc -p tsconfig.json --noEmit` clean, eslint clean on the changed files, `vitest run` 833 passed / 3 pre-existing EditorCanvas failures unrelated to this work.
Mark closed this issue 2026-10-03 23:35:50 +00:00
Sign in to join this conversation.
No description provided.