diff --git a/packages/core/src/commands/registry.ts b/packages/core/src/commands/registry.ts index 7874089a1..5f9ea38a2 100644 --- a/packages/core/src/commands/registry.ts +++ b/packages/core/src/commands/registry.ts @@ -10,6 +10,7 @@ import type { FullscreenCommandRegistryRun, FullscreenCommandRegistryStop } from import type { PreviewCommandRegistryRun, PreviewCommandRegistryStop } from './view/Preview'; import type { ResizeCommandRegistryRun, ResizeCommandRegistryStop } from './view/Resize'; import type { ComponentNextCommandRegistryRun } from './view/ComponentNext'; +import type { ComponentPrevCommandRegistryRun } from './view/ComponentPrev'; import type { CopyComponentCommandRegistryRun } from './view/CopyComponent'; import type { PasteComponentCommandRegistryRun } from './view/PasteComponent'; import type { CanvasMoveCommandRegistryRun, CanvasMoveCommandRegistryStop } from './view/CanvasMove'; @@ -43,6 +44,7 @@ export interface CommandRegistryRun PreviewCommandRegistryRun, ResizeCommandRegistryRun, ComponentNextCommandRegistryRun, + ComponentPrevCommandRegistryRun, CopyComponentCommandRegistryRun, PasteComponentCommandRegistryRun, CanvasMoveCommandRegistryRun, diff --git a/packages/core/src/commands/view/ComponentPrev.ts b/packages/core/src/commands/view/ComponentPrev.ts index f6b1ae2cc..0f1a79f8c 100644 --- a/packages/core/src/commands/view/ComponentPrev.ts +++ b/packages/core/src/commands/view/ComponentPrev.ts @@ -1,8 +1,14 @@ -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) { +export interface ComponentPrevCommandRegistryRun { + 'core:component-prev': CommandPublicFnFromHandler; +} + +export default class CommandComponentPrev extends CommandAbstract { + run(ed: Editor) { if (!ed.Canvas.hasFocus()) return; const toSelect: Component[] = []; @@ -12,7 +18,7 @@ export default { let incr = 0; let at = 0; - let next: any; + let next: Component | null = null; // Get the first selectable component do { @@ -25,5 +31,5 @@ export default { }); toSelect.length && ed.select(toSelect); - }, -} as CommandObject; + } +} diff --git a/packages/core/test/specs/commands/view/ComponentPrev.ts b/packages/core/test/specs/commands/view/ComponentPrev.ts new file mode 100644 index 000000000..ad3d0ffda --- /dev/null +++ b/packages/core/test/specs/commands/view/ComponentPrev.ts @@ -0,0 +1,43 @@ +import ComponentPrev from '../../../../src/commands/view/ComponentPrev'; + +describe('ComponentPrev command', () => { + test('should select the previous selectable sibling', () => { + const command = new ComponentPrev({}); + const prevSelectable = { get: jest.fn(() => true) }; + const notSelectable = { get: jest.fn(() => false) }; + const parent = { + getChildAt: jest.fn((index: number) => { + if (index === 1) return notSelectable; + if (index === 0) return prevSelectable; + return null; + }), + }; + const selected = { + parent: jest.fn(() => parent), + index: jest.fn(() => 2), + }; + const editor = { + Canvas: { hasFocus: jest.fn(() => true) }, + getSelectedAll: jest.fn(() => [selected]), + select: jest.fn(), + }; + + command.run(editor as any); + + expect(editor.select).toHaveBeenCalledWith([prevSelectable]); + }); + + test('should do nothing if the canvas has no focus', () => { + const command = new ComponentPrev({}); + const editor = { + Canvas: { hasFocus: jest.fn(() => false) }, + getSelectedAll: jest.fn(), + select: jest.fn(), + }; + + command.run(editor as any); + + expect(editor.getSelectedAll).not.toHaveBeenCalled(); + expect(editor.select).not.toHaveBeenCalled(); + }); +});