Merge branch '479-is-there-any-way-to-focus-the-panel-content' of https://github.com/mathuo/dockview into 479-is-there-any-way-to-focus-the-panel-content

This commit is contained in:
mathuo 2024-02-19 20:51:57 +00:00
commit 5fddff72e7
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
5 changed files with 158 additions and 80 deletions

View File

@ -61,6 +61,7 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
options.group ?? options.group ??
this.accessor.addGroup({ this.accessor.addGroup({
direction: positionToDirection(options.position ?? 'right'), direction: positionToDirection(options.position ?? 'right'),
skipSetActive: true,
}); });
this.accessor.moveGroupOrPanel({ this.accessor.moveGroupOrPanel({

View File

@ -199,7 +199,9 @@ export class ContentContainer
public closePanel(): void { public closePanel(): void {
if (this.panel) { if (this.panel) {
if (this.panel.api.renderer === 'onlyWhenVisibile') { 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; this.panel = undefined;

View File

@ -71,6 +71,25 @@ const DEFAULT_ROOT_OVERLAY_MODEL: DroptargetOverlayModel = {
size: { type: 'pixels', value: 20 }, 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 getDockviewTheme(element: HTMLElement): string | undefined {
function toClassList(element: HTMLElement) { function toClassList(element: HTMLElement) {
const list: string[] = []; const list: string[] = [];
@ -253,16 +272,25 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
readonly activePanel: IDockviewPanel | undefined; readonly activePanel: IDockviewPanel | undefined;
readonly totalPanels: number; readonly totalPanels: number;
readonly panels: IDockviewPanel[]; readonly panels: IDockviewPanel[];
readonly orientation: Orientation;
readonly onDidDrop: Event<DockviewDidDropEvent>; readonly onDidDrop: Event<DockviewDidDropEvent>;
readonly onWillDrop: Event<DockviewWillDropEvent>; readonly onWillDrop: Event<DockviewWillDropEvent>;
readonly onWillShowOverlay: Event<WillShowOverlayLocationEvent>; readonly onWillShowOverlay: Event<WillShowOverlayLocationEvent>;
readonly orientation: Orientation; readonly onDidRemovePanel: Event<IDockviewPanel>;
readonly onDidAddPanel: Event<IDockviewPanel>;
readonly onDidLayoutFromJSON: Event<void>;
readonly onDidActivePanelChange: Event<IDockviewPanel | undefined>;
readonly onWillDragPanel: Event<TabDragEvent>;
readonly onWillDragGroup: Event<GroupDragEvent>;
readonly onDidRemoveGroup: Event<DockviewGroupPanel>;
readonly onDidAddGroup: Event<DockviewGroupPanel>;
readonly onDidActiveGroupChange: Event<DockviewGroupPanel | undefined>;
readonly options: DockviewComponentOptions;
updateOptions(options: DockviewComponentUpdateOptions): void; updateOptions(options: DockviewComponentUpdateOptions): void;
moveGroupOrPanel(options: MoveGroupOrPanelOptions): void; moveGroupOrPanel(options: MoveGroupOrPanelOptions): void;
moveGroup(options: MoveGroupOptions): void; moveGroup(options: MoveGroupOptions): void;
doSetGroupActive: (group: DockviewGroupPanel, skipFocus?: boolean) => void; doSetGroupActive: (group: DockviewGroupPanel, skipFocus?: boolean) => void;
removeGroup: (group: DockviewGroupPanel) => void; removeGroup: (group: DockviewGroupPanel) => void;
options: DockviewComponentOptions;
addPanel<T extends object = Parameters>( addPanel<T extends object = Parameters>(
options: AddPanelOptions<T> options: AddPanelOptions<T>
): IDockviewPanel; ): IDockviewPanel;
@ -280,12 +308,6 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
toJSON(): SerializedDockview; toJSON(): SerializedDockview;
fromJSON(data: SerializedDockview): void; fromJSON(data: SerializedDockview): void;
// //
readonly onDidRemovePanel: Event<IDockviewPanel>;
readonly onDidAddPanel: Event<IDockviewPanel>;
readonly onDidLayoutFromJSON: Event<void>;
readonly onDidActivePanelChange: Event<IDockviewPanel | undefined>;
readonly onWillDragPanel: Event<TabDragEvent>;
readonly onWillDragGroup: Event<GroupDragEvent>;
addFloatingGroup( addFloatingGroup(
item: IDockviewPanel | DockviewGroupPanel, item: IDockviewPanel | DockviewGroupPanel,
coord?: { x: number; y: number } coord?: { x: number; y: number }
@ -299,9 +321,6 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
onWillClose?: (event: { id: string; window: Window }) => void; onWillClose?: (event: { id: string; window: Window }) => void;
} }
): Promise<void>; ): Promise<void>;
readonly onDidRemoveGroup: Event<DockviewGroupPanel>;
readonly onDidAddGroup: Event<DockviewGroupPanel>;
readonly onDidActiveGroupChange: Event<DockviewGroupPanel | undefined>;
} }
export class DockviewComponent export class DockviewComponent
@ -358,8 +377,8 @@ export class DockviewComponent
private readonly _popoutGroups: { private readonly _popoutGroups: {
window: PopoutWindow; window: PopoutWindow;
popoutGroup: DockviewGroupPanel; popoutGroup: DockviewGroupPanel;
referenceGroup: string; referenceGroup?: string;
disposable: IDisposable; disposable: { dispose: () => DockviewGroupPanel | undefined };
}[] = []; }[] = [];
private readonly _rootDropTarget: Droptarget; private readonly _rootDropTarget: Droptarget;
@ -621,22 +640,6 @@ export class DockviewComponent
const theme = getDockviewTheme(this.gridview.element); const theme = getDockviewTheme(this.gridview.element);
const element = this.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 { function getBox(): Box {
if (options?.position) { if (options?.position) {
return options.position; return options.position;
@ -657,7 +660,9 @@ export class DockviewComponent
const groupId = const groupId =
options?.overridePopoutGroup?.id ?? this.getNextGroupId(); //item.id; options?.overridePopoutGroup?.id ?? this.getNextGroupId(); //item.id;
if (itemToPopout.api.location.type === 'grid') {
itemToPopout.api.setHidden(true); itemToPopout.api.setHidden(true);
}
const _window = new PopoutWindow( const _window = new PopoutWindow(
`${this.id}-${groupId}`, // unique id `${this.id}-${groupId}`, // unique id
@ -704,6 +709,8 @@ export class DockviewComponent
? itemToPopout.group ? itemToPopout.group
: itemToPopout; : itemToPopout;
const referenceLocation = itemToPopout.api.location.type;
const group = const group =
options?.overridePopoutGroup ?? options?.overridePopoutGroup ??
this.createGroup({ id: groupId }); this.createGroup({ id: groupId });
@ -713,23 +720,29 @@ export class DockviewComponent
this._onDidAddGroup.fire(group); this._onDidAddGroup.fire(group);
} }
const isMoving = this._moving;
try {
this._moving = true;
if (itemToPopout instanceof DockviewPanel) { if (itemToPopout instanceof DockviewPanel) {
this.movingLock(() => {
const panel = const panel =
referenceGroup.model.removePanel(itemToPopout); referenceGroup.model.removePanel(itemToPopout);
group.model.openPanel(panel); group.model.openPanel(panel);
});
} else { } else {
this.movingLock(() =>
moveGroupWithoutDestroying({ moveGroupWithoutDestroying({
from: referenceGroup, from: referenceGroup,
to: group, to: group,
}); })
);
switch (referenceLocation) {
case 'grid':
referenceGroup.api.setHidden(true); referenceGroup.api.setHidden(true);
break;
case 'floating':
case 'popout':
this.removeGroup(referenceGroup);
break;
} }
} finally {
this._moving = isMoving;
} }
popoutContainer.classList.add('dv-dockview'); popoutContainer.classList.add('dv-dockview');
@ -743,6 +756,8 @@ export class DockviewComponent
getWindow: () => _window.window!, getWindow: () => _window.window!,
}; };
this.doSetGroupAndPanelActive(group);
popoutWindowDisposable.addDisposables( popoutWindowDisposable.addDisposables(
group.api.onDidActiveChange((event) => { group.api.onDidActiveChange((event) => {
if (event.isActive) { if (event.isActive) {
@ -754,11 +769,20 @@ export class DockviewComponent
}) })
); );
let returnedGroup: DockviewGroupPanel | undefined;
const value = { const value = {
window: _window, window: _window,
popoutGroup: group, popoutGroup: group,
referenceGroup: referenceGroup.id, referenceGroup: this.getPanel(referenceGroup.id)
disposable: popoutWindowDisposable, ? referenceGroup.id
: undefined,
disposable: {
dispose: () => {
popoutWindowDisposable.dispose();
return returnedGroup;
},
},
}; };
popoutWindowDisposable.addDisposables( popoutWindowDisposable.addDisposables(
@ -777,24 +801,24 @@ export class DockviewComponent
overlayRenderContainer, overlayRenderContainer,
Disposable.from(() => { Disposable.from(() => {
if (this.getPanel(referenceGroup.id)) { if (this.getPanel(referenceGroup.id)) {
try { this.movingLock(() =>
this._moving = true;
moveGroupWithoutDestroying({ moveGroupWithoutDestroying({
from: group, from: group,
to: referenceGroup, to: referenceGroup,
}); })
} finally { );
this._moving = isMoving;
}
if (referenceGroup.api.isHidden) { if (referenceGroup.api.isHidden) {
referenceGroup.api.setHidden(false); referenceGroup.api.setHidden(false);
} }
if (this.getPanel(group.id)) {
this.doRemoveGroup(group, { this.doRemoveGroup(group, {
skipPopoutAssociated: true, skipPopoutAssociated: true,
}); });
}
} else { } else {
if (this.getPanel(group.id)) {
const removedGroup = this.doRemoveGroup(group, { const removedGroup = this.doRemoveGroup(group, {
skipDispose: true, skipDispose: true,
skipActive: true, skipActive: true,
@ -802,8 +826,8 @@ export class DockviewComponent
removedGroup.model.renderContainer = removedGroup.model.renderContainer =
this.overlayRenderContainer; this.overlayRenderContainer;
removedGroup.model.location = { type: 'grid' }; removedGroup.model.location = { type: 'grid' };
this.doAddGroup(removedGroup, [0]); returnedGroup = removedGroup;
this.doSetGroupAndPanelActive(removedGroup); }
} }
}) })
); );
@ -843,12 +867,40 @@ export class DockviewComponent
} else { } else {
group = item; group = item;
const popoutReferenceGroupId = this._popoutGroups.find(
(_) => _.popoutGroup === group
)?.referenceGroup;
const popoutReferenceGroup = popoutReferenceGroupId
? this.getPanel(popoutReferenceGroupId)
: undefined;
const skip = const skip =
typeof options?.skipRemoveGroup === 'boolean' && typeof options?.skipRemoveGroup === 'boolean' &&
options.skipRemoveGroup; options.skipRemoveGroup;
if (!skip) { 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,
});
}
} }
} }
@ -1503,7 +1555,7 @@ export class DockviewComponent
}); });
if (!options.skipDispose) { if (!options.skipDispose) {
this.overlayRenderContainer.detatch(panel); panel.group.model.renderContainer.detatch(panel);
panel.dispose(); panel.dispose();
} }
@ -1594,7 +1646,9 @@ export class DockviewComponent
const group = this.orthogonalize( const group = this.orthogonalize(
directionToPosition(<Direction>options.direction) directionToPosition(<Direction>options.direction)
); );
if (!options.skipSetActive) {
this.doSetGroupAndPanelActive(group); this.doSetGroupAndPanelActive(group);
}
return group; return group;
} }
@ -1607,7 +1661,9 @@ export class DockviewComponent
target target
); );
this.doAddGroup(group, relativeLocation); this.doAddGroup(group, relativeLocation);
if (!options.skipSetActive) {
this.doSetGroupAndPanelActive(group); this.doSetGroupAndPanelActive(group);
}
return group; return group;
} else { } else {
this.doAddGroup(group); this.doAddGroup(group);
@ -1622,6 +1678,8 @@ export class DockviewComponent
| { | {
skipActive?: boolean; skipActive?: boolean;
skipDispose?: boolean; skipDispose?: boolean;
skipPopoutAssociated?: boolean;
skipPopoutReturn?: boolean;
} }
| undefined | undefined
): void { ): void {
@ -1635,6 +1693,7 @@ export class DockviewComponent
skipActive?: boolean; skipActive?: boolean;
skipDispose?: boolean; skipDispose?: boolean;
skipPopoutAssociated?: boolean; skipPopoutAssociated?: boolean;
skipPopoutReturn?: boolean;
} }
| undefined | undefined
): DockviewGroupPanel { ): DockviewGroupPanel {
@ -1688,20 +1747,26 @@ export class DockviewComponent
if (selectedGroup) { if (selectedGroup) {
if (!options?.skipDispose) { if (!options?.skipDispose) {
if (!options?.skipPopoutAssociated) { if (!options?.skipPopoutAssociated) {
const refGroup = this.getPanel( const refGroup = selectedGroup.referenceGroup
selectedGroup.referenceGroup ? this.getPanel(selectedGroup.referenceGroup)
); : undefined;
if (refGroup) { if (refGroup) {
this.removeGroup(refGroup); this.removeGroup(refGroup);
} }
} }
selectedGroup.popoutGroup.dispose(); selectedGroup.popoutGroup.dispose();
this._groups.delete(group.id); this._groups.delete(group.id);
this._onDidRemoveGroup.fire(group); 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) { if (!options?.skipActive && this._activeGroup === group) {
const groups = Array.from(this._groups.values()); const groups = Array.from(this._groups.values());
@ -1780,7 +1845,7 @@ export class DockviewComponent
const removedPanel: IDockviewPanel | undefined = this.movingLock( const removedPanel: IDockviewPanel | undefined = this.movingLock(
() => () =>
sourceGroup.model.removePanel(sourceItemId, { sourceGroup.model.removePanel(sourceItemId, {
skipSetActive: true, skipSetActive: false,
skipSetActiveGroup: true, skipSetActiveGroup: true,
}) })
); );
@ -1922,11 +1987,13 @@ export class DockviewComponent
for (const panel of panels) { for (const panel of panels) {
to.model.openPanel(panel, { to.model.openPanel(panel, {
skipSetActive: panel !== activePanel, skipSetActive: panel !== activePanel,
skipSetGroupActive: panel !== activePanel, skipSetGroupActive: true,
}); });
} }
}); });
this.doSetGroupAndPanelActive(to);
panels.forEach((panel) => { panels.forEach((panel) => {
this._onDidMovePanel.fire({ panel }); this._onDidMovePanel.fire({ panel });
}); });
@ -1985,17 +2052,18 @@ export class DockviewComponent
} }
doSetGroupAndPanelActive(group: DockviewGroupPanel | undefined): void { doSetGroupAndPanelActive(group: DockviewGroupPanel | undefined): void {
// if (
// this.activeGroup === group &&
// this._onDidActiveGroupChange.value !== group
// ) {
// this._onDidActiveGroupChange.fire(group);
// }
super.doSetGroupActive(group); super.doSetGroupActive(group);
const activePanel = this.activePanel; const activePanel = this.activePanel;
if (
group &&
this.hasMaximizedGroup() &&
!this.isMaximizedGroup(group)
) {
this.exitMaximizedGroup();
}
if ( if (
!this._moving && !this._moving &&
activePanel !== this._onDidActivePanelChange.value activePanel !== this._onDidActivePanelChange.value

View File

@ -38,6 +38,7 @@ interface GroupMoveEvent {
interface CoreGroupOptions { interface CoreGroupOptions {
locked?: DockviewGroupPanelLocked; locked?: DockviewGroupPanelLocked;
hideHeader?: boolean; hideHeader?: boolean;
skipSetActive?: boolean;
} }
export interface GroupOptions extends CoreGroupOptions { export interface GroupOptions extends CoreGroupOptions {

View File

@ -28,6 +28,8 @@ export class OverlayRenderContainer extends CompositeDisposable {
} }
> = {}; > = {};
private _disposed = false;
constructor(private readonly element: HTMLElement) { constructor(private readonly element: HTMLElement) {
super(); super();
@ -37,6 +39,7 @@ export class OverlayRenderContainer extends CompositeDisposable {
value.disposable.dispose(); value.disposable.dispose();
value.destroy.dispose(); value.destroy.dispose();
} }
this._disposed = true;
}) })
); );
} }
@ -149,8 +152,11 @@ export class OverlayRenderContainer extends CompositeDisposable {
); );
this.map[panel.api.id].destroy = Disposable.from(() => { this.map[panel.api.id].destroy = Disposable.from(() => {
if (panel.view.content.element.parentElement === focusContainer) {
focusContainer.removeChild(panel.view.content.element); focusContainer.removeChild(panel.view.content.element);
this.element.removeChild(focusContainer); }
focusContainer.parentElement?.removeChild(focusContainer);
}); });
queueMicrotask(() => { queueMicrotask(() => {