Add layer copy/paste and node duplication with layers

Implements two new features:
- Layer copy/paste within canvas using Ctrl+C/V
- Node duplication that preserves all layers

Layer Copy/Paste:
- Added Ctrl+V keyboard shortcut handler for pasting layers
- Intercept keydown events during capture phase to handle before ComfyUI
- Focus canvas when layer is clicked to ensure shortcuts work
- Prevent layers panel from stealing focus on mousedown

Node Duplication:
- Store source node ID during serialize for copy operations
- Track pending copy sources across node ID changes (-1 to real ID)
- Copy canvas state from source to destination in onAdded hook
- Use Map to persist copy metadata through node lifecycle
This commit is contained in:
diodiogod
2026-01-19 17:57:14 -03:00
parent 66cbcb641b
commit 27ad139cd5
6 changed files with 162 additions and 2 deletions

View File

@@ -176,6 +176,9 @@ export class CanvasInteractions {
document.addEventListener('paste', this.onPaste as unknown as EventListener);
// Intercept Ctrl+V during capture phase to handle layer paste before ComfyUI
document.addEventListener('keydown', this.onKeyDown as EventListener, { capture: true });
this.canvas.canvas.addEventListener('mouseenter', this.onMouseEnter as EventListener);
this.canvas.canvas.addEventListener('mouseleave', this.onMouseLeave as EventListener);
@@ -195,6 +198,9 @@ export class CanvasInteractions {
this.canvas.canvas.removeEventListener('keydown', this.onKeyDown as EventListener);
this.canvas.canvas.removeEventListener('keyup', this.onKeyUp as EventListener);
// Remove document-level capture listener
document.removeEventListener('keydown', this.onKeyDown as EventListener, { capture: true });
window.removeEventListener('blur', this.onBlur);
document.removeEventListener('paste', this.onPaste as unknown as EventListener);
@@ -697,6 +703,12 @@ export class CanvasInteractions {
this.canvas.canvasLayers.copySelectedLayers();
}
break;
case 'v':
// Paste layers from internal clipboard
if (this.canvas.canvasLayers.internalClipboard.length > 0) {
this.canvas.canvasLayers.pasteLayers();
}
break;
default:
handled = false;
break;