Skip to content

Commit 5fc8a6a

Browse files
authored
Merge pull request #487 from mathuo/469-add-window-lifecycle-callbacks-1
feat: popout group enhancements
2 parents 66d96cf + 0bca63b commit 5fc8a6a

File tree

5 files changed

+110
-45
lines changed

5 files changed

+110
-45
lines changed

packages/dockview-core/src/__tests__/dockview/components/panel/content.spec.ts

+23-16
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,19 @@ describe('contentContainer', () => {
6262

6363
const disposable = new CompositeDisposable();
6464

65-
const dockviewComponent = jest.fn<DockviewComponent, []>(() => {
66-
return {
67-
renderer: 'onlyWhenVisibile',
68-
overlayRenderContainer: new OverlayRenderContainer(
69-
document.createElement('div')
70-
),
71-
} as DockviewComponent;
72-
});
65+
const overlayRenderContainer = new OverlayRenderContainer(
66+
document.createElement('div')
67+
);
7368

74-
const cut = new ContentContainer(dockviewComponent(), jest.fn() as any);
69+
const cut = new ContentContainer(
70+
fromPartial<DockviewComponent>({
71+
renderer: 'onlyWhenVisibile',
72+
overlayRenderContainer,
73+
}),
74+
fromPartial<DockviewGroupPanelModel>({
75+
renderContainer: overlayRenderContainer,
76+
})
77+
);
7578

7679
disposable.addDisposables(
7780
cut.onDidFocus(() => {
@@ -84,12 +87,12 @@ describe('contentContainer', () => {
8487

8588
const contentRenderer = new TestContentRenderer('id-1');
8689

87-
const panel = {
90+
const panel = fromPartial<IDockviewPanel>({
8891
view: {
8992
content: contentRenderer,
90-
} as Partial<IDockviewPanelModel>,
93+
},
9194
api: { renderer: 'onlyWhenVisibile' },
92-
} as Partial<IDockviewPanel>;
95+
});
9396

9497
cut.openPanel(panel as IDockviewPanel);
9598

@@ -151,13 +154,17 @@ describe('contentContainer', () => {
151154
});
152155

153156
test("that panels renderered as 'onlyWhenVisibile' are removed when closed", () => {
157+
const overlayRenderContainer = fromPartial<OverlayRenderContainer>({
158+
detatch: jest.fn(),
159+
});
160+
154161
const cut = new ContentContainer(
155162
fromPartial<DockviewComponent>({
156-
overlayRenderContainer: {
157-
detatch: jest.fn(),
158-
},
163+
overlayRenderContainer,
159164
}),
160-
fromPartial<DockviewGroupPanelModel>({})
165+
fromPartial<DockviewGroupPanelModel>({
166+
renderContainer: overlayRenderContainer,
167+
})
161168
);
162169

163170
const panel1 = fromPartial<IDockviewPanel>({

packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts

+23-22
Original file line numberDiff line numberDiff line change
@@ -4434,12 +4434,13 @@ describe('dockviewComponent', () => {
44344434
cb();
44354435
}
44364436
}),
4437+
removeEventListener: jest.fn(),
44374438
close: jest.fn(),
44384439
})
44394440
);
44404441
});
44414442

4442-
test('that can remove a popout group', async () => {
4443+
test('add a popout group', async () => {
44434444
const container = document.createElement('div');
44444445

44454446
const dockview = new DockviewComponent({
@@ -4460,19 +4461,25 @@ describe('dockviewComponent', () => {
44604461
component: 'default',
44614462
});
44624463

4463-
await dockview.addPopoutGroup(panel1);
4464+
const panel2 = dockview.addPanel({
4465+
id: 'panel_2',
4466+
component: 'default',
4467+
});
44644468

4465-
expect(dockview.panels.length).toBe(1);
4466-
expect(dockview.groups.length).toBe(2);
4467-
expect(panel1.api.group.api.location.type).toBe('popout');
4469+
expect(panel1.group.api.location.type).toBe('grid');
4470+
expect(panel2.group.api.location.type).toBe('grid');
4471+
expect(dockview.groups.length).toBe(1);
4472+
expect(dockview.panels.length).toBe(2);
44684473

4469-
dockview.removePanel(panel1);
4474+
await dockview.addPopoutGroup(panel2.group);
44704475

4471-
expect(dockview.panels.length).toBe(0);
4472-
expect(dockview.groups.length).toBe(0);
4476+
expect(panel1.group.api.location.type).toBe('popout');
4477+
expect(panel2.group.api.location.type).toBe('popout');
4478+
expect(dockview.groups.length).toBe(2);
4479+
expect(dockview.panels.length).toBe(2);
44734480
});
44744481

4475-
test('add a popout group', async () => {
4482+
test('that can remove a popout group', async () => {
44764483
const container = document.createElement('div');
44774484

44784485
const dockview = new DockviewComponent({
@@ -4493,22 +4500,16 @@ describe('dockviewComponent', () => {
44934500
component: 'default',
44944501
});
44954502

4496-
const panel2 = dockview.addPanel({
4497-
id: 'panel_2',
4498-
component: 'default',
4499-
});
4503+
await dockview.addPopoutGroup(panel1);
45004504

4501-
expect(panel1.group.api.location.type).toBe('grid');
4502-
expect(panel2.group.api.location.type).toBe('grid');
4503-
expect(dockview.groups.length).toBe(1);
4504-
expect(dockview.panels.length).toBe(2);
4505+
expect(dockview.panels.length).toBe(1);
4506+
expect(dockview.groups.length).toBe(2);
4507+
expect(panel1.api.group.api.location.type).toBe('popout');
45054508

4506-
await dockview.addPopoutGroup(panel2.group);
4509+
dockview.removePanel(panel1);
45074510

4508-
expect(panel1.group.api.location.type).toBe('popout');
4509-
expect(panel2.group.api.location.type).toBe('popout');
4510-
expect(dockview.groups.length).toBe(2);
4511-
expect(dockview.panels.length).toBe(2);
4511+
expect(dockview.panels.length).toBe(0);
4512+
expect(dockview.groups.length).toBe(0);
45124513
});
45134514

45144515
test('move from fixed to popout group and back', async () => {

packages/dockview-core/src/dockview/components/panel/content.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ export class ContentContainer
133133

134134
switch (panel.api.renderer) {
135135
case 'onlyWhenVisibile':
136-
this.accessor.overlayRenderContainer.detatch(panel);
136+
this.group.renderContainer.detatch(panel);
137137
if (this.panel) {
138138
if (doRender) {
139139
this._element.appendChild(
@@ -149,7 +149,7 @@ export class ContentContainer
149149
) {
150150
this._element.removeChild(panel.view.content.element);
151151
}
152-
container = this.accessor.overlayRenderContainer.attach({
152+
container = this.group.renderContainer.attach({
153153
panel,
154154
referenceContainer: this,
155155
});

packages/dockview-core/src/dockview/dockviewComponent.ts

+40-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import { tail, sequenceEquals, remove } from '../array';
1414
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
1515
import { CompositeDisposable, Disposable, IDisposable } from '../lifecycle';
16-
import { Event, Emitter } from '../events';
16+
import { Event, Emitter, addDisposableWindowListener } from '../events';
1717
import { Watermark } from './components/watermark/watermark';
1818
import { IWatermarkRenderer, GroupviewPanelState } from './types';
1919
import { sequentialNumberGenerator } from '../math';
@@ -561,12 +561,15 @@ export class DockviewComponent
561561
from: DockviewGroupPanel;
562562
to: DockviewGroupPanel;
563563
}) {
564+
const activePanel = options.from.activePanel;
564565
const panels = [...options.from.panels].map((panel) =>
565566
options.from.model.removePanel(panel)
566567
);
567568

568569
panels.forEach((panel) => {
569-
options.to.model.openPanel(panel);
570+
options.to.model.openPanel(panel, {
571+
skipSetPanelActive: activePanel !== panel,
572+
});
570573
});
571574
}
572575

@@ -624,10 +627,18 @@ export class DockviewComponent
624627
return;
625628
}
626629

630+
const gready = document.createElement('div');
631+
gready.className = 'dv-overlay-render-container';
632+
633+
const overlayRenderContainer = new OverlayRenderContainer(
634+
gready
635+
);
636+
627637
const referenceGroup =
628638
item instanceof DockviewPanel ? item.group : item;
629639

630640
const group = this.createGroup({ id: groupId });
641+
group.model.renderContainer = overlayRenderContainer;
631642

632643
if (item instanceof DockviewPanel) {
633644
const panel = referenceGroup.model.removePanel(item);
@@ -637,9 +648,13 @@ export class DockviewComponent
637648
from: referenceGroup,
638649
to: group,
639650
});
640-
referenceGroup.api.setHidden(false);
651+
referenceGroup.api.setHidden(true);
641652
}
642653

654+
popoutContainer.classList.add('dv-dockview');
655+
popoutContainer.style.overflow = 'hidden';
656+
popoutContainer.appendChild(gready);
657+
643658
popoutContainer.appendChild(group.element);
644659

645660
group.model.location = {
@@ -655,6 +670,19 @@ export class DockviewComponent
655670
};
656671

657672
popoutWindowDisposable.addDisposables(
673+
/**
674+
* ResizeObserver seems slow here, I do not know why but we don't need it
675+
* since we can reply on the window resize event as we will occupy the full
676+
* window dimensions
677+
*/
678+
addDisposableWindowListener(
679+
_window.window!,
680+
'resize',
681+
() => {
682+
group.layout(window.innerWidth, window.innerHeight);
683+
}
684+
),
685+
overlayRenderContainer,
658686
Disposable.from(() => {
659687
if (this.getPanel(referenceGroup.id)) {
660688
moveGroupWithoutDestroying({
@@ -666,12 +694,16 @@ export class DockviewComponent
666694
referenceGroup.api.setHidden(false);
667695
}
668696

669-
this.doRemoveGroup(group);
697+
this.doRemoveGroup(group, {
698+
skipPopoutAssociated: true,
699+
});
670700
} else {
671701
const removedGroup = this.doRemoveGroup(group, {
672702
skipDispose: true,
673703
skipActive: true,
674704
});
705+
removedGroup.model.renderContainer =
706+
this.overlayRenderContainer;
675707
removedGroup.model.location = { type: 'grid' };
676708
this.doAddGroup(removedGroup, [0]);
677709
}
@@ -1484,6 +1516,7 @@ export class DockviewComponent
14841516
| {
14851517
skipActive?: boolean;
14861518
skipDispose?: boolean;
1519+
skipPopoutAssociated?: boolean;
14871520
}
14881521
| undefined
14891522
): DockviewGroupPanel {
@@ -1523,7 +1556,9 @@ export class DockviewComponent
15231556

15241557
if (selectedGroup) {
15251558
if (!options?.skipDispose) {
1526-
this.doRemoveGroup(selectedGroup.referenceGroup);
1559+
if (!options?.skipPopoutAssociated) {
1560+
this.removeGroup(selectedGroup.referenceGroup);
1561+
}
15271562

15281563
selectedGroup.popoutGroup.dispose();
15291564
this._groups.delete(group.id);

packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts

+22
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { DockviewDropTargets, IWatermarkRenderer } from './types';
2626
import { DockviewGroupPanel } from './dockviewGroupPanel';
2727
import { IDockviewPanel } from './dockviewPanel';
2828
import { IHeaderActionsRenderer } from './options';
29+
import { OverlayRenderContainer } from '../overlayRenderContainer';
2930

3031
interface GroupMoveEvent {
3132
groupId: string;
@@ -421,6 +422,27 @@ export class DockviewGroupPanelModel
421422
);
422423
}
423424

425+
private _overwriteRenderContainer: OverlayRenderContainer | null = null;
426+
427+
set renderContainer(value: OverlayRenderContainer | null) {
428+
this.panels.forEach((panel) => {
429+
this.renderContainer.detatch(panel);
430+
});
431+
432+
this._overwriteRenderContainer = value;
433+
434+
this.panels.forEach((panel) => {
435+
this.rerender(panel);
436+
});
437+
}
438+
439+
get renderContainer(): OverlayRenderContainer {
440+
return (
441+
this._overwriteRenderContainer ??
442+
this.accessor.overlayRenderContainer
443+
);
444+
}
445+
424446
initialize(): void {
425447
if (this.options.panels) {
426448
this.options.panels.forEach((panel) => {

0 commit comments

Comments
 (0)