From ed40e224e79ac6486ca1a073e433c95fcee80394 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Tue, 13 Feb 2024 20:24:56 +0000 Subject: [PATCH] feat: fixes --- .../src/dockview/components/panel/content.ts | 4 +- .../src/dockview/dockviewComponent.ts | 170 ++++++++++++------ .../src/overlayRenderContainer.ts | 10 +- 3 files changed, 126 insertions(+), 58 deletions(-) diff --git a/packages/dockview-core/src/dockview/components/panel/content.ts b/packages/dockview-core/src/dockview/components/panel/content.ts index 933415283..1bf35fb84 100644 --- a/packages/dockview-core/src/dockview/components/panel/content.ts +++ b/packages/dockview-core/src/dockview/components/panel/content.ts @@ -199,7 +199,9 @@ export class ContentContainer public closePanel(): void { if (this.panel) { if (this.panel.api.renderer === 'onlyWhenVisibile') { - this._element.removeChild(this.panel.view.content.element); + this.panel.view.content.element.parentElement?.removeChild( + this.panel.view.content.element + ); } } this.panel = undefined; diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index 55f9113a1..d0601c8ac 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -71,6 +71,25 @@ const DEFAULT_ROOT_OVERLAY_MODEL: DroptargetOverlayModel = { size: { type: 'pixels', value: 20 }, }; +function moveGroupWithoutDestroying(options: { + from: DockviewGroupPanel; + to: DockviewGroupPanel; +}) { + const activePanel = options.from.activePanel; + const panels = [...options.from.panels].map((panel) => { + const removedPanel = options.from.model.removePanel(panel); + options.from.model.renderContainer.detatch(panel); + return removedPanel; + }); + + panels.forEach((panel) => { + options.to.model.openPanel(panel, { + skipSetActive: activePanel !== panel, + skipSetGroupActive: true, + }); + }); +} + function getDockviewTheme(element: HTMLElement): string | undefined { function toClassList(element: HTMLElement) { const list: string[] = []; @@ -358,8 +377,8 @@ export class DockviewComponent private readonly _popoutGroups: { window: PopoutWindow; popoutGroup: DockviewGroupPanel; - referenceGroup: string; - disposable: IDisposable; + referenceGroup?: string; + disposable: { dispose: () => DockviewGroupPanel | undefined }; }[] = []; private readonly _rootDropTarget: Droptarget; @@ -621,22 +640,6 @@ export class DockviewComponent const theme = getDockviewTheme(this.gridview.element); const element = this.element; - function moveGroupWithoutDestroying(options: { - from: DockviewGroupPanel; - to: DockviewGroupPanel; - }) { - const activePanel = options.from.activePanel; - const panels = [...options.from.panels].map((panel) => - options.from.model.removePanel(panel) - ); - - panels.forEach((panel) => { - options.to.model.openPanel(panel, { - skipSetActive: activePanel !== panel, - }); - }); - } - function getBox(): Box { if (options?.position) { return options.position; @@ -657,7 +660,9 @@ export class DockviewComponent const groupId = options?.overridePopoutGroup?.id ?? this.getNextGroupId(); //item.id; - itemToPopout.api.setHidden(true); + if (itemToPopout.api.location.type === 'grid') { + itemToPopout.api.setHidden(true); + } const _window = new PopoutWindow( `${this.id}-${groupId}`, // unique id @@ -704,6 +709,8 @@ export class DockviewComponent ? itemToPopout.group : itemToPopout; + const referenceLocation = itemToPopout.api.location.type; + const group = options?.overridePopoutGroup ?? this.createGroup({ id: groupId }); @@ -713,23 +720,29 @@ export class DockviewComponent this._onDidAddGroup.fire(group); } - const isMoving = this._moving; - - try { - this._moving = true; - if (itemToPopout instanceof DockviewPanel) { + if (itemToPopout instanceof DockviewPanel) { + this.movingLock(() => { const panel = referenceGroup.model.removePanel(itemToPopout); group.model.openPanel(panel); - } else { + }); + } else { + this.movingLock(() => moveGroupWithoutDestroying({ from: referenceGroup, to: group, - }); - referenceGroup.api.setHidden(true); + }) + ); + + switch (referenceLocation) { + case 'grid': + referenceGroup.api.setHidden(true); + break; + case 'floating': + case 'popout': + this.removeGroup(referenceGroup); + break; } - } finally { - this._moving = isMoving; } popoutContainer.classList.add('dv-dockview'); @@ -743,6 +756,8 @@ export class DockviewComponent getWindow: () => _window.window!, }; + this.doSetGroupAndPanelActive(group); + popoutWindowDisposable.addDisposables( group.api.onDidActiveChange((event) => { if (event.isActive) { @@ -754,11 +769,20 @@ export class DockviewComponent }) ); + let returnedGroup: DockviewGroupPanel | undefined; + const value = { window: _window, popoutGroup: group, - referenceGroup: referenceGroup.id, - disposable: popoutWindowDisposable, + referenceGroup: this.getPanel(referenceGroup.id) + ? referenceGroup.id + : undefined, + disposable: { + dispose: () => { + popoutWindowDisposable.dispose(); + return returnedGroup; + }, + }, }; popoutWindowDisposable.addDisposables( @@ -777,23 +801,22 @@ export class DockviewComponent overlayRenderContainer, Disposable.from(() => { if (this.getPanel(referenceGroup.id)) { - try { - this._moving = true; + this.movingLock(() => moveGroupWithoutDestroying({ from: group, to: referenceGroup, - }); - } finally { - this._moving = isMoving; - } + }) + ); if (referenceGroup.api.isHidden) { referenceGroup.api.setHidden(false); } - this.doRemoveGroup(group, { - skipPopoutAssociated: true, - }); + if (this.getPanel(group.id)) { + this.doRemoveGroup(group, { + skipPopoutAssociated: true, + }); + } } else { if (this.getPanel(group.id)) { const removedGroup = this.doRemoveGroup(group, { @@ -803,8 +826,7 @@ export class DockviewComponent removedGroup.model.renderContainer = this.overlayRenderContainer; removedGroup.model.location = { type: 'grid' }; - this.doAddGroup(removedGroup, [0]); - this.doSetGroupAndPanelActive(removedGroup); + returnedGroup = removedGroup; } } }) @@ -845,12 +867,40 @@ export class DockviewComponent } else { group = item; + const popoutReferenceGroupId = this._popoutGroups.find( + (_) => _.popoutGroup === group + )?.referenceGroup; + const popoutReferenceGroup = popoutReferenceGroupId + ? this.getPanel(popoutReferenceGroupId) + : undefined; + const skip = typeof options?.skipRemoveGroup === 'boolean' && options.skipRemoveGroup; if (!skip) { - this.doRemoveGroup(item, { skipDispose: true }); + if (popoutReferenceGroup) { + this.movingLock(() => + moveGroupWithoutDestroying({ + from: item, + to: popoutReferenceGroup, + }) + ); + this.doRemoveGroup(item, { + skipPopoutReturn: true, + skipPopoutAssociated: true, + }); + this.doRemoveGroup(popoutReferenceGroup, { + skipDispose: true, + }); + group = popoutReferenceGroup; + } else { + this.doRemoveGroup(item, { + skipDispose: true, + skipPopoutReturn: true, + skipPopoutAssociated: !!popoutReferenceGroup, + }); + } } } @@ -1505,7 +1555,7 @@ export class DockviewComponent }); if (!options.skipDispose) { - this.overlayRenderContainer.detatch(panel); + panel.group.model.renderContainer.detatch(panel); panel.dispose(); } @@ -1628,6 +1678,8 @@ export class DockviewComponent | { skipActive?: boolean; skipDispose?: boolean; + skipPopoutAssociated?: boolean; + skipPopoutReturn?: boolean; } | undefined ): void { @@ -1641,6 +1693,7 @@ export class DockviewComponent skipActive?: boolean; skipDispose?: boolean; skipPopoutAssociated?: boolean; + skipPopoutReturn?: boolean; } | undefined ): DockviewGroupPanel { @@ -1694,20 +1747,26 @@ export class DockviewComponent if (selectedGroup) { if (!options?.skipDispose) { if (!options?.skipPopoutAssociated) { - const refGroup = this.getPanel( - selectedGroup.referenceGroup - ); + const refGroup = selectedGroup.referenceGroup + ? this.getPanel(selectedGroup.referenceGroup) + : undefined; if (refGroup) { this.removeGroup(refGroup); } } selectedGroup.popoutGroup.dispose(); + this._groups.delete(group.id); this._onDidRemoveGroup.fire(group); } - selectedGroup.disposable.dispose(); + const removedGroup = selectedGroup.disposable.dispose(); + + if (!options?.skipPopoutReturn && removedGroup) { + this.doAddGroup(removedGroup, [0]); + this.doSetGroupAndPanelActive(removedGroup); + } if (!options?.skipActive && this._activeGroup === group) { const groups = Array.from(this._groups.values()); @@ -1993,17 +2052,18 @@ export class DockviewComponent } doSetGroupAndPanelActive(group: DockviewGroupPanel | undefined): void { - // if ( - // this.activeGroup === group && - // this._onDidActiveGroupChange.value !== group - // ) { - // this._onDidActiveGroupChange.fire(group); - // } - super.doSetGroupActive(group); const activePanel = this.activePanel; + if ( + group && + this.hasMaximizedGroup() && + !this.isMaximizedGroup(group) + ) { + this.exitMaximizedGroup(); + } + if ( !this._moving && activePanel !== this._onDidActivePanelChange.value diff --git a/packages/dockview-core/src/overlayRenderContainer.ts b/packages/dockview-core/src/overlayRenderContainer.ts index 62095e595..84c0f0cb0 100644 --- a/packages/dockview-core/src/overlayRenderContainer.ts +++ b/packages/dockview-core/src/overlayRenderContainer.ts @@ -28,6 +28,8 @@ export class OverlayRenderContainer extends CompositeDisposable { } > = {}; + private _disposed = false; + constructor(private readonly element: HTMLElement) { super(); @@ -37,6 +39,7 @@ export class OverlayRenderContainer extends CompositeDisposable { value.disposable.dispose(); value.destroy.dispose(); } + this._disposed = true; }) ); } @@ -149,8 +152,11 @@ export class OverlayRenderContainer extends CompositeDisposable { ); this.map[panel.api.id].destroy = Disposable.from(() => { - focusContainer.removeChild(panel.view.content.element); - this.element.removeChild(focusContainer); + if (panel.view.content.element.parentElement === focusContainer) { + focusContainer.removeChild(panel.view.content.element); + } + + focusContainer.parentElement?.removeChild(focusContainer); }); queueMicrotask(() => {