Skip to content

fix(editor): make copy/cut/paste work across documents (VCs included) - #543

Open
fortusfederal wants to merge 1 commit into
CoreBunch:mainfrom
fortusfederal:fix/clipboard-visual-component-documents
Open

fortusfederal wants to merge 1 commit into
CoreBunch:mainfrom
fortusfederal:fix/clipboard-visual-component-documents

Conversation

@fortusfederal

Copy link
Copy Markdown

Summary

Copy, cut and paste silently do nothing inside a Visual Component. Paste appears in the context menu (a clipboard entry exists) and then no node is inserted, with no error and no toast.

The clipboard slice reimplements its own page-only "find the active document" lookup (getActivePage) instead of routing through resolveActiveTreeTarget, the VC-aware resolver every other named tree-mutation action shares via mutateActiveTree. Two consequences:

  • Entering Visual Component mode does not clear activePageId (it only stashes it in previousActivePageId), so getActivePage keeps resolving to whichever page was open before — a stale, unrelated document.
  • resolveInsertLocation then looks up the right-clicked node's id in that wrong tree, finds nothing, and returns null. pasteNode sees a null location and aborts.

The slice now resolves through resolveActiveTreeTarget and operates on a NodeTree<PageNode> rather than a Page, so clipboard operations behave identically whichever kind of document is open.

Verification

  • bun run build
  • bun test
  • bun run lint
  • Docker/deployment check — not relevant

Checklist

  • Tests cover behavior changes — clipboardSlice.test.ts
  • Docs — no documented surface changed
  • No compatibility shim was added for old pre-release behavior.
  • No secrets, local databases, uploads, or generated artifacts are included.

🤖 Generated with Claude Code

The clipboard slice reimplemented its own page-only "find the active
document" lookup (getActivePage) instead of routing through
resolveActiveTreeTarget, the VC-aware resolver every other named
tree-mutation action shares via mutateActiveTree. Two consequences:

- Entering Visual Component mode doesn't clear activePageId (only
  stashes it in previousActivePageId), so getActivePage kept resolving
  to whichever page was open before -- a stale, unrelated document.
- resolveInsertLocation then looked up the right-clicked node's id in
  that wrong tree, found nothing, and returned null. pasteNode saw a
  null location and aborted with no error, no toast -- exactly the
  reported symptom (Paste appears in the menu since clipboardEntry is
  a plain boolean unrelated to the active document, but clicking it
  does nothing).
- A second, independent instance of the same bug lived inside the
  actual insert transaction, which looked up the draft target via
  `site.pages.find(...)` -- a Visual Component's tree lives in
  `site.visualComponents`, not `site.pages`, so this line could never
  resolve a VC target even after fixing the first lookup.

Replaced getActivePage with getActiveTree, backed by
resolveActiveTreeTarget, at both call sites (outer resolution +
the draft-side lookup inside the paste transaction). copy/cut/paste
now work identically whether the active document is a page, template,
or Visual Component, matching every other mutation action's routing.

Added regression coverage: paste into a VC tree while it's the active
document, and copy-from-VC / paste-into-page in the other direction.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@fortusfederal
fortusfederal marked this pull request as ready for review September 18, 2026 00:57

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants