From 8e7e0b4d6dad8baa3a17183f59b13ca0b23aca4f Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Wed, 20 May 2026 15:52:34 +0400 Subject: [PATCH] Refactor CommandCopyComponent --- packages/core/src/commands/registry.ts | 4 +- .../core/src/commands/view/CopyComponent.ts | 17 ++++++--- .../test/specs/commands/view/CopyComponent.ts | 37 +++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 packages/core/test/specs/commands/view/CopyComponent.ts diff --git a/packages/core/src/commands/registry.ts b/packages/core/src/commands/registry.ts index 328da6d86..cc1091102 100644 --- a/packages/core/src/commands/registry.ts +++ b/packages/core/src/commands/registry.ts @@ -9,6 +9,7 @@ import type { import type { FullscreenCommandRegistryRun, FullscreenCommandRegistryStop } from './view/Fullscreen'; import type { PreviewCommandRegistryRun, PreviewCommandRegistryStop } from './view/Preview'; import type { ResizeCommandRegistryRun, ResizeCommandRegistryStop } from './view/Resize'; +import type { CopyComponentCommandRegistryRun } from './view/CopyComponent'; type CommandRegistryHandler = (...args: any[]) => any; type CommandRegistryEntry = TId extends keyof TRegistry @@ -20,7 +21,8 @@ type CommandRegistryEntry = TId extends keyof TRe export interface CommandRegistryRun extends FullscreenCommandRegistryRun, PreviewCommandRegistryRun, - ResizeCommandRegistryRun {} + ResizeCommandRegistryRun, + CopyComponentCommandRegistryRun {} export interface CommandRegistryStop extends FullscreenCommandRegistryStop, diff --git a/packages/core/src/commands/view/CopyComponent.ts b/packages/core/src/commands/view/CopyComponent.ts index a477fc05b..5f42343fa 100644 --- a/packages/core/src/commands/view/CopyComponent.ts +++ b/packages/core/src/commands/view/CopyComponent.ts @@ -1,9 +1,16 @@ -import { CommandObject } from './CommandAbstract'; +import Editor from '../../editor'; +import type { CommandPublicFnFromHandler } from '../registryHelpers'; +import CommandAbstract from './CommandAbstract'; -export default { - run(ed) { +export interface CopyComponentCommandRegistryRun { + 'core:copy': CommandPublicFnFromHandler; + copy: CommandPublicFnFromHandler; +} + +export default class CommandCopyComponent extends CommandAbstract { + run(ed: Editor) { const em = ed.getModel(); const models = [...ed.getSelectedAll()].map((md) => md.delegate?.copy?.(md) || md).filter(Boolean); models.length && em.set('clipboard', models); - }, -} as CommandObject; + } +} diff --git a/packages/core/test/specs/commands/view/CopyComponent.ts b/packages/core/test/specs/commands/view/CopyComponent.ts new file mode 100644 index 000000000..d7feab5f6 --- /dev/null +++ b/packages/core/test/specs/commands/view/CopyComponent.ts @@ -0,0 +1,37 @@ +import CopyComponent from '../../../../src/commands/view/CopyComponent'; + +describe('CopyComponent command', () => { + test('should set the clipboard with selected components', () => { + const command = new CopyComponent({}); + const set = jest.fn(); + const selected = [{ id: 'cmp-1' }, { id: 'cmp-2' }]; + const editor = { + getModel: jest.fn(() => ({ set })), + getSelectedAll: jest.fn(() => selected), + }; + + command.run(editor); + + expect(set).toHaveBeenCalledWith('clipboard', selected); + }); + + test('should use delegated copy target when available', () => { + const command = new CopyComponent({}); + const set = jest.fn(); + const delegated = { id: 'delegated' }; + const component = { + delegate: { + copy: jest.fn(() => delegated), + }, + }; + const editor = { + getModel: jest.fn(() => ({ set })), + getSelectedAll: jest.fn(() => [component]), + }; + + command.run(editor); + + expect(component.delegate.copy).toHaveBeenCalledWith(component); + expect(set).toHaveBeenCalledWith('clipboard', [delegated]); + }); +});