diff --git a/packages/core/src/commands/registry.ts b/packages/core/src/commands/registry.ts index 879cf8788..a01eb9586 100644 --- a/packages/core/src/commands/registry.ts +++ b/packages/core/src/commands/registry.ts @@ -12,6 +12,7 @@ import type { ResizeCommandRegistryRun, ResizeCommandRegistryStop } from './view import type { ComponentNextCommandRegistryRun } from './view/ComponentNext'; import type { ComponentPrevCommandRegistryRun } from './view/ComponentPrev'; import type { ComponentEnterCommandRegistryRun } from './view/ComponentEnter'; +import type { ComponentExitCommandRegistryRun } from './view/ComponentExit'; import type { CopyComponentCommandRegistryRun } from './view/CopyComponent'; import type { PasteComponentCommandRegistryRun } from './view/PasteComponent'; import type { CanvasMoveCommandRegistryRun, CanvasMoveCommandRegistryStop } from './view/CanvasMove'; @@ -47,6 +48,7 @@ export interface CommandRegistryRun ComponentNextCommandRegistryRun, ComponentPrevCommandRegistryRun, ComponentEnterCommandRegistryRun, + ComponentExitCommandRegistryRun, CopyComponentCommandRegistryRun, PasteComponentCommandRegistryRun, CanvasMoveCommandRegistryRun, diff --git a/packages/core/src/commands/view/ComponentExit.ts b/packages/core/src/commands/view/ComponentExit.ts index caabcb71d..39c0f3fb8 100644 --- a/packages/core/src/commands/view/ComponentExit.ts +++ b/packages/core/src/commands/view/ComponentExit.ts @@ -1,8 +1,15 @@ -import Component from '../../dom_components/model/Component'; -import { CommandObject } from './CommandAbstract'; +import type Component from '../../dom_components/model/Component'; +import Editor from '../../editor'; +import type { CommandPublicFnFromHandler } from '../registryHelpers'; +import CommandAbstract from './CommandAbstract'; -export default { - run(ed, snd, opts = {}) { +export interface ComponentExitCommandRegistryRun { + 'core:component-exit': CommandPublicFnFromHandler; + 'select-parent': CommandPublicFnFromHandler; +} + +export default class CommandComponentExit extends CommandAbstract { + run(ed: Editor, _: any, opts: any = {}) { if (!ed.Canvas.hasFocus() && !opts.force) return; const toSelect: Component[] = []; @@ -18,5 +25,5 @@ export default { }); toSelect.length && ed.select(toSelect); - }, -} as CommandObject; + } +} diff --git a/packages/core/test/specs/commands/view/ComponentExit.ts b/packages/core/test/specs/commands/view/ComponentExit.ts new file mode 100644 index 000000000..8dc75bd5b --- /dev/null +++ b/packages/core/test/specs/commands/view/ComponentExit.ts @@ -0,0 +1,61 @@ +import ComponentExit from '../../../../src/commands/view/ComponentExit'; + +describe('ComponentExit command', () => { + test('should select the first selectable parent', () => { + const command = new ComponentExit({}); + const selectableParent = { + get: jest.fn(() => true), + parent: jest.fn(), + }; + const nonSelectableParent = { + get: jest.fn(() => false), + parent: jest.fn(() => selectableParent), + }; + const component = { + parent: jest.fn(() => nonSelectableParent), + }; + const editor = { + Canvas: { hasFocus: jest.fn(() => true) }, + getSelectedAll: jest.fn(() => [component]), + select: jest.fn(), + }; + + command.run(editor as any, null, {}); + + expect(editor.select).toHaveBeenCalledWith([selectableParent]); + }); + + test('should select parent when forced even without canvas focus', () => { + const command = new ComponentExit({}); + const parent = { + get: jest.fn(() => true), + parent: jest.fn(), + }; + const component = { + parent: jest.fn(() => parent), + }; + const editor = { + Canvas: { hasFocus: jest.fn(() => false) }, + getSelectedAll: jest.fn(() => [component]), + select: jest.fn(), + }; + + command.run(editor as any, null, { force: true }); + + expect(editor.select).toHaveBeenCalledWith([parent]); + }); + + test('should do nothing if the canvas has no focus and force is not set', () => { + const command = new ComponentExit({}); + const editor = { + Canvas: { hasFocus: jest.fn(() => false) }, + getSelectedAll: jest.fn(), + select: jest.fn(), + }; + + command.run(editor as any, null, {}); + + expect(editor.getSelectedAll).not.toHaveBeenCalled(); + expect(editor.select).not.toHaveBeenCalled(); + }); +});