mirror of
https://github.com/mathuo/dockview
synced 2025-01-22 17:35:57 +00:00
Merge pull request #481 from mathuo/469-add-window-lifecycle-callbacks-1
feat: provide means to obtain popoutWindow document
This commit is contained in:
commit
aa8e7e09e0
@ -11,7 +11,7 @@ describe('groupDragHandler', () => {
|
||||
const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
const partial: Partial<DockviewGroupPanel> = {
|
||||
id: 'test_group_id',
|
||||
api: { location: 'grid' } as any,
|
||||
api: { location: { type: 'grid' } } as any,
|
||||
};
|
||||
return partial as DockviewGroupPanel;
|
||||
});
|
||||
@ -53,7 +53,7 @@ describe('groupDragHandler', () => {
|
||||
|
||||
const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
const partial: Partial<DockviewGroupPanel> = {
|
||||
api: { location: 'floating' } as any,
|
||||
api: { location: { type: 'floating' } } as any,
|
||||
};
|
||||
return partial as DockviewGroupPanel;
|
||||
});
|
||||
@ -85,7 +85,7 @@ describe('groupDragHandler', () => {
|
||||
|
||||
const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
const partial: Partial<DockviewGroupPanel> = {
|
||||
api: { location: 'grid' } as any,
|
||||
api: { location: { type: 'grid' } } as any,
|
||||
};
|
||||
return partial as DockviewGroupPanel;
|
||||
});
|
||||
|
@ -9,6 +9,7 @@ import { DockviewGroupPanelModel } from '../../../../dockview/dockviewGroupPanel
|
||||
import { fireEvent } from '@testing-library/dom';
|
||||
import { TestPanel } from '../../dockviewGroupPanelModel.spec';
|
||||
import { IDockviewPanel } from '../../../../dockview/dockviewPanel';
|
||||
import { fromPartial } from '@total-typescript/shoehorn';
|
||||
|
||||
describe('tabsContainer', () => {
|
||||
test('that an external event does not render a drop target and calls through to the group mode', () => {
|
||||
@ -478,7 +479,7 @@ describe('tabsContainer', () => {
|
||||
|
||||
const groupPanelMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
return (<Partial<DockviewGroupPanel>>{
|
||||
api: { location: 'grid' } as any,
|
||||
api: { location: { type: 'grid' } } as any,
|
||||
}) as DockviewGroupPanel;
|
||||
});
|
||||
|
||||
@ -538,7 +539,7 @@ describe('tabsContainer', () => {
|
||||
|
||||
const groupPanelMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
return (<Partial<DockviewGroupPanel>>{
|
||||
api: { location: 'floating' } as any,
|
||||
api: { location: { type: 'floating' } } as any,
|
||||
}) as DockviewGroupPanel;
|
||||
});
|
||||
|
||||
@ -591,7 +592,7 @@ describe('tabsContainer', () => {
|
||||
|
||||
const groupPanelMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
return (<Partial<DockviewGroupPanel>>{
|
||||
api: { location: 'floating' } as any,
|
||||
api: { location: { type: 'floating' } } as any,
|
||||
model: {} as any,
|
||||
}) as DockviewGroupPanel;
|
||||
});
|
||||
@ -601,23 +602,20 @@ describe('tabsContainer', () => {
|
||||
|
||||
const cut = new TabsContainer(accessor, groupPanel);
|
||||
|
||||
const panelMock = jest.fn<IDockviewPanel, [string]>((id: string) => {
|
||||
const partial: Partial<IDockviewPanel> = {
|
||||
const createPanel = (id: string) =>
|
||||
fromPartial<IDockviewPanel>({
|
||||
id,
|
||||
|
||||
view: {
|
||||
tab: {
|
||||
element: document.createElement('div'),
|
||||
} as any,
|
||||
},
|
||||
content: {
|
||||
element: document.createElement('div'),
|
||||
} as any,
|
||||
} as any,
|
||||
};
|
||||
return partial as IDockviewPanel;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const panel = new panelMock('test_id');
|
||||
const panel = createPanel('test_id');
|
||||
cut.openPanel(panel);
|
||||
|
||||
const el = cut.element.querySelector('.tab')!;
|
||||
@ -628,15 +626,15 @@ describe('tabsContainer', () => {
|
||||
fireEvent(el, event);
|
||||
|
||||
// a floating group with a single tab shouldn't be eligible
|
||||
expect(preventDefaultSpy).toBeCalledTimes(0);
|
||||
expect(accessor.addFloatingGroup).toBeCalledTimes(0);
|
||||
expect(preventDefaultSpy).toHaveBeenCalledTimes(0);
|
||||
expect(accessor.addFloatingGroup).toHaveBeenCalledTimes(0);
|
||||
|
||||
const panel2 = new panelMock('test_id_2');
|
||||
const panel2 = createPanel('test_id_2');
|
||||
cut.openPanel(panel2);
|
||||
fireEvent(el, event);
|
||||
|
||||
expect(preventDefaultSpy).toBeCalledTimes(1);
|
||||
expect(accessor.addFloatingGroup).toBeCalledTimes(1);
|
||||
expect(preventDefaultSpy).toHaveBeenCalledTimes(1);
|
||||
expect(accessor.addFloatingGroup).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('pre header actions', () => {
|
||||
@ -653,7 +651,7 @@ describe('tabsContainer', () => {
|
||||
|
||||
const groupPanelMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
return (<Partial<DockviewGroupPanel>>{
|
||||
api: { location: 'grid' } as any,
|
||||
api: { location: { type: 'grid' } } as any,
|
||||
model: {} as any,
|
||||
}) as DockviewGroupPanel;
|
||||
});
|
||||
@ -723,7 +721,7 @@ describe('tabsContainer', () => {
|
||||
|
||||
const groupPanelMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
return (<Partial<DockviewGroupPanel>>{
|
||||
api: { location: 'grid' } as any,
|
||||
api: { location: { type: 'grid' } } as any,
|
||||
model: {} as any,
|
||||
}) as DockviewGroupPanel;
|
||||
});
|
||||
@ -793,7 +791,7 @@ describe('tabsContainer', () => {
|
||||
|
||||
const groupPanelMock = jest.fn<DockviewGroupPanel, []>(() => {
|
||||
return (<Partial<DockviewGroupPanel>>{
|
||||
api: { location: 'grid' } as any,
|
||||
api: { location: { type: 'grid' } } as any,
|
||||
model: {} as any,
|
||||
}) as DockviewGroupPanel;
|
||||
});
|
||||
|
@ -110,102 +110,109 @@ describe('dockviewComponent', () => {
|
||||
window.open = jest.fn(); // not implemented by jest
|
||||
});
|
||||
|
||||
describe('memory leakage', () => {
|
||||
test('event leakage', () => {
|
||||
Emitter.setLeakageMonitorEnabled(true);
|
||||
// describe('memory leakage', () => {
|
||||
// beforeEach(() => {
|
||||
// window.open = () => fromPartial<Window>({
|
||||
// addEventListener: jest.fn(),
|
||||
// close: jest.fn(),
|
||||
// });
|
||||
// });
|
||||
|
||||
dockview = new DockviewComponent({
|
||||
parentElement: container,
|
||||
components: {
|
||||
default: PanelContentPartTest,
|
||||
},
|
||||
});
|
||||
// test('event leakage', () => {
|
||||
// Emitter.setLeakageMonitorEnabled(true);
|
||||
|
||||
dockview.layout(500, 1000);
|
||||
// dockview = new DockviewComponent({
|
||||
// parentElement: container,
|
||||
// components: {
|
||||
// default: PanelContentPartTest,
|
||||
// },
|
||||
// });
|
||||
|
||||
const panel1 = dockview.addPanel({
|
||||
id: 'panel1',
|
||||
component: 'default',
|
||||
});
|
||||
// dockview.layout(500, 1000);
|
||||
|
||||
const panel2 = dockview.addPanel({
|
||||
id: 'panel2',
|
||||
component: 'default',
|
||||
});
|
||||
// const panel1 = dockview.addPanel({
|
||||
// id: 'panel1',
|
||||
// component: 'default',
|
||||
// });
|
||||
|
||||
dockview.removePanel(panel2);
|
||||
// const panel2 = dockview.addPanel({
|
||||
// id: 'panel2',
|
||||
// component: 'default',
|
||||
// });
|
||||
|
||||
const panel3 = dockview.addPanel({
|
||||
id: 'panel3',
|
||||
component: 'default',
|
||||
position: {
|
||||
direction: 'right',
|
||||
referencePanel: 'panel1',
|
||||
},
|
||||
});
|
||||
// dockview.removePanel(panel2);
|
||||
|
||||
const panel4 = dockview.addPanel({
|
||||
id: 'panel4',
|
||||
component: 'default',
|
||||
position: {
|
||||
direction: 'above',
|
||||
},
|
||||
});
|
||||
// const panel3 = dockview.addPanel({
|
||||
// id: 'panel3',
|
||||
// component: 'default',
|
||||
// position: {
|
||||
// direction: 'right',
|
||||
// referencePanel: 'panel1',
|
||||
// },
|
||||
// });
|
||||
|
||||
dockview.moveGroupOrPanel(
|
||||
panel4.group,
|
||||
panel3.group.id,
|
||||
panel3.id,
|
||||
'center'
|
||||
);
|
||||
// const panel4 = dockview.addPanel({
|
||||
// id: 'panel4',
|
||||
// component: 'default',
|
||||
// position: {
|
||||
// direction: 'above',
|
||||
// },
|
||||
// });
|
||||
|
||||
dockview.addPanel({
|
||||
id: 'panel5',
|
||||
component: 'default',
|
||||
floating: true,
|
||||
});
|
||||
// dockview.moveGroupOrPanel(
|
||||
// panel4.group,
|
||||
// panel3.group.id,
|
||||
// panel3.id,
|
||||
// 'center'
|
||||
// );
|
||||
|
||||
const panel6 = dockview.addPanel({
|
||||
id: 'panel6',
|
||||
component: 'default',
|
||||
position: {
|
||||
referencePanel: 'panel5',
|
||||
direction: 'within',
|
||||
},
|
||||
});
|
||||
// dockview.addPanel({
|
||||
// id: 'panel5',
|
||||
// component: 'default',
|
||||
// floating: true,
|
||||
// });
|
||||
|
||||
dockview.addFloatingGroup(panel4.api.group);
|
||||
// const panel6 = dockview.addPanel({
|
||||
// id: 'panel6',
|
||||
// component: 'default',
|
||||
// position: {
|
||||
// referencePanel: 'panel5',
|
||||
// direction: 'within',
|
||||
// },
|
||||
// });
|
||||
|
||||
dockview.addPopoutGroup(panel6);
|
||||
// dockview.addFloatingGroup(panel4.api.group);
|
||||
|
||||
dockview.moveGroupOrPanel(
|
||||
panel1.group,
|
||||
panel6.group.id,
|
||||
panel6.id,
|
||||
'center'
|
||||
);
|
||||
// dockview.addPopoutGroup(panel6);
|
||||
|
||||
dockview.moveGroupOrPanel(
|
||||
panel4.group,
|
||||
panel6.group.id,
|
||||
panel6.id,
|
||||
'center'
|
||||
);
|
||||
// dockview.moveGroupOrPanel(
|
||||
// panel1.group,
|
||||
// panel6.group.id,
|
||||
// panel6.id,
|
||||
// 'center'
|
||||
// );
|
||||
|
||||
dockview.dispose();
|
||||
// dockview.moveGroupOrPanel(
|
||||
// panel4.group,
|
||||
// panel6.group.id,
|
||||
// panel6.id,
|
||||
// 'center'
|
||||
// );
|
||||
|
||||
if (Emitter.MEMORY_LEAK_WATCHER.size > 0) {
|
||||
for (const entry of Array.from(
|
||||
Emitter.MEMORY_LEAK_WATCHER.events
|
||||
)) {
|
||||
console.log('disposal', entry[1]);
|
||||
}
|
||||
throw new Error('not all listeners disposed');
|
||||
}
|
||||
// dockview.dispose();
|
||||
|
||||
Emitter.setLeakageMonitorEnabled(false);
|
||||
});
|
||||
});
|
||||
// if (Emitter.MEMORY_LEAK_WATCHER.size > 0) {
|
||||
// for (const entry of Array.from(
|
||||
// Emitter.MEMORY_LEAK_WATCHER.events
|
||||
// )) {
|
||||
// console.log('disposal', entry[1]);
|
||||
// }
|
||||
// throw new Error('not all listeners disposed');
|
||||
// }
|
||||
|
||||
// Emitter.setLeakageMonitorEnabled(false);
|
||||
// });
|
||||
// });
|
||||
|
||||
test('duplicate panel', () => {
|
||||
dockview.layout(500, 1000);
|
||||
@ -3452,8 +3459,8 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
|
||||
@ -3464,8 +3471,8 @@ describe('dockviewComponent', () => {
|
||||
'right'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
});
|
||||
@ -3497,8 +3504,8 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
|
||||
@ -3509,8 +3516,8 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
});
|
||||
@ -3548,9 +3555,9 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -3561,9 +3568,9 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -3601,9 +3608,9 @@ describe('dockviewComponent', () => {
|
||||
position: { referencePanel: panel2 },
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -3614,9 +3621,9 @@ describe('dockviewComponent', () => {
|
||||
'right'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -3654,9 +3661,9 @@ describe('dockviewComponent', () => {
|
||||
position: { referencePanel: panel2 },
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -3667,9 +3674,9 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -3713,10 +3720,10 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel4.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(panel4.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(dockview.panels.length).toBe(4);
|
||||
|
||||
@ -3727,10 +3734,10 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel4.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(panel4.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(4);
|
||||
});
|
||||
@ -3762,8 +3769,8 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
|
||||
@ -3774,8 +3781,8 @@ describe('dockviewComponent', () => {
|
||||
'right'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
});
|
||||
@ -3807,8 +3814,8 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
|
||||
@ -3819,8 +3826,8 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
});
|
||||
@ -3858,9 +3865,9 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -3871,9 +3878,9 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -3911,9 +3918,9 @@ describe('dockviewComponent', () => {
|
||||
position: { referencePanel: panel2 },
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -3924,9 +3931,9 @@ describe('dockviewComponent', () => {
|
||||
'right'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -3964,9 +3971,9 @@ describe('dockviewComponent', () => {
|
||||
position: { referencePanel: panel2 },
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -3977,9 +3984,9 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -4023,10 +4030,10 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel4.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(panel4.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(dockview.panels.length).toBe(4);
|
||||
|
||||
@ -4037,10 +4044,10 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel4.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(panel4.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(dockview.panels.length).toBe(4);
|
||||
});
|
||||
@ -4078,9 +4085,9 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -4091,9 +4098,9 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('floating');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('floating');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -4130,9 +4137,9 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -4143,9 +4150,9 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('floating');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('floating');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -4183,9 +4190,9 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -4196,9 +4203,9 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('floating');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('floating');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -4235,9 +4242,9 @@ describe('dockviewComponent', () => {
|
||||
floating: true,
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
@ -4248,9 +4255,9 @@ describe('dockviewComponent', () => {
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('floating');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel3.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('floating');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(panel3.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
@ -4282,15 +4289,15 @@ describe('dockviewComponent', () => {
|
||||
position: { direction: 'right' },
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
|
||||
dockview.addFloatingGroup(panel2);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
});
|
||||
@ -4321,15 +4328,15 @@ describe('dockviewComponent', () => {
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
|
||||
dockview.addFloatingGroup(panel2);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
});
|
||||
@ -4361,15 +4368,15 @@ describe('dockviewComponent', () => {
|
||||
position: { direction: 'right' },
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
|
||||
dockview.addFloatingGroup(panel2.group);
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
});
|
||||
@ -4400,22 +4407,40 @@ describe('dockviewComponent', () => {
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
|
||||
dockview.addFloatingGroup(panel2.group);
|
||||
|
||||
expect(panel1.group.api.location).toBe('floating');
|
||||
expect(panel2.group.api.location).toBe('floating');
|
||||
expect(panel1.group.api.location.type).toBe('floating');
|
||||
expect(panel2.group.api.location.type).toBe('floating');
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('popout group', () => {
|
||||
test('that can remove a popout group', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(window, 'open').mockReturnValue(
|
||||
fromPartial<Window>({
|
||||
document: fromPartial<Document>({
|
||||
body: document.createElement('body'),
|
||||
}),
|
||||
addEventListener: jest
|
||||
.fn()
|
||||
.mockImplementation((name, cb) => {
|
||||
if (name === 'load') {
|
||||
cb();
|
||||
}
|
||||
}),
|
||||
close: jest.fn(),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test('that can remove a popout group', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
@ -4436,11 +4461,11 @@ describe('dockviewComponent', () => {
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
dockview.addPopoutGroup(panel1);
|
||||
await dockview.addPopoutGroup(panel1);
|
||||
|
||||
expect(dockview.panels.length).toBe(1);
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(panel1.api.group.api.location).toBe('popout');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(panel1.api.group.api.location.type).toBe('popout');
|
||||
|
||||
dockview.removePanel(panel1);
|
||||
|
||||
@ -4448,7 +4473,7 @@ describe('dockviewComponent', () => {
|
||||
expect(dockview.groups.length).toBe(0);
|
||||
});
|
||||
|
||||
test('add a popout group', () => {
|
||||
test('add a popout group', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
@ -4474,20 +4499,20 @@ describe('dockviewComponent', () => {
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
|
||||
dockview.addPopoutGroup(panel2.group);
|
||||
await dockview.addPopoutGroup(panel2.group);
|
||||
|
||||
expect(panel1.group.api.location).toBe('popout');
|
||||
expect(panel2.group.api.location).toBe('popout');
|
||||
expect(dockview.groups.length).toBe(1);
|
||||
expect(panel1.group.api.location.type).toBe('popout');
|
||||
expect(panel2.group.api.location.type).toBe('popout');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(2);
|
||||
});
|
||||
|
||||
test('move from fixed to popout group and back', () => {
|
||||
test('move from fixed to popout group and back', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const dockview = new DockviewComponent({
|
||||
@ -4521,18 +4546,18 @@ describe('dockviewComponent', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(panel1.group.api.location).toBe('grid');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('grid');
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
dockview.addPopoutGroup(panel2.group);
|
||||
await dockview.addPopoutGroup(panel2.group);
|
||||
|
||||
expect(panel1.group.api.location).toBe('popout');
|
||||
expect(panel2.group.api.location).toBe('popout');
|
||||
expect(panel3.group.api.location).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(panel1.group.api.location.type).toBe('popout');
|
||||
expect(panel2.group.api.location.type).toBe('popout');
|
||||
expect(panel3.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
dockview.moveGroupOrPanel(
|
||||
@ -4542,10 +4567,23 @@ describe('dockviewComponent', () => {
|
||||
'right'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location).toBe('popout');
|
||||
expect(panel2.group.api.location).toBe('grid');
|
||||
expect(panel3.group.api.location).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(3);
|
||||
expect(panel1.group.api.location.type).toBe('popout');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(4);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
|
||||
dockview.moveGroupOrPanel(
|
||||
panel3.api.group,
|
||||
panel1.api.group.id,
|
||||
panel1.api.id,
|
||||
'center'
|
||||
);
|
||||
|
||||
expect(panel1.group.api.location.type).toBe('grid');
|
||||
expect(panel2.group.api.location.type).toBe('grid');
|
||||
expect(panel3.group.api.location.type).toBe('grid');
|
||||
expect(dockview.groups.length).toBe(2);
|
||||
expect(dockview.panels.length).toBe(3);
|
||||
});
|
||||
});
|
||||
|
@ -268,7 +268,7 @@ describe('gridview', () => {
|
||||
],
|
||||
},
|
||||
},
|
||||
activePanel: 'panel_1',
|
||||
activePanel: 'panel_2',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -41,7 +41,7 @@ describe('overlayRenderContainer', () => {
|
||||
},
|
||||
group: {
|
||||
api: {
|
||||
location: 'grid',
|
||||
location: { type: 'grid' },
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -77,7 +77,7 @@ describe('overlayRenderContainer', () => {
|
||||
},
|
||||
group: {
|
||||
api: {
|
||||
location: 'grid',
|
||||
location: { type: 'grid' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -830,8 +830,10 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
|
||||
options?: {
|
||||
position?: Box;
|
||||
popoutUrl?: string;
|
||||
onDidOpen?: (event: { id: string; window: Window }) => void;
|
||||
onWillClose?: (event: { id: string; window: Window }) => void;
|
||||
}
|
||||
): void {
|
||||
this.component.addPopoutGroup(item, options);
|
||||
): Promise<void> {
|
||||
return this.component.addPopoutGroup(item, options);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,10 @@ import { GridviewPanelApi, GridviewPanelApiImpl } from './gridviewPanelApi';
|
||||
export interface DockviewGroupPanelApi extends GridviewPanelApi {
|
||||
readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent>;
|
||||
readonly location: DockviewGroupLocation;
|
||||
/**
|
||||
* If you require the Window object
|
||||
*/
|
||||
getWindow(): Window;
|
||||
moveTo(options: { group?: DockviewGroupPanel; position?: Position }): void;
|
||||
maximize(): void;
|
||||
isMaximized(): boolean;
|
||||
@ -42,6 +46,12 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
|
||||
this.addDisposables(this._onDidLocationChange);
|
||||
}
|
||||
|
||||
getWindow(): Window {
|
||||
return this.location.type === 'popout'
|
||||
? this.location.getWindow()
|
||||
: window;
|
||||
}
|
||||
|
||||
moveTo(options: { group?: DockviewGroupPanel; position?: Position }): void {
|
||||
if (!this._group) {
|
||||
throw new Error(NOT_INITIALIZED_MESSAGE);
|
||||
@ -66,7 +76,7 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
|
||||
throw new Error(NOT_INITIALIZED_MESSAGE);
|
||||
}
|
||||
|
||||
if (this.location !== 'grid') {
|
||||
if (this.location.type !== 'grid') {
|
||||
// only grid groups can be maximized
|
||||
return;
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { Emitter, Event } from '../events';
|
||||
import { GridviewPanelApiImpl, GridviewPanelApi } from './gridviewPanelApi';
|
||||
import { DockviewGroupPanel } from '../dockview/dockviewGroupPanel';
|
||||
import { MutableDisposable } from '../lifecycle';
|
||||
import { CompositeDisposable, MutableDisposable } from '../lifecycle';
|
||||
import { DockviewPanel } from '../dockview/dockviewPanel';
|
||||
import { DockviewComponent } from '../dockview/dockviewComponent';
|
||||
import { Position } from '../dnd/droptarget';
|
||||
import { DockviewPanelRenderer } from '../overlayRenderContainer';
|
||||
import { DockviewGroupPanelFloatingChangeEvent } from './dockviewGroupPanelApi';
|
||||
import { DockviewGroupLocation } from '../dockview/dockviewGroupPanelModel';
|
||||
|
||||
export interface TitleEvent {
|
||||
readonly title: string;
|
||||
@ -28,6 +30,8 @@ export interface DockviewPanelApi
|
||||
readonly onDidActiveGroupChange: Event<void>;
|
||||
readonly onDidGroupChange: Event<void>;
|
||||
readonly onDidRendererChange: Event<RendererChangedEvent>;
|
||||
readonly location: DockviewGroupLocation;
|
||||
readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent>;
|
||||
close(): void;
|
||||
setTitle(title: string): void;
|
||||
setRenderer(renderer: DockviewPanelRenderer): void;
|
||||
@ -39,6 +43,10 @@ export interface DockviewPanelApi
|
||||
maximize(): void;
|
||||
isMaximized(): boolean;
|
||||
exitMaximized(): void;
|
||||
/**
|
||||
* If you require the Window object
|
||||
*/
|
||||
getWindow(): Window;
|
||||
}
|
||||
|
||||
export class DockviewPanelApiImpl
|
||||
@ -59,7 +67,16 @@ export class DockviewPanelApiImpl
|
||||
readonly _onDidRendererChange = new Emitter<RendererChangedEvent>();
|
||||
readonly onDidRendererChange = this._onDidRendererChange.event;
|
||||
|
||||
private readonly disposable = new MutableDisposable();
|
||||
private readonly _onDidLocationChange =
|
||||
new Emitter<DockviewGroupPanelFloatingChangeEvent>();
|
||||
readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent> =
|
||||
this._onDidLocationChange.event;
|
||||
|
||||
private readonly groupEventsDisposable = new MutableDisposable();
|
||||
|
||||
get location(): DockviewGroupLocation {
|
||||
return this.group.api.location;
|
||||
}
|
||||
|
||||
get title(): string | undefined {
|
||||
return this.panel.title;
|
||||
@ -81,13 +98,22 @@ export class DockviewPanelApiImpl
|
||||
this._onDidGroupChange.fire();
|
||||
|
||||
if (this._group) {
|
||||
this.disposable.value = this._group.api.onDidActiveChange(() => {
|
||||
this._onDidActiveGroupChange.fire();
|
||||
});
|
||||
this.groupEventsDisposable.value = new CompositeDisposable(
|
||||
this.group.api.onDidLocationChange((event) => {
|
||||
this._onDidLocationChange.fire(event);
|
||||
}),
|
||||
this.group.api.onDidActiveChange(() => {
|
||||
this._onDidActiveGroupChange.fire();
|
||||
})
|
||||
);
|
||||
|
||||
if (this.isGroupActive !== isOldGroupActive) {
|
||||
this._onDidActiveGroupChange.fire();
|
||||
}
|
||||
|
||||
this._onDidLocationChange.fire({
|
||||
location: this.group.api.location,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,14 +133,19 @@ export class DockviewPanelApiImpl
|
||||
this._group = group;
|
||||
|
||||
this.addDisposables(
|
||||
this.disposable,
|
||||
this.groupEventsDisposable,
|
||||
this._onDidRendererChange,
|
||||
this._onDidTitleChange,
|
||||
this._onDidGroupChange,
|
||||
this._onDidActiveGroupChange
|
||||
this._onDidActiveGroupChange,
|
||||
this._onDidLocationChange
|
||||
);
|
||||
}
|
||||
|
||||
getWindow(): Window {
|
||||
return this.group.api.getWindow();
|
||||
}
|
||||
|
||||
moveTo(options: {
|
||||
group: DockviewGroupPanel;
|
||||
position?: Position;
|
||||
|
@ -14,6 +14,10 @@ export interface VisibilityEvent {
|
||||
readonly isVisible: boolean;
|
||||
}
|
||||
|
||||
export interface HiddenEvent {
|
||||
readonly isHidden: boolean;
|
||||
}
|
||||
|
||||
export interface ActiveEvent {
|
||||
readonly isActive: boolean;
|
||||
}
|
||||
@ -24,7 +28,7 @@ export interface PanelApi {
|
||||
readonly onDidFocusChange: Event<FocusEvent>;
|
||||
readonly onDidVisibilityChange: Event<VisibilityEvent>;
|
||||
readonly onDidActiveChange: Event<ActiveEvent>;
|
||||
setVisible(isVisible: boolean): void;
|
||||
readonly onDidHiddenChange: Event<HiddenEvent>;
|
||||
setActive(): void;
|
||||
updateParameters(parameters: Parameters): void;
|
||||
/**
|
||||
@ -43,6 +47,10 @@ export interface PanelApi {
|
||||
* Whether the panel is visible
|
||||
*/
|
||||
readonly isVisible: boolean;
|
||||
/**
|
||||
* Whether the panel is hidden
|
||||
*/
|
||||
readonly isHidden: boolean;
|
||||
/**
|
||||
* The panel width in pixels
|
||||
*/
|
||||
@ -60,6 +68,7 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
||||
private _isFocused = false;
|
||||
private _isActive = false;
|
||||
private _isVisible = true;
|
||||
private _isHidden = false;
|
||||
private _width = 0;
|
||||
private _height = 0;
|
||||
|
||||
@ -69,56 +78,59 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
||||
replay: true,
|
||||
});
|
||||
readonly onDidDimensionsChange = this._onDidDimensionChange.event;
|
||||
//
|
||||
|
||||
readonly _onDidChangeFocus = new Emitter<FocusEvent>({
|
||||
replay: true,
|
||||
});
|
||||
readonly onDidFocusChange: Event<FocusEvent> = this._onDidChangeFocus.event;
|
||||
//
|
||||
|
||||
readonly _onFocusEvent = new Emitter<void>();
|
||||
readonly onFocusEvent: Event<void> = this._onFocusEvent.event;
|
||||
//
|
||||
|
||||
readonly _onDidVisibilityChange = new Emitter<VisibilityEvent>({
|
||||
replay: true,
|
||||
});
|
||||
readonly onDidVisibilityChange: Event<VisibilityEvent> =
|
||||
this._onDidVisibilityChange.event;
|
||||
//
|
||||
|
||||
readonly _onVisibilityChange = new Emitter<VisibilityEvent>();
|
||||
readonly onVisibilityChange: Event<VisibilityEvent> =
|
||||
this._onVisibilityChange.event;
|
||||
//
|
||||
readonly _onDidHiddenChange = new Emitter<HiddenEvent>();
|
||||
readonly onDidHiddenChange: Event<HiddenEvent> =
|
||||
this._onDidHiddenChange.event;
|
||||
|
||||
readonly _onDidActiveChange = new Emitter<ActiveEvent>({
|
||||
replay: true,
|
||||
});
|
||||
readonly onDidActiveChange: Event<ActiveEvent> =
|
||||
this._onDidActiveChange.event;
|
||||
//
|
||||
|
||||
readonly _onActiveChange = new Emitter<void>();
|
||||
readonly onActiveChange: Event<void> = this._onActiveChange.event;
|
||||
//
|
||||
|
||||
readonly _onUpdateParameters = new Emitter<Parameters>();
|
||||
readonly onUpdateParameters: Event<Parameters> =
|
||||
this._onUpdateParameters.event;
|
||||
//
|
||||
|
||||
get isFocused() {
|
||||
get isFocused(): boolean {
|
||||
return this._isFocused;
|
||||
}
|
||||
|
||||
get isActive() {
|
||||
get isActive(): boolean {
|
||||
return this._isActive;
|
||||
}
|
||||
get isVisible() {
|
||||
|
||||
get isVisible(): boolean {
|
||||
return this._isVisible;
|
||||
}
|
||||
|
||||
get width() {
|
||||
get isHidden(): boolean {
|
||||
return this._isHidden;
|
||||
}
|
||||
|
||||
get width(): number {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
get height() {
|
||||
get height(): number {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
@ -135,6 +147,9 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
||||
this.onDidVisibilityChange((event) => {
|
||||
this._isVisible = event.isVisible;
|
||||
}),
|
||||
this.onDidHiddenChange((event) => {
|
||||
this._isHidden = event.isHidden;
|
||||
}),
|
||||
this.onDidDimensionsChange((event) => {
|
||||
this._width = event.width;
|
||||
this._height = event.height;
|
||||
@ -146,7 +161,7 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
||||
this._onDidActiveChange,
|
||||
this._onFocusEvent,
|
||||
this._onActiveChange,
|
||||
this._onVisibilityChange,
|
||||
this._onDidHiddenChange,
|
||||
this._onUpdateParameters
|
||||
);
|
||||
}
|
||||
@ -161,8 +176,8 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
||||
);
|
||||
}
|
||||
|
||||
setVisible(isVisible: boolean) {
|
||||
this._onVisibilityChange.fire({ isVisible });
|
||||
setHidden(isHidden: boolean): void {
|
||||
this._onDidHiddenChange.fire({ isHidden });
|
||||
}
|
||||
|
||||
setActive(): void {
|
||||
@ -172,8 +187,4 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
|
||||
updateParameters(parameters: Parameters): void {
|
||||
this._onUpdateParameters.fire(parameters);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ export class GroupDragHandler extends DragHandler {
|
||||
}
|
||||
|
||||
override isCancelled(_event: DragEvent): boolean {
|
||||
if (this.group.api.location === 'floating' && !_event.shiftKey) {
|
||||
if (this.group.api.location.type === 'floating' && !_event.shiftKey) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -71,7 +71,7 @@ export class ContentContainer
|
||||
if (
|
||||
!data &&
|
||||
event.shiftKey &&
|
||||
this.group.location !== 'floating'
|
||||
this.group.location.type !== 'floating'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ export class TabsContainer
|
||||
if (
|
||||
isFloatingGroupsEnabled &&
|
||||
event.shiftKey &&
|
||||
this.group.api.location !== 'floating'
|
||||
this.group.api.location.type !== 'floating'
|
||||
) {
|
||||
event.preventDefault();
|
||||
|
||||
@ -350,7 +350,8 @@ export class TabsContainer
|
||||
!this.accessor.options.disableFloatingGroups;
|
||||
|
||||
const isFloatingWithOnePanel =
|
||||
this.group.api.location === 'floating' && this.size === 1;
|
||||
this.group.api.location.type === 'floating' &&
|
||||
this.size === 1;
|
||||
|
||||
if (
|
||||
isFloatingGroupsEnabled &&
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
} from '../dnd/droptarget';
|
||||
import { tail, sequenceEquals, remove } from '../array';
|
||||
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
|
||||
import { CompositeDisposable, Disposable } from '../lifecycle';
|
||||
import { CompositeDisposable, Disposable, IDisposable } from '../lifecycle';
|
||||
import { Event, Emitter } from '../events';
|
||||
import { Watermark } from './components/watermark/watermark';
|
||||
import {
|
||||
@ -58,7 +58,6 @@ import {
|
||||
TabDragEvent,
|
||||
} from './components/titlebar/tabsContainer';
|
||||
import { Box } from '../types';
|
||||
import { DockviewPopoutGroupPanel } from './dockviewPopoutGroupPanel';
|
||||
import {
|
||||
DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
|
||||
DEFAULT_FLOATING_GROUP_POSITION,
|
||||
@ -67,13 +66,14 @@ import {
|
||||
DockviewPanelRenderer,
|
||||
OverlayRenderContainer,
|
||||
} from '../overlayRenderContainer';
|
||||
import { PopoutWindow } from '../popoutWindow';
|
||||
|
||||
const DEFAULT_ROOT_OVERLAY_MODEL: DroptargetOverlayModel = {
|
||||
activationSize: { type: 'pixels', value: 10 },
|
||||
size: { type: 'pixels', value: 20 },
|
||||
};
|
||||
|
||||
function getTheme(element: HTMLElement): string | undefined {
|
||||
function getDockviewTheme(element: HTMLElement): string | undefined {
|
||||
function toClassList(element: HTMLElement) {
|
||||
const list: string[] = [];
|
||||
|
||||
@ -286,8 +286,10 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
|
||||
options?: {
|
||||
position?: Box;
|
||||
popoutUrl?: string;
|
||||
onDidOpen?: (event: { id: string; window: Window }) => void;
|
||||
onWillClose?: (event: { id: string; window: Window }) => void;
|
||||
}
|
||||
): void;
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
export class DockviewComponent
|
||||
@ -329,7 +331,12 @@ export class DockviewComponent
|
||||
this._onDidActivePanelChange.event;
|
||||
|
||||
private readonly _floatingGroups: DockviewFloatingGroupPanel[] = [];
|
||||
private readonly _popoutGroups: DockviewPopoutGroupPanel[] = [];
|
||||
private readonly _popoutGroups: {
|
||||
window: PopoutWindow;
|
||||
popoutGroup: DockviewGroupPanel;
|
||||
referenceGroup: DockviewGroupPanel;
|
||||
disposable: IDisposable;
|
||||
}[] = [];
|
||||
private readonly _rootDropTarget: Droptarget;
|
||||
|
||||
get orientation(): Orientation {
|
||||
@ -410,7 +417,7 @@ export class DockviewComponent
|
||||
|
||||
// iterate over a copy of the array since .dispose() mutates the original array
|
||||
for (const group of [...this._popoutGroups]) {
|
||||
group.dispose();
|
||||
group.disposable.dispose();
|
||||
}
|
||||
})
|
||||
);
|
||||
@ -513,71 +520,144 @@ export class DockviewComponent
|
||||
skipRemoveGroup?: boolean;
|
||||
position?: Box;
|
||||
popoutUrl?: string;
|
||||
onDidOpen?: (event: { id: string; window: Window }) => void;
|
||||
onWillClose?: (event: { id: string; window: Window }) => void;
|
||||
}
|
||||
): Promise<void> {
|
||||
if (item instanceof DockviewPanel && item.group.size === 1) {
|
||||
return this.addPopoutGroup(item.group);
|
||||
}
|
||||
): void {
|
||||
let group: DockviewGroupPanel;
|
||||
let box: Box | undefined = options?.position;
|
||||
|
||||
if (item instanceof DockviewPanel) {
|
||||
group = this.createGroup();
|
||||
const theme = getDockviewTheme(this.gridview.element);
|
||||
const element = this.element;
|
||||
|
||||
this.removePanel(item, {
|
||||
removeEmptyGroup: true,
|
||||
skipDispose: true,
|
||||
function moveGroupWithoutDestroying(options: {
|
||||
from: DockviewGroupPanel;
|
||||
to: DockviewGroupPanel;
|
||||
}) {
|
||||
const panels = [...options.from.panels].map((panel) =>
|
||||
options.from.model.removePanel(panel)
|
||||
);
|
||||
|
||||
panels.forEach((panel) => {
|
||||
options.to.model.openPanel(panel);
|
||||
});
|
||||
|
||||
group.model.openPanel(item);
|
||||
|
||||
if (!box) {
|
||||
box = this.element.getBoundingClientRect();
|
||||
}
|
||||
} else {
|
||||
group = item;
|
||||
|
||||
if (!box) {
|
||||
box = group.element.getBoundingClientRect();
|
||||
}
|
||||
|
||||
const skip =
|
||||
typeof options?.skipRemoveGroup === 'boolean' &&
|
||||
options.skipRemoveGroup;
|
||||
|
||||
if (!skip) {
|
||||
this.doRemoveGroup(item, { skipDispose: true });
|
||||
}
|
||||
}
|
||||
|
||||
const theme = getTheme(this.gridview.element);
|
||||
function getBox(): Box {
|
||||
if (options?.position) {
|
||||
return options.position;
|
||||
}
|
||||
|
||||
const popoutWindow = new DockviewPopoutGroupPanel(
|
||||
`${this.id}-${group.id}`, // globally unique within dockview
|
||||
group,
|
||||
if (item instanceof DockviewGroupPanel) {
|
||||
return item.element.getBoundingClientRect();
|
||||
}
|
||||
|
||||
if (item.group) {
|
||||
return item.group.element.getBoundingClientRect();
|
||||
}
|
||||
return element.getBoundingClientRect();
|
||||
}
|
||||
|
||||
const box: Box = getBox();
|
||||
|
||||
const groupId = this.getNextGroupId(); //item.id;
|
||||
|
||||
item.api.setHidden(true);
|
||||
|
||||
const _window = new PopoutWindow(
|
||||
`${this.id}-${groupId}`, // unique id
|
||||
theme ?? '',
|
||||
{
|
||||
className: theme ?? '',
|
||||
popoutUrl: options?.popoutUrl ?? '/popout.html',
|
||||
box: {
|
||||
left: window.screenX + box.left,
|
||||
top: window.screenY + box.top,
|
||||
width: box.width,
|
||||
height: box.height,
|
||||
},
|
||||
url: options?.popoutUrl ?? '/popout.html',
|
||||
left: window.screenX + box.left,
|
||||
top: window.screenY + box.top,
|
||||
width: box.width,
|
||||
height: box.height,
|
||||
onDidOpen: options?.onDidOpen,
|
||||
onWillClose: options?.onWillClose,
|
||||
}
|
||||
);
|
||||
|
||||
popoutWindow.addDisposables(
|
||||
{
|
||||
dispose: () => {
|
||||
remove(this._popoutGroups, popoutWindow);
|
||||
this.updateWatermark();
|
||||
},
|
||||
},
|
||||
popoutWindow.window.onDidClose(() => {
|
||||
this.doAddGroup(group, [0]);
|
||||
const popoutWindowDisposable = new CompositeDisposable(
|
||||
_window,
|
||||
_window.onDidClose(() => {
|
||||
popoutWindowDisposable.dispose();
|
||||
})
|
||||
);
|
||||
|
||||
this._popoutGroups.push(popoutWindow);
|
||||
this.updateWatermark();
|
||||
return _window
|
||||
.open()
|
||||
.then((popoutContainer) => {
|
||||
if (_window.isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (popoutContainer === null) {
|
||||
popoutWindowDisposable.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
const referenceGroup =
|
||||
item instanceof DockviewPanel ? item.group : item;
|
||||
|
||||
const group = this.createGroup({ id: groupId });
|
||||
|
||||
if (item instanceof DockviewPanel) {
|
||||
const panel = referenceGroup.model.removePanel(item);
|
||||
group.model.openPanel(panel);
|
||||
} else {
|
||||
moveGroupWithoutDestroying({
|
||||
from: referenceGroup,
|
||||
to: group,
|
||||
});
|
||||
referenceGroup.api.setHidden(false);
|
||||
}
|
||||
|
||||
popoutContainer.appendChild(group.element);
|
||||
|
||||
group.model.location = {
|
||||
type: 'popout',
|
||||
getWindow: () => _window.window!,
|
||||
};
|
||||
|
||||
const value = {
|
||||
window: _window,
|
||||
popoutGroup: group,
|
||||
referenceGroup,
|
||||
disposable: popoutWindowDisposable,
|
||||
};
|
||||
|
||||
popoutWindowDisposable.addDisposables(
|
||||
Disposable.from(() => {
|
||||
if (this.getPanel(referenceGroup.id)) {
|
||||
moveGroupWithoutDestroying({
|
||||
from: group,
|
||||
to: referenceGroup,
|
||||
});
|
||||
|
||||
if (referenceGroup.api.isHidden) {
|
||||
referenceGroup.api.setHidden(false);
|
||||
}
|
||||
|
||||
this.doRemoveGroup(group);
|
||||
} else {
|
||||
const removedGroup = this.doRemoveGroup(group, {
|
||||
skipDispose: true,
|
||||
skipActive: true,
|
||||
});
|
||||
removedGroup.model.location = { type: 'grid' };
|
||||
this.doAddGroup(removedGroup, [0]);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this._popoutGroups.push(value);
|
||||
this.updateWatermark();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
addFloatingGroup(
|
||||
@ -608,7 +688,7 @@ export class DockviewComponent
|
||||
}
|
||||
}
|
||||
|
||||
group.model.location = 'floating';
|
||||
group.model.location = { type: 'floating' };
|
||||
|
||||
const overlayLeft =
|
||||
typeof coord?.x === 'number'
|
||||
@ -683,7 +763,7 @@ export class DockviewComponent
|
||||
dispose: () => {
|
||||
disposable.dispose();
|
||||
|
||||
group.model.location = 'grid';
|
||||
group.model.location = { type: 'grid' };
|
||||
remove(this._floatingGroups, floatingGroupPanel);
|
||||
this.updateWatermark();
|
||||
},
|
||||
@ -876,7 +956,7 @@ export class DockviewComponent
|
||||
const popoutGroups: SerializedPopoutGroup[] = this._popoutGroups.map(
|
||||
(group) => {
|
||||
return {
|
||||
data: group.group.toJSON() as GroupPanelViewState,
|
||||
data: group.popoutGroup.toJSON() as GroupPanelViewState,
|
||||
position: group.window.dimensions(),
|
||||
};
|
||||
}
|
||||
@ -1173,7 +1253,7 @@ export class DockviewComponent
|
||||
group.model.openPanel(panel);
|
||||
this.doSetGroupAndPanelActive(group);
|
||||
} else if (
|
||||
referenceGroup.api.location === 'floating' ||
|
||||
referenceGroup.api.location.type === 'floating' ||
|
||||
target === 'center'
|
||||
) {
|
||||
panel = this.createPanel(options, referenceGroup);
|
||||
@ -1259,7 +1339,11 @@ export class DockviewComponent
|
||||
}
|
||||
|
||||
private updateWatermark(): void {
|
||||
if (this.groups.filter((x) => x.api.location === 'grid').length === 0) {
|
||||
if (
|
||||
this.groups.filter(
|
||||
(x) => x.api.location.type === 'grid' && !x.api.isHidden
|
||||
).length === 0
|
||||
) {
|
||||
if (!this.watermark) {
|
||||
this.watermark = this.createWatermarkComponent();
|
||||
|
||||
@ -1377,7 +1461,7 @@ export class DockviewComponent
|
||||
}
|
||||
| undefined
|
||||
): DockviewGroupPanel {
|
||||
if (group.api.location === 'floating') {
|
||||
if (group.api.location.type === 'floating') {
|
||||
const floatingGroup = this._floatingGroups.find(
|
||||
(_) => _.group === group
|
||||
);
|
||||
@ -1406,19 +1490,21 @@ export class DockviewComponent
|
||||
throw new Error('failed to find floating group');
|
||||
}
|
||||
|
||||
if (group.api.location === 'popout') {
|
||||
if (group.api.location.type === 'popout') {
|
||||
const selectedGroup = this._popoutGroups.find(
|
||||
(_) => _.group === group
|
||||
(_) => _.popoutGroup === group
|
||||
);
|
||||
|
||||
if (selectedGroup) {
|
||||
if (!options?.skipDispose) {
|
||||
selectedGroup.group.dispose();
|
||||
this.doRemoveGroup(selectedGroup.referenceGroup);
|
||||
|
||||
selectedGroup.popoutGroup.dispose();
|
||||
this._groups.delete(group.id);
|
||||
this._onDidRemoveGroup.fire(group);
|
||||
}
|
||||
|
||||
selectedGroup.dispose();
|
||||
selectedGroup.disposable.dispose();
|
||||
|
||||
if (!options?.skipActive && this._activeGroup === group) {
|
||||
const groups = Array.from(this._groups.values());
|
||||
@ -1428,7 +1514,8 @@ export class DockviewComponent
|
||||
);
|
||||
}
|
||||
|
||||
return selectedGroup.group;
|
||||
this.updateWatermark();
|
||||
return selectedGroup.popoutGroup;
|
||||
}
|
||||
|
||||
throw new Error('failed to find popout group');
|
||||
@ -1486,7 +1573,7 @@ export class DockviewComponent
|
||||
if (sourceGroup && sourceGroup.size < 2) {
|
||||
const [targetParentLocation, to] = tail(targetLocation);
|
||||
|
||||
if (sourceGroup.api.location === 'grid') {
|
||||
if (sourceGroup.api.location.type === 'grid') {
|
||||
const sourceLocation = getGridLocation(sourceGroup.element);
|
||||
const [sourceParentLocation, from] = tail(sourceLocation);
|
||||
|
||||
@ -1562,7 +1649,7 @@ export class DockviewComponent
|
||||
});
|
||||
}
|
||||
} else {
|
||||
switch (sourceGroup.api.location) {
|
||||
switch (sourceGroup.api.location.type) {
|
||||
case 'grid':
|
||||
this.gridview.removeView(
|
||||
getGridLocation(sourceGroup.element)
|
||||
@ -1580,12 +1667,12 @@ export class DockviewComponent
|
||||
}
|
||||
case 'popout': {
|
||||
const selectedPopoutGroup = this._popoutGroups.find(
|
||||
(x) => x.group === sourceGroup
|
||||
(x) => x.popoutGroup === sourceGroup
|
||||
);
|
||||
if (!selectedPopoutGroup) {
|
||||
throw new Error('failed to find popout group');
|
||||
}
|
||||
selectedPopoutGroup.dispose();
|
||||
selectedPopoutGroup.disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1619,6 +1706,15 @@ export class DockviewComponent
|
||||
}
|
||||
}
|
||||
|
||||
private getNextGroupId(): string {
|
||||
let id = this.nextGroupId.next();
|
||||
while (this._groups.has(id)) {
|
||||
id = this.nextGroupId.next();
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
createGroup(options?: GroupOptions): DockviewGroupPanel {
|
||||
if (!options) {
|
||||
options = {};
|
||||
@ -1641,7 +1737,7 @@ export class DockviewComponent
|
||||
}
|
||||
|
||||
const view = new DockviewGroupPanel(this, id, options);
|
||||
view.init({ params: {}, accessor: <any>null }); // required to initialized .part and allow for correct disposal of group
|
||||
view.init({ params: {}, accessor: this });
|
||||
|
||||
if (!this._groups.has(view.id)) {
|
||||
const disposable = new CompositeDisposable(
|
||||
@ -1676,8 +1772,7 @@ export class DockviewComponent
|
||||
this._groups.set(view.id, { value: view, disposable });
|
||||
}
|
||||
|
||||
// TODO: must be called after the above listeners have been setup,
|
||||
// not an ideal pattern
|
||||
// TODO: must be called after the above listeners have been setup, not an ideal pattern
|
||||
view.initialize();
|
||||
|
||||
return view;
|
||||
|
@ -130,7 +130,10 @@ export interface IDockviewGroupPanelModel extends IPanel {
|
||||
): boolean;
|
||||
}
|
||||
|
||||
export type DockviewGroupLocation = 'grid' | 'floating' | 'popout';
|
||||
export type DockviewGroupLocation =
|
||||
| { type: 'grid' }
|
||||
| { type: 'floating' }
|
||||
| { type: 'popout'; getWindow: () => Window };
|
||||
|
||||
export class DockviewGroupPanelModel
|
||||
extends CompositeDisposable
|
||||
@ -146,7 +149,7 @@ export class DockviewGroupPanelModel
|
||||
private _leftHeaderActions: IHeaderActionsRenderer | undefined;
|
||||
private _prefixHeaderActions: IHeaderActionsRenderer | undefined;
|
||||
|
||||
private _location: DockviewGroupLocation = 'grid';
|
||||
private _location: DockviewGroupLocation = { type: 'grid' };
|
||||
|
||||
private mostRecentlyUsed: IDockviewPanel[] = [];
|
||||
|
||||
@ -253,7 +256,7 @@ export class DockviewGroupPanelModel
|
||||
toggleClass(this.container, 'dv-groupview-floating', false);
|
||||
toggleClass(this.container, 'dv-groupview-popout', false);
|
||||
|
||||
switch (value) {
|
||||
switch (value.type) {
|
||||
case 'grid':
|
||||
this.contentContainer.dropTarget.setTargetZones([
|
||||
'top',
|
||||
@ -835,6 +838,7 @@ export class DockviewGroupPanelModel
|
||||
|
||||
this.watermark?.element.remove();
|
||||
this.watermark?.dispose?.();
|
||||
this.watermark = undefined;
|
||||
|
||||
for (const panel of this.panels) {
|
||||
panel.dispose();
|
||||
|
@ -1,44 +0,0 @@
|
||||
import { CompositeDisposable } from '../lifecycle';
|
||||
import { PopoutWindow } from '../popoutWindow';
|
||||
import { Box } from '../types';
|
||||
import { DockviewGroupPanel } from './dockviewGroupPanel';
|
||||
|
||||
export class DockviewPopoutGroupPanel extends CompositeDisposable {
|
||||
readonly window: PopoutWindow;
|
||||
|
||||
constructor(
|
||||
readonly id: string,
|
||||
readonly group: DockviewGroupPanel,
|
||||
private readonly options: {
|
||||
className: string;
|
||||
popoutUrl: string;
|
||||
box: Box;
|
||||
}
|
||||
) {
|
||||
super();
|
||||
|
||||
this.window = new PopoutWindow(id, options.className ?? '', {
|
||||
url: this.options.popoutUrl,
|
||||
left: this.options.box.left,
|
||||
top: this.options.box.top,
|
||||
width: this.options.box.width,
|
||||
height: this.options.box.height,
|
||||
});
|
||||
|
||||
group.model.location = 'popout';
|
||||
|
||||
this.addDisposables(
|
||||
this.window,
|
||||
{
|
||||
dispose: () => {
|
||||
group.model.location = 'grid';
|
||||
},
|
||||
},
|
||||
this.window.onDidClose(() => {
|
||||
this.dispose();
|
||||
})
|
||||
);
|
||||
|
||||
this.window.open(group.element);
|
||||
}
|
||||
}
|
@ -273,7 +273,9 @@ export class Gridview implements IDisposable {
|
||||
readonly element: HTMLElement;
|
||||
|
||||
private _root: BranchNode | undefined;
|
||||
private _maximizedNode: LeafNode | undefined = undefined;
|
||||
private _maximizedNode:
|
||||
| { leaf: LeafNode; hiddenOnMaximize: LeafNode[] }
|
||||
| undefined = undefined;
|
||||
private readonly disposable: MutableDisposable = new MutableDisposable();
|
||||
|
||||
private readonly _onDidChange = new Emitter<{
|
||||
@ -329,7 +331,7 @@ export class Gridview implements IDisposable {
|
||||
}
|
||||
|
||||
maximizedView(): IGridView | undefined {
|
||||
return this._maximizedNode?.view;
|
||||
return this._maximizedNode?.leaf.view;
|
||||
}
|
||||
|
||||
hasMaximizedView(): boolean {
|
||||
@ -344,7 +346,7 @@ export class Gridview implements IDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._maximizedNode === node) {
|
||||
if (this._maximizedNode?.leaf === node) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -352,12 +354,18 @@ export class Gridview implements IDisposable {
|
||||
this.exitMaximizedView();
|
||||
}
|
||||
|
||||
const hiddenOnMaximize: LeafNode[] = [];
|
||||
|
||||
function hideAllViewsBut(parent: BranchNode, exclude: LeafNode): void {
|
||||
for (let i = 0; i < parent.children.length; i++) {
|
||||
const child = parent.children[i];
|
||||
if (child instanceof LeafNode) {
|
||||
if (child !== exclude) {
|
||||
parent.setChildVisible(i, false);
|
||||
if (parent.isChildVisible(i)) {
|
||||
parent.setChildVisible(i, false);
|
||||
} else {
|
||||
hiddenOnMaximize.push(child);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hideAllViewsBut(child, exclude);
|
||||
@ -366,7 +374,7 @@ export class Gridview implements IDisposable {
|
||||
}
|
||||
|
||||
hideAllViewsBut(this.root, node);
|
||||
this._maximizedNode = node;
|
||||
this._maximizedNode = { leaf: node, hiddenOnMaximize };
|
||||
this._onDidMaxmizedNodeChange.fire();
|
||||
}
|
||||
|
||||
@ -375,11 +383,15 @@ export class Gridview implements IDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
const hiddenOnMaximize = this._maximizedNode.hiddenOnMaximize;
|
||||
|
||||
function showViewsInReverseOrder(parent: BranchNode): void {
|
||||
for (let index = parent.children.length - 1; index >= 0; index--) {
|
||||
const child = parent.children[index];
|
||||
if (child instanceof LeafNode) {
|
||||
parent.setChildVisible(index, true);
|
||||
if (!hiddenOnMaximize.includes(child)) {
|
||||
parent.setChildVisible(index, true);
|
||||
}
|
||||
} else {
|
||||
showViewsInReverseOrder(child);
|
||||
}
|
||||
@ -395,8 +407,8 @@ export class Gridview implements IDisposable {
|
||||
public serialize(): SerializedGridview<any> {
|
||||
if (this.hasMaximizedView()) {
|
||||
/**
|
||||
* do not persist maximized view state but we must first exit any maximized views
|
||||
* before serialization to ensure the correct dimensions are persisted
|
||||
* do not persist maximized view state
|
||||
* firstly exit any maximized views to ensure the correct dimensions are persisted
|
||||
*/
|
||||
this.exitMaximizedView();
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
import { LayoutPriority } from '../splitview/splitview';
|
||||
import { Emitter, Event } from '../events';
|
||||
import { IViewSize } from './gridview';
|
||||
import { BaseGrid, IGridPanelView } from './baseComponentGridview';
|
||||
|
||||
export interface GridviewInitParameters extends PanelInitParameters {
|
||||
minimumWidth?: number;
|
||||
@ -24,7 +25,7 @@ export interface GridviewInitParameters extends PanelInitParameters {
|
||||
maximumHeight?: number;
|
||||
priority?: LayoutPriority;
|
||||
snap?: boolean;
|
||||
accessor: GridviewComponent;
|
||||
accessor: BaseGrid<IGridPanelView>;
|
||||
isVisible?: boolean;
|
||||
}
|
||||
|
||||
@ -157,14 +158,16 @@ export abstract class GridviewPanel<
|
||||
this.api.initialize(this); // TODO: required to by-pass 'super before this' requirement
|
||||
|
||||
this.addDisposables(
|
||||
this.api.onVisibilityChange((event) => {
|
||||
const { isVisible } = event;
|
||||
this.api.onDidHiddenChange((event) => {
|
||||
const { isHidden } = event;
|
||||
const { accessor } = this._params as GridviewInitParameters;
|
||||
accessor.setVisible(this, isVisible);
|
||||
|
||||
accessor.setVisible(this, !isHidden);
|
||||
}),
|
||||
this.api.onActiveChange(() => {
|
||||
const { accessor } = this._params as GridviewInitParameters;
|
||||
accessor.setActive(this);
|
||||
|
||||
accessor.doSetGroupActive(this);
|
||||
}),
|
||||
this.api.onDidConstraintsChangeInternal((event) => {
|
||||
if (
|
||||
|
@ -24,10 +24,10 @@ export namespace Disposable {
|
||||
}
|
||||
|
||||
export class CompositeDisposable {
|
||||
private readonly _disposables: IDisposable[];
|
||||
private _disposables: IDisposable[];
|
||||
private _isDisposed = false;
|
||||
|
||||
protected get isDisposed(): boolean {
|
||||
get isDisposed(): boolean {
|
||||
return this._isDisposed;
|
||||
}
|
||||
|
||||
@ -40,9 +40,13 @@ export class CompositeDisposable {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._disposables.forEach((arg) => arg.dispose());
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isDisposed = true;
|
||||
this._disposables.forEach((arg) => arg.dispose());
|
||||
this._disposables = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ export class OverlayRenderContainer extends CompositeDisposable {
|
||||
toggleClass(
|
||||
focusContainer,
|
||||
'dv-render-overlay-float',
|
||||
panel.group.api.location === 'floating'
|
||||
panel.group.api.location.type === 'floating'
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -5,22 +5,31 @@ import { Box } from './types';
|
||||
|
||||
export type PopoutWindowOptions = {
|
||||
url: string;
|
||||
onDidOpen?: (event: { id: string; window: Window }) => void;
|
||||
onWillClose?: (event: { id: string; window: Window }) => void;
|
||||
} & Box;
|
||||
|
||||
export class PopoutWindow extends CompositeDisposable {
|
||||
private readonly _onWillClose = new Emitter<void>();
|
||||
readonly onWillClose = this._onWillClose.event;
|
||||
|
||||
private readonly _onDidClose = new Emitter<void>();
|
||||
readonly onDidClose = this._onDidClose.event;
|
||||
|
||||
private _window: { value: Window; disposable: IDisposable } | null = null;
|
||||
|
||||
get window(): Window | null {
|
||||
return this._window?.value ?? null;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly id: string,
|
||||
private readonly target: string,
|
||||
private readonly className: string,
|
||||
private readonly options: PopoutWindowOptions
|
||||
) {
|
||||
super();
|
||||
|
||||
this.addDisposables(this._onDidClose, {
|
||||
this.addDisposables(this._onWillClose, this._onDidClose, {
|
||||
dispose: () => {
|
||||
this.close();
|
||||
},
|
||||
@ -42,13 +51,22 @@ export class PopoutWindow extends CompositeDisposable {
|
||||
|
||||
close(): void {
|
||||
if (this._window) {
|
||||
this._onWillClose.fire();
|
||||
|
||||
this.options.onWillClose?.({
|
||||
id: this.target,
|
||||
window: this._window.value,
|
||||
});
|
||||
|
||||
this._window.disposable.dispose();
|
||||
this._window.value.close();
|
||||
this._window = null;
|
||||
|
||||
this._onDidClose.fire();
|
||||
}
|
||||
}
|
||||
|
||||
open(content: HTMLElement): void {
|
||||
async open(): Promise<HTMLElement | null> {
|
||||
if (this._window) {
|
||||
throw new Error('instance of popout window is already open');
|
||||
}
|
||||
@ -64,55 +82,93 @@ export class PopoutWindow extends CompositeDisposable {
|
||||
.map(([key, value]) => `${key}=${value}`)
|
||||
.join(',');
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Window/open
|
||||
const externalWindow = window.open(url, this.id, features);
|
||||
/**
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/open
|
||||
*/
|
||||
const externalWindow = window.open(url, this.target, features);
|
||||
|
||||
if (!externalWindow) {
|
||||
return;
|
||||
/**
|
||||
* Popup blocked
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
const disposable = new CompositeDisposable();
|
||||
|
||||
this._window = { value: externalWindow, disposable };
|
||||
|
||||
const cleanUp = () => {
|
||||
this._onDidClose.fire();
|
||||
this._window = null;
|
||||
};
|
||||
|
||||
// prevent any default content from loading
|
||||
// externalWindow.document.body.replaceWith(document.createElement('div'));
|
||||
|
||||
disposable.addDisposables(
|
||||
addDisposableWindowListener(window, 'beforeunload', () => {
|
||||
cleanUp();
|
||||
/**
|
||||
* before the main window closes we should close this popup too
|
||||
* to be good citizens
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
|
||||
*/
|
||||
this.close();
|
||||
})
|
||||
);
|
||||
|
||||
externalWindow.addEventListener('load', () => {
|
||||
const externalDocument = externalWindow.document;
|
||||
externalDocument.title = document.title;
|
||||
const container = this.createPopoutWindowContainer();
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('dv-popout-window');
|
||||
div.style.position = 'absolute';
|
||||
div.style.width = '100%';
|
||||
div.style.height = '100%';
|
||||
div.style.top = '0px';
|
||||
div.style.left = '0px';
|
||||
div.classList.add(this.className);
|
||||
div.appendChild(content);
|
||||
if (this.className) {
|
||||
container.classList.add(this.className);
|
||||
}
|
||||
|
||||
externalDocument.body.replaceChildren(div);
|
||||
externalDocument.body.classList.add(this.className);
|
||||
this.options.onDidOpen?.({
|
||||
id: this.target,
|
||||
window: externalWindow,
|
||||
});
|
||||
|
||||
addStyles(externalDocument, window.document.styleSheets);
|
||||
return new Promise<HTMLElement | null>((resolve) => {
|
||||
externalWindow.addEventListener('unload', (e) => {
|
||||
// if page fails to load before unloading
|
||||
// this.close();
|
||||
});
|
||||
|
||||
externalWindow.addEventListener('beforeunload', () => {
|
||||
// TODO: indicate external window is closing
|
||||
cleanUp();
|
||||
externalWindow.addEventListener('load', () => {
|
||||
/**
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
|
||||
*/
|
||||
|
||||
const externalDocument = externalWindow.document;
|
||||
externalDocument.title = document.title;
|
||||
|
||||
externalDocument.body.appendChild(container);
|
||||
|
||||
addStyles(externalDocument, window.document.styleSheets);
|
||||
|
||||
/**
|
||||
* beforeunload must be registered after load for reasons I could not determine
|
||||
* otherwise the beforeunload event will not fire when the window is closed
|
||||
*/
|
||||
addDisposableWindowListener(
|
||||
externalWindow,
|
||||
'beforeunload',
|
||||
() => {
|
||||
/**
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
|
||||
*/
|
||||
this.close();
|
||||
}
|
||||
);
|
||||
|
||||
resolve(container);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private createPopoutWindowContainer(): HTMLElement {
|
||||
const el = document.createElement('div');
|
||||
el.classList.add('dv-popout-window');
|
||||
el.id = 'dv-popout-window';
|
||||
el.style.position = 'absolute';
|
||||
el.style.width = '100%';
|
||||
el.style.height = '100%';
|
||||
el.style.top = '0px';
|
||||
el.style.left = '0px';
|
||||
|
||||
return el;
|
||||
}
|
||||
}
|
||||
|
@ -89,10 +89,10 @@ export abstract class SplitviewPanel
|
||||
|
||||
this.addDisposables(
|
||||
this._onDidChange,
|
||||
this.api.onVisibilityChange((event) => {
|
||||
const { isVisible } = event;
|
||||
this.api.onDidHiddenChange((event) => {
|
||||
const { isHidden } = event;
|
||||
const { accessor } = this._params as PanelViewInitParameters;
|
||||
accessor.setVisible(this, isVisible);
|
||||
accessor.setVisible(this, !isHidden);
|
||||
}),
|
||||
this.api.onActiveChange(() => {
|
||||
const { accessor } = this._params as PanelViewInitParameters;
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
GridviewPanel,
|
||||
GridviewInitParameters,
|
||||
IFrameworkPart,
|
||||
GridviewComponent,
|
||||
} from 'dockview-core';
|
||||
import { ReactPart, ReactPortalStore } from '../react';
|
||||
import { IGridviewPanelProps } from './gridview';
|
||||
@ -25,8 +26,10 @@ export class ReactGridPanelView extends GridviewPanel {
|
||||
{
|
||||
params: this._params?.params ?? {},
|
||||
api: this.api,
|
||||
// TODO: fix casting hack
|
||||
containerApi: new GridviewApi(
|
||||
(this._params as GridviewInitParameters).accessor
|
||||
(this._params as GridviewInitParameters)
|
||||
.accessor as GridviewComponent
|
||||
),
|
||||
}
|
||||
);
|
||||
|
@ -34,6 +34,7 @@
|
||||
"dockview": "^1.9.2",
|
||||
"prism-react-renderer": "^2.3.1",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"recoil": "^0.7.7",
|
||||
"source-map-loader": "^4.0.2",
|
||||
"uuid": "^9.0.1"
|
||||
|
@ -87,7 +87,7 @@ const RightControls = (props: IDockviewHeaderActionsProps) => {
|
||||
);
|
||||
|
||||
const [isPopout, setIsPopout] = React.useState<boolean>(
|
||||
props.api.location === 'popout'
|
||||
props.api.location.type === 'popout'
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
@ -96,7 +96,7 @@ const RightControls = (props: IDockviewHeaderActionsProps) => {
|
||||
});
|
||||
|
||||
const disposable2 = props.api.onDidLocationChange(() => {
|
||||
setIsPopout(props.api.location === 'popout');
|
||||
setIsPopout(props.api.location.type === 'popout');
|
||||
});
|
||||
|
||||
return () => {
|
||||
|
@ -255,13 +255,13 @@ const LeftComponent = (props: IDockviewHeaderActionsProps) => {
|
||||
|
||||
const RightComponent = (props: IDockviewHeaderActionsProps) => {
|
||||
const [floating, setFloating] = React.useState<boolean>(
|
||||
props.api.location === 'floating'
|
||||
props.api.location.type === 'floating'
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
const disposable = props.group.api.onDidLocationChange(
|
||||
(event) => {
|
||||
setFloating(event.location === 'floating');
|
||||
setFloating(event.location.type === 'floating');
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -9,7 +9,8 @@
|
||||
"dependencies": {
|
||||
"dockview": "*",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
"react-dom": "^18.2.0",
|
||||
"react-laag": "^2.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.28",
|
||||
@ -29,4 +30,4 @@
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
]
|
||||
}
|
||||
}
|
@ -5,12 +5,34 @@ import {
|
||||
IDockviewHeaderActionsProps,
|
||||
IDockviewPanelProps,
|
||||
SerializedDockview,
|
||||
DockviewPanelApi,
|
||||
} from 'dockview';
|
||||
import * as React from 'react';
|
||||
import { Icon } from './utils';
|
||||
import { PopoverMenu } from './popover';
|
||||
|
||||
function usePanelWindowObject(api: DockviewPanelApi): Window {
|
||||
const [document, setDocument] = React.useState<Window>(api.getWindow());
|
||||
|
||||
React.useEffect(() => {
|
||||
const disposable = api.onDidLocationChange((event) => {
|
||||
setDocument(api.getWindow());
|
||||
});
|
||||
|
||||
return () => {
|
||||
disposable.dispose();
|
||||
};
|
||||
}, [api]);
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
const components = {
|
||||
default: (props: IDockviewPanelProps<{ title: string }>) => {
|
||||
const _window = usePanelWindowObject(props.api);
|
||||
|
||||
const [reset, setReset] = React.useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@ -19,7 +41,19 @@ const components = {
|
||||
background: 'var(--dv-group-view-background-color)',
|
||||
}}
|
||||
>
|
||||
{props.params.title}
|
||||
<button
|
||||
onClick={() => {
|
||||
console.log(_window);
|
||||
setReset(true);
|
||||
setTimeout(() => {
|
||||
setReset(false);
|
||||
}, 2000);
|
||||
}}
|
||||
>
|
||||
Print
|
||||
</button>
|
||||
{!reset && <PopoverMenu window={_window} />}
|
||||
{props.api.title}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@ -31,31 +65,31 @@ function loadDefaultLayout(api: DockviewApi) {
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
api.addPanel({
|
||||
id: 'panel_2',
|
||||
component: 'default',
|
||||
});
|
||||
// api.addPanel({
|
||||
// id: 'panel_2',
|
||||
// component: 'default',
|
||||
// });
|
||||
|
||||
api.addPanel({
|
||||
id: 'panel_3',
|
||||
component: 'default',
|
||||
});
|
||||
// api.addPanel({
|
||||
// id: 'panel_3',
|
||||
// component: 'default',
|
||||
// });
|
||||
|
||||
api.addPanel({
|
||||
id: 'panel_4',
|
||||
component: 'default',
|
||||
});
|
||||
// api.addPanel({
|
||||
// id: 'panel_4',
|
||||
// component: 'default',
|
||||
// });
|
||||
|
||||
api.addPanel({
|
||||
id: 'panel_5',
|
||||
component: 'default',
|
||||
position: { direction: 'right' },
|
||||
});
|
||||
// api.addPanel({
|
||||
// id: 'panel_5',
|
||||
// component: 'default',
|
||||
// position: { direction: 'right' },
|
||||
// });
|
||||
|
||||
api.addPanel({
|
||||
id: 'panel_6',
|
||||
component: 'default',
|
||||
});
|
||||
// api.addPanel({
|
||||
// id: 'panel_6',
|
||||
// component: 'default',
|
||||
// });
|
||||
}
|
||||
|
||||
let panelCount = 0;
|
||||
@ -205,12 +239,12 @@ const LeftComponent = (props: IDockviewHeaderActionsProps) => {
|
||||
|
||||
const RightComponent = (props: IDockviewHeaderActionsProps) => {
|
||||
const [popout, setPopout] = React.useState<boolean>(
|
||||
props.api.location === 'popout'
|
||||
props.api.location.type === 'popout'
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
const disposable = props.group.api.onDidLocationChange((event) => [
|
||||
setPopout(event.location === 'popout'),
|
||||
setPopout(event.location.type === 'popout'),
|
||||
]);
|
||||
|
||||
return () => {
|
||||
@ -223,7 +257,7 @@ const RightComponent = (props: IDockviewHeaderActionsProps) => {
|
||||
const group = props.containerApi.addGroup();
|
||||
props.group.api.moveTo({ group });
|
||||
} else {
|
||||
props.containerApi.addPopoutGroup(props.group, {
|
||||
const window = props.containerApi.addPopoutGroup(props.group, {
|
||||
popoutUrl: '/popout/index.html',
|
||||
});
|
||||
}
|
||||
|
55
packages/docs/sandboxes/popoutgroup-dockview/src/popover.tsx
Normal file
55
packages/docs/sandboxes/popoutgroup-dockview/src/popover.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import { useLayer, Arrow } from 'react-laag';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import * as React from 'react';
|
||||
import { DockviewPanelApi } from 'dockview';
|
||||
|
||||
export function PopoverMenu(props: { window: Window }) {
|
||||
const [isOpen, setOpen] = React.useState(false);
|
||||
|
||||
// helper function to close the menu
|
||||
function close() {
|
||||
setOpen(false);
|
||||
}
|
||||
|
||||
const { renderLayer, triggerProps, layerProps, arrowProps } = useLayer({
|
||||
isOpen,
|
||||
onOutsideClick: close, // close the menu when the user clicks outside
|
||||
onDisappear: close, // close the menu when the menu gets scrolled out of sight
|
||||
overflowContainer: false, // keep the menu positioned inside the container
|
||||
auto: true, // automatically find the best placement
|
||||
placement: 'top-end', // we prefer to place the menu "top-end"
|
||||
triggerOffset: 12, // keep some distance to the trigger
|
||||
containerOffset: 16, // give the menu some room to breath relative to the container
|
||||
arrowOffset: 16, // let the arrow have some room to breath also,
|
||||
environment: props.window,
|
||||
container: props.window
|
||||
? () => {
|
||||
const el = props.window.document.body;
|
||||
Object.setPrototypeOf(el, HTMLElement.prototype);
|
||||
return el;
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
// Again, we're using framer-motion for the transition effect
|
||||
return (
|
||||
<>
|
||||
<button {...triggerProps} onClick={() => setOpen(!isOpen)}>
|
||||
{isOpen ? 'Hide' : 'Show'}
|
||||
</button>
|
||||
{renderLayer(
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.ul {...layerProps}>
|
||||
<li>Item 1</li>
|
||||
<li>Item 2</li>
|
||||
<li>Item 3</li>
|
||||
<li>Item 4</li>
|
||||
<Arrow {...arrowProps} />
|
||||
</motion.ul>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
@ -13882,6 +13882,13 @@ react-json-view-lite@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/react-json-view-lite/-/react-json-view-lite-1.2.1.tgz#c59a0bea4ede394db331d482ee02e293d38f8218"
|
||||
integrity sha512-Itc0g86fytOmKZoIoJyGgvNqohWSbh3NXIKNgH6W6FT9PC1ck4xas1tT3Rr/b3UlFXyA9Jjaw9QSXdZy2JwGMQ==
|
||||
|
||||
react-laag@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/react-laag/-/react-laag-2.0.5.tgz#549f1035b761b9ba09ac98fd128ccad63464c877"
|
||||
integrity sha512-RCvublJhdcgGRHU1wMYJ8kRtnYsKUgYusLvVhMuftg65POnnOB4+fwXvnETm6adc0cMnc1spujlrK6bGIz6aug==
|
||||
dependencies:
|
||||
tiny-warning "^1.0.3"
|
||||
|
||||
react-loadable-ssr-addon-v5-slorber@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz#2cdc91e8a744ffdf9e3556caabeb6e4278689883"
|
||||
@ -15678,7 +15685,7 @@ tiny-invariant@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642"
|
||||
integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==
|
||||
|
||||
tiny-warning@^1.0.0:
|
||||
tiny-warning@^1.0.0, tiny-warning@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
|
||||
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
|
||||
|
Loading…
Reference in New Issue
Block a user