diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts index 0be413221..154d074e7 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts @@ -6485,6 +6485,223 @@ describe('dockviewComponent', () => { }); }); + describe('moveGroup', () => { + test('#1', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent(container, { + createComponent(options) { + switch (options.name) { + case 'default': + return new PanelContentPartTest( + options.id, + options.name + ); + default: + throw new Error(`unsupported`); + } + }, + }); + const api = new DockviewApi(dockview); + + dockview.layout(1000, 1000); + + let panel1!: IDockviewPanel; + let panel2!: IDockviewPanel; + + const reset = () => { + dockview.clear(); + + panel1 = api.addPanel({ + id: 'panel_1', + component: 'default', + }); + + panel2 = api.addPanel({ + id: 'panel_2', + component: 'default', + position: { direction: 'right' }, + }); + }; + + // default case + + reset(); + expect([ + panel1.group.api.isActive, + panel2.group.api.isActive, + ]).toEqual([false, true]); + expect([panel1.api.isActive, panel2.api.isActive]).toEqual([ + false, + true, + ]); + + // move inactive group + + reset(); + panel1.group.api.moveTo({ group: panel2.group, position: 'right' }); + expect([ + panel1.group.api.isActive, + panel2.group.api.isActive, + ]).toEqual([true, false]); + expect([panel1.api.isActive, panel2.api.isActive]).toEqual([ + true, + false, + ]); + + // move active group + + reset(); + panel2.group.api.moveTo({ group: panel1.group, position: 'left' }); + expect([ + panel1.group.api.isActive, + panel2.group.api.isActive, + ]).toEqual([false, true]); + expect([panel1.api.isActive, panel2.api.isActive]).toEqual([ + false, + true, + ]); + + // move inactive group (with inactive flag) + + reset(); + panel1.group.api.moveTo({ + group: panel2.group, + position: 'right', + inactive: true, + }); + expect([ + panel1.group.api.isActive, + panel2.group.api.isActive, + ]).toEqual([false, true]); + expect([panel1.api.isActive, panel2.api.isActive]).toEqual([ + false, + true, + ]); + + // move active group (with inactive flag) + + reset(); + panel2.group.api.moveTo({ + group: panel1.group, + position: 'left', + inactive: true, + }); + expect([ + panel1.group.api.isActive, + panel2.group.api.isActive, + ]).toEqual([false, true]); + expect([panel1.api.isActive, panel2.api.isActive]).toEqual([ + false, + true, + ]); + + // merge inactive group with active group + + reset(); + panel1.group.api.moveTo({ group: panel2.group }); + expect([ + panel1.group.api.isActive, + panel2.group.api.isActive, + ]).toEqual([true, true]); + expect([panel1.api.isActive, panel2.api.isActive]).toEqual([ + true, + false, + ]); + + // merge active group with inactive group + + reset(); + panel2.group.api.moveTo({ group: panel1.group }); + expect([ + panel1.group.api.isActive, + panel2.group.api.isActive, + ]).toEqual([true, true]); + expect([panel1.api.isActive, panel2.api.isActive]).toEqual([ + false, + true, + ]); + + // merge inactive group with active group (with inactive flag) + + reset(); + panel1.group.api.moveTo({ group: panel2.group, inactive: true }); + expect([ + panel1.group.api.isActive, + panel2.group.api.isActive, + ]).toEqual([true, true]); + expect([panel1.api.isActive, panel2.api.isActive]).toEqual([ + false, + true, + ]); + + // merge active group with inactive group (with inactive flag) + + reset(); + panel2.group.api.moveTo({ group: panel1.group, inactive: true }); + expect([ + panel1.group.api.isActive, + panel2.group.api.isActive, + ]).toEqual([true, true]); + expect([panel1.api.isActive, panel2.api.isActive]).toEqual([ + false, + true, + ]); + }); + }); + + describe('movePanel', () => { + test('#1', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent(container, { + createComponent(options) { + switch (options.name) { + case 'default': + return new PanelContentPartTest( + options.id, + options.name + ); + default: + throw new Error(`unsupported`); + } + }, + }); + const api = new DockviewApi(dockview); + + dockview.layout(1000, 1000); + + let panel1!: IDockviewPanel; + let panel2!: IDockviewPanel; + + const reset = () => { + dockview.clear(); + + panel1 = api.addPanel({ + id: 'panel_1', + component: 'default', + }); + + panel2 = api.addPanel({ + id: 'panel_2', + component: 'default', + position: { direction: 'right' }, + }); + }; + + // default case + // + // last panel of group to within another group + // + // panel from group of at least 2 panels to within another group + // + // last panel of group to a new group within same branch + // + // last panel of group to a new group not within same branch + // + }); + }); + test('that `onDidLayoutChange` only subscribes to events after initial subscription time', () => { jest.useFakeTimers(); diff --git a/packages/dockview-core/src/api/dockviewGroupPanelApi.ts b/packages/dockview-core/src/api/dockviewGroupPanelApi.ts index 12424debb..358a7e10d 100644 --- a/packages/dockview-core/src/api/dockviewGroupPanelApi.ts +++ b/packages/dockview-core/src/api/dockviewGroupPanelApi.ts @@ -16,6 +16,7 @@ export interface DockviewGroupMoveParams { * The index to place the panel within a group, only applicable if the placement is within an existing group */ index?: number; + inactive?: boolean; } export interface DockviewGroupPanelApi extends GridviewPanelApi { @@ -105,6 +106,7 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl { : 'center', index: options.index, }, + inactive: options.inactive, }); } diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index 63915751d..24ff421b1 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -153,6 +153,7 @@ export interface MovePanelEvent { type MoveGroupOptions = { from: { group: DockviewGroupPanel }; to: { group: DockviewGroupPanel; position: Position }; + inactive?: boolean; }; type MoveGroupOrPanelOptions = { @@ -165,6 +166,7 @@ type MoveGroupOrPanelOptions = { position: Position; index?: number; }; + inactive?: boolean; }; export interface FloatingGroupOptions { @@ -1997,6 +1999,7 @@ export class DockviewComponent group: destinationGroup, position: destinationTarget, }, + inactive: options.inactive, }); return; } @@ -2027,9 +2030,13 @@ export class DockviewComponent destinationGroup.model.openPanel(removedPanel, { index: destinationIndex, skipSetGroupActive: true, + skipSetActive: options.inactive, }) ); - this.doSetGroupAndPanelActive(destinationGroup); + + if (!options.inactive) { + this.doSetGroupAndPanelActive(destinationGroup); + } this._onDidMovePanel.fire({ panel: removedPanel, @@ -2107,10 +2114,14 @@ export class DockviewComponent this.doRemoveGroup(sourceGroup, { skipActive: true }); const newGroup = this.createGroupAtLocation(targetLocation); + this.movingLock(() => newGroup.model.openPanel(removedPanel) ); - this.doSetGroupAndPanelActive(newGroup); + + if (!options.inactive) { + this.doSetGroupAndPanelActive(newGroup); + } this._onDidMovePanel.fire({ panel: this.getGroupPanel(sourceItemId)!, @@ -2137,8 +2148,12 @@ export class DockviewComponent updatedReferenceLocation, destinationTarget ); + this.movingLock(() => this.doAddGroup(targetGroup, location)); - this.doSetGroupAndPanelActive(targetGroup); + + if (!options.inactive) { + this.doSetGroupAndPanelActive(targetGroup); + } this._onDidMovePanel.fire({ panel: this.getGroupPanel(sourceItemId)!, @@ -2173,7 +2188,10 @@ export class DockviewComponent skipSetGroupActive: true, }) ); - this.doSetGroupAndPanelActive(group); + + if (!options.inactive) { + this.doSetGroupAndPanelActive(group); + } this._onDidMovePanel.fire({ panel: removedPanel, @@ -2199,6 +2217,8 @@ export class DockviewComponent ) ); + const isActiveGroup = from.api.isActive; + if (from?.model.size === 0) { this.doRemoveGroup(from, { skipActive: true }); } @@ -2206,13 +2226,18 @@ export class DockviewComponent this.movingLock(() => { for (const panel of panels) { to.model.openPanel(panel, { - skipSetActive: panel !== activePanel, - skipSetGroupActive: true, + skipSetActive: + options.inactive && !isActiveGroup + ? true + : panel !== activePanel, + skipSetGroupActive: !options.inactive, }); } }); - this.doSetGroupAndPanelActive(to); + if (isActiveGroup || !options.inactive) { + this.doSetGroupAndPanelActive(to); + } } else { switch (from.api.location.type) { case 'grid': @@ -2264,6 +2289,10 @@ export class DockviewComponent } this.gridview.addView(from, size, dropLocation); + + if (!options.inactive) { + this.doSetGroupAndPanelActive(from); + } } from.panels.forEach((panel) => {