diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts index 450800fb5..9dd25066d 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts @@ -17,6 +17,7 @@ import { GroupDragEvent, TabDragEvent, } from '../../dockview/components/titlebar/tabsContainer'; +import { fromPartial } from '@total-typescript/shoehorn'; class PanelContentPartTest implements IContentRenderer { element: HTMLElement = document.createElement('div'); @@ -105,68 +106,105 @@ describe('dockviewComponent', () => { default: PanelContentPartTest, }, }); + + window.open = jest.fn(); // not implemented by jest }); - test('event leakage', () => { - Emitter.setLeakageMonitorEnabled(true); + describe('memory leakage', () => { + test('event leakage', () => { + Emitter.setLeakageMonitorEnabled(true); - dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - }); + dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + }); - dockview.layout(500, 1000); + dockview.layout(500, 1000); - dockview.addPanel({ - id: 'panel1', - component: 'default', - }); + const panel1 = dockview.addPanel({ + id: 'panel1', + component: 'default', + }); - const panel2 = dockview.addPanel({ - id: 'panel2', - component: 'default', - }); + const panel2 = dockview.addPanel({ + id: 'panel2', + component: 'default', + }); - dockview.removePanel(panel2); + dockview.removePanel(panel2); - const panel3 = dockview.addPanel({ - id: 'panel3', - component: 'default', - position: { - direction: 'right', - referencePanel: 'panel1', - }, - }); + const panel3 = dockview.addPanel({ + id: 'panel3', + component: 'default', + position: { + direction: 'right', + referencePanel: 'panel1', + }, + }); - const panel4 = dockview.addPanel({ - id: 'panel4', - component: 'default', - position: { - direction: 'above', - }, - }); + const panel4 = dockview.addPanel({ + id: 'panel4', + component: 'default', + position: { + direction: 'above', + }, + }); - dockview.moveGroupOrPanel( - panel4.group, - panel3.group.id, - panel3.id, - 'center' - ); + dockview.moveGroupOrPanel( + panel4.group, + panel3.group.id, + panel3.id, + 'center' + ); - dockview.dispose(); + dockview.addPanel({ + id: 'panel5', + component: 'default', + floating: true, + }); - if (Emitter.MEMORY_LEAK_WATCHER.size > 0) { - for (const entry of Array.from( - Emitter.MEMORY_LEAK_WATCHER.events - )) { - console.log('disposal', entry[1]); + const panel6 = dockview.addPanel({ + id: 'panel6', + component: 'default', + position: { + referencePanel: 'panel5', + direction: 'within', + }, + }); + + dockview.addFloatingGroup(panel4.api.group); + + dockview.addPopoutGroup(panel6); + + dockview.moveGroupOrPanel( + panel1.group, + panel6.group.id, + panel6.id, + 'center' + ); + + dockview.moveGroupOrPanel( + panel4.group, + panel6.group.id, + panel6.id, + 'center' + ); + + dockview.dispose(); + + 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'); } - throw new Error('not all listeners disposed'); - } - Emitter.setLeakageMonitorEnabled(false); + Emitter.setLeakageMonitorEnabled(false); + }); }); test('duplicate panel', () => { @@ -2807,1022 +2845,6 @@ describe('dockviewComponent', () => { }); }); - test('floating: group is removed', async () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - expect(dockview.groups.length).toBe(0); - const panel = dockview.addPanel({ - id: 'panel_1', - component: 'default', - floating: true, - }); - expect(dockview.groups.length).toBe(1); - - dockview.removePanel(panel); - expect(dockview.groups.length).toBe(0); - }); - - test('floating: move a floating group of one tab to a new fixed group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(2); - - dockview.moveGroupOrPanel( - panel1.group, - panel2.group.id, - undefined, - 'right' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(2); - }); - - test('floating: move a floating group of one tab to an existing fixed group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(2); - - dockview.moveGroupOrPanel( - panel1.group, - panel2.group.id, - undefined, - 'center' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(dockview.groups.length).toBe(1); - expect(dockview.panels.length).toBe(2); - }); - - test('floating: move a floating group of one tab to an existing floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('floating'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(3); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel2.group, - panel3.group.id, - undefined, - 'center' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('floating'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a floating group of many tabs to a new fixed group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - 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(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel1.group, - panel2.group.id, - undefined, - 'right' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('grid'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a floating group of many tabs to an existing fixed group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - 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(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel1.group, - panel2.group.id, - undefined, - 'center' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('grid'); - expect(dockview.groups.length).toBe(1); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a floating group of many tabs to an existing floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - position: { referencePanel: panel2 }, - }); - - const panel4 = dockview.addPanel({ - id: 'panel_4', - component: 'default', - 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(dockview.groups.length).toBe(3); - expect(dockview.panels.length).toBe(4); - - dockview.moveGroupOrPanel( - panel4.group, - panel2.group.id, - undefined, - '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(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(4); - }); - - test('floating: move a floating tab of one tab to a new fixed group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(2); - - dockview.moveGroupOrPanel( - panel1.group, - panel2.group.id, - panel2.id, - 'right' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(2); - }); - - test('floating: move a floating tab of one tab to an existing fixed group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(2); - - dockview.moveGroupOrPanel( - panel1.group, - panel2.group.id, - panel2.id, - 'center' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(dockview.groups.length).toBe(1); - expect(dockview.panels.length).toBe(2); - }); - - test('floating: move a floating tab of one tab to an existing floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('floating'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(3); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel2.group, - panel3.group.id, - panel3.id, - 'center' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('floating'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a floating tab of many tabs to a new fixed group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - 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(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel1.group, - panel2.group.id, - panel2.id, - 'right' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(3); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a floating tab of many tabs to an existing fixed group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - 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(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel1.group, - panel2.group.id, - panel2.id, - 'center' - ); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a floating tab of many tabs to an existing floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - floating: true, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - position: { referencePanel: panel2 }, - }); - - const panel4 = dockview.addPanel({ - id: 'panel_4', - component: 'default', - 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(dockview.groups.length).toBe(3); - expect(dockview.panels.length).toBe(4); - - dockview.moveGroupOrPanel( - panel4.group, - panel2.group.id, - panel2.id, - '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(dockview.groups.length).toBe(3); - expect(dockview.panels.length).toBe(4); - }); - - test('floating: move a fixed tab of one tab to an existing floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - position: { direction: 'right' }, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(3); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel3.group, - panel1.group.id, - panel1.id, - 'center' - ); - - expect(panel1.group.api.location).toBe('floating'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a fixed tab of many tabs to an existing floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel3.group, - panel1.group.id, - panel1.id, - 'center' - ); - - expect(panel1.group.api.location).toBe('floating'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a fixed group of one tab to an existing floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - position: { direction: 'right' }, - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(3); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel3.group, - panel1.group.id, - undefined, - 'center' - ); - - expect(panel1.group.api.location).toBe('floating'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a fixed group of many tabs to an existing floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - }); - - const panel3 = dockview.addPanel({ - id: 'panel_3', - component: 'default', - floating: true, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).toBe('grid'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(3); - - dockview.moveGroupOrPanel( - panel3.group, - panel1.group.id, - undefined, - 'center' - ); - - expect(panel1.group.api.location).toBe('floating'); - expect(panel2.group.api.location).toBe('floating'); - expect(panel3.group.api.location).toBe('floating'); - expect(dockview.groups.length).toBe(1); - expect(dockview.panels.length).toBe(3); - }); - - test('floating: move a fixed tab of one tab to a new floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - position: { direction: 'right' }, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).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(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(2); - }); - - test('floating: move a fixed tab of many tabs to a new floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).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(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(2); - }); - - test('floating: move a fixed group of one tab to a new floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - position: { direction: 'right' }, - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).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(dockview.groups.length).toBe(2); - expect(dockview.panels.length).toBe(2); - }); - - test('floating: move a fixed group of many tabs to a new floating group', () => { - const container = document.createElement('div'); - - const dockview = new DockviewComponent({ - parentElement: container, - components: { - default: PanelContentPartTest, - }, - tabComponents: { - test_tab_id: PanelTabPartTest, - }, - orientation: Orientation.HORIZONTAL, - }); - - dockview.layout(1000, 500); - - const panel1 = dockview.addPanel({ - id: 'panel_1', - component: 'default', - }); - - const panel2 = dockview.addPanel({ - id: 'panel_2', - component: 'default', - }); - - expect(panel1.group.api.location).toBe('grid'); - expect(panel2.group.api.location).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(dockview.groups.length).toBe(1); - expect(dockview.panels.length).toBe(2); - }); - test('that moving the last panel to be floating should leave an empty gridview', () => { const container = document.createElement('div'); @@ -4373,4 +3395,1158 @@ describe('dockviewComponent', () => { expect(dockview.disableResizing).toBeTruthy(); }); + + describe('floating groups', () => { + test('that a floating group can be removed', async () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + expect(dockview.groups.length).toBe(0); + const panel = dockview.addPanel({ + id: 'panel_1', + component: 'default', + floating: true, + }); + expect(dockview.groups.length).toBe(1); + + dockview.removePanel(panel); + expect(dockview.groups.length).toBe(0); + }); + + test('move a floating group of one tab to a new fixed group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(2); + + dockview.moveGroupOrPanel( + panel1.group, + panel2.group.id, + undefined, + 'right' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(2); + }); + + test('move a floating group of one tab to an existing fixed group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(2); + + dockview.moveGroupOrPanel( + panel1.group, + panel2.group.id, + undefined, + 'center' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(dockview.groups.length).toBe(1); + expect(dockview.panels.length).toBe(2); + }); + + test('move a floating group of one tab to an existing floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('floating'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(3); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel2.group, + panel3.group.id, + undefined, + 'center' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('floating'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + }); + + test('move a floating group of many tabs to a new fixed group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + 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(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel1.group, + panel2.group.id, + undefined, + 'right' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('grid'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + }); + + test('move a floating group of many tabs to an existing fixed group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + 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(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel1.group, + panel2.group.id, + undefined, + 'center' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('grid'); + expect(dockview.groups.length).toBe(1); + expect(dockview.panels.length).toBe(3); + }); + + test('move a floating group of many tabs to an existing floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + position: { referencePanel: panel2 }, + }); + + const panel4 = dockview.addPanel({ + id: 'panel_4', + component: 'default', + 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(dockview.groups.length).toBe(3); + expect(dockview.panels.length).toBe(4); + + dockview.moveGroupOrPanel( + panel4.group, + panel2.group.id, + undefined, + '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(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(4); + }); + + test('move a floating tab of one tab to a new fixed group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(2); + + dockview.moveGroupOrPanel( + panel1.group, + panel2.group.id, + panel2.id, + 'right' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(2); + }); + + test('move a floating tab of one tab to an existing fixed group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(2); + + dockview.moveGroupOrPanel( + panel1.group, + panel2.group.id, + panel2.id, + 'center' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(dockview.groups.length).toBe(1); + expect(dockview.panels.length).toBe(2); + }); + + test('move a floating tab of one tab to an existing floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('floating'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(3); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel2.group, + panel3.group.id, + panel3.id, + 'center' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('floating'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + }); + + test('move a floating tab of many tabs to a new fixed group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + 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(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel1.group, + panel2.group.id, + panel2.id, + 'right' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(3); + expect(dockview.panels.length).toBe(3); + }); + + test('move a floating tab of many tabs to an existing fixed group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + 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(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel1.group, + panel2.group.id, + panel2.id, + 'center' + ); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + }); + + test('move a floating tab of many tabs to an existing floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + floating: true, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + position: { referencePanel: panel2 }, + }); + + const panel4 = dockview.addPanel({ + id: 'panel_4', + component: 'default', + 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(dockview.groups.length).toBe(3); + expect(dockview.panels.length).toBe(4); + + dockview.moveGroupOrPanel( + panel4.group, + panel2.group.id, + panel2.id, + '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(dockview.groups.length).toBe(3); + expect(dockview.panels.length).toBe(4); + }); + + test('move a fixed tab of one tab to an existing floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + position: { direction: 'right' }, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(3); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel3.group, + panel1.group.id, + panel1.id, + 'center' + ); + + expect(panel1.group.api.location).toBe('floating'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + }); + + test('move a fixed tab of many tabs to an existing floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel3.group, + panel1.group.id, + panel1.id, + 'center' + ); + + expect(panel1.group.api.location).toBe('floating'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + }); + + test('move a fixed group of one tab to an existing floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + position: { direction: 'right' }, + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(3); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel3.group, + panel1.group.id, + undefined, + 'center' + ); + + expect(panel1.group.api.location).toBe('floating'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + }); + + test('move a fixed group of many tabs to an existing floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + floating: true, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel3.group, + panel1.group.id, + undefined, + 'center' + ); + + expect(panel1.group.api.location).toBe('floating'); + expect(panel2.group.api.location).toBe('floating'); + expect(panel3.group.api.location).toBe('floating'); + expect(dockview.groups.length).toBe(1); + expect(dockview.panels.length).toBe(3); + }); + + test('move a fixed tab of one tab to a new floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + position: { direction: 'right' }, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).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(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(2); + }); + + test('move a fixed tab of many tabs to a new floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).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(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(2); + }); + + test('move a fixed group of one tab to a new floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + position: { direction: 'right' }, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).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(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(2); + }); + + test('move a fixed group of many tabs to a new floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).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(dockview.groups.length).toBe(1); + expect(dockview.panels.length).toBe(2); + }); + }); + + describe('popout group', () => { + test('that can remove a popout group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + dockview.addPopoutGroup(panel1); + + expect(dockview.panels.length).toBe(1); + expect(dockview.groups.length).toBe(1); + expect(panel1.api.group.api.location).toBe('popout'); + + dockview.removePanel(panel1); + + expect(dockview.panels.length).toBe(0); + expect(dockview.groups.length).toBe(0); + }); + + test('add a popout group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(dockview.groups.length).toBe(1); + expect(dockview.panels.length).toBe(2); + + 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(dockview.panels.length).toBe(2); + }); + + test('move from fixed to popout group and back', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel_2', + component: 'default', + }); + + const panel3 = dockview.addPanel({ + id: 'panel_3', + component: 'default', + position: { + direction: 'right', + }, + }); + + expect(panel1.group.api.location).toBe('grid'); + expect(panel2.group.api.location).toBe('grid'); + expect(panel3.group.api.location).toBe('grid'); + expect(dockview.groups.length).toBe(2); + expect(dockview.panels.length).toBe(3); + + 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(dockview.panels.length).toBe(3); + + dockview.moveGroupOrPanel( + panel3.api.group, + panel2.api.group.id, + panel2.api.id, + '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(dockview.panels.length).toBe(3); + }); + }); }); diff --git a/packages/dockview-core/src/__tests__/lifecycle.spec.ts b/packages/dockview-core/src/__tests__/lifecycle.spec.ts index db67c750c..8a7ae1332 100644 --- a/packages/dockview-core/src/__tests__/lifecycle.spec.ts +++ b/packages/dockview-core/src/__tests__/lifecycle.spec.ts @@ -1,4 +1,8 @@ -import { CompositeDisposable, MutableDisposable } from '../lifecycle'; +import { + CompositeDisposable, + Disposable, + MutableDisposable, +} from '../lifecycle'; describe('lifecycle', () => { test('mutable disposable', () => { @@ -64,4 +68,16 @@ describe('lifecycle', () => { expect(cut.checkIsDisposed()).toBeTruthy(); }); + + test('Disposable.from(...)', () => { + const func = jest.fn(); + + const disposable = Disposable.from(func); + + expect(func).not.toHaveBeenCalled(); + + disposable.dispose(); + + expect(func).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/dockview-core/src/api/dockviewGroupPanelApi.ts b/packages/dockview-core/src/api/dockviewGroupPanelApi.ts index 8b075d620..c4b349bdf 100644 --- a/packages/dockview-core/src/api/dockviewGroupPanelApi.ts +++ b/packages/dockview-core/src/api/dockviewGroupPanelApi.ts @@ -1,4 +1,4 @@ -import { Position } from '../dnd/droptarget'; +import { Position, positionToDirection } from '../dnd/droptarget'; import { DockviewComponent } from '../dockview/dockviewComponent'; import { DockviewGroupPanel } from '../dockview/dockviewGroupPanel'; import { DockviewGroupLocation } from '../dockview/dockviewGroupPanelModel'; @@ -6,9 +6,9 @@ import { Emitter, Event } from '../events'; import { GridviewPanelApi, GridviewPanelApiImpl } from './gridviewPanelApi'; export interface DockviewGroupPanelApi extends GridviewPanelApi { - readonly onDidRenderPositionChange: Event; + readonly onDidLocationChange: Event; readonly location: DockviewGroupLocation; - moveTo(options: { group: DockviewGroupPanel; position?: Position }): void; + moveTo(options: { group?: DockviewGroupPanel; position?: Position }): void; maximize(): void; isMaximized(): boolean; exitMaximized(): void; @@ -24,10 +24,10 @@ const NOT_INITIALIZED_MESSAGE = 'DockviewGroupPanelApiImpl not initialized'; export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl { private _group: DockviewGroupPanel | undefined; - readonly _onDidRenderPositionChange = + readonly _onDidLocationChange = new Emitter(); - readonly onDidRenderPositionChange: Event = - this._onDidRenderPositionChange.event; + readonly onDidLocationChange: Event = + this._onDidLocationChange.event; get location(): DockviewGroupLocation { if (!this._group) { @@ -39,19 +39,25 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl { constructor(id: string, private readonly accessor: DockviewComponent) { super(id); - this.addDisposables(this._onDidRenderPositionChange); + this.addDisposables(this._onDidLocationChange); } - moveTo(options: { group: DockviewGroupPanel; position?: Position }): void { + moveTo(options: { group?: DockviewGroupPanel; position?: Position }): void { if (!this._group) { throw new Error(NOT_INITIALIZED_MESSAGE); } + const group = + options.group ?? + this.accessor.addGroup({ + direction: positionToDirection(options.position ?? 'right'), + }); + this.accessor.moveGroupOrPanel( - options.group, + group, this._group.id, undefined, - options.position ?? 'center' + options.group ? options.position ?? 'center' : 'center' ); } @@ -60,6 +66,11 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl { throw new Error(NOT_INITIALIZED_MESSAGE); } + if (this.location !== 'grid') { + // only grid groups can be maximized + return; + } + this.accessor.maximizeGroup(this._group); } diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index e17087902..019b2789a 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -7,7 +7,7 @@ import { import { directionToPosition, Droptarget, Position } from '../dnd/droptarget'; import { tail, sequenceEquals, remove } from '../array'; import { DockviewPanel, IDockviewPanel } from './dockviewPanel'; -import { CompositeDisposable } from '../lifecycle'; +import { CompositeDisposable, Disposable } from '../lifecycle'; import { Event, Emitter } from '../events'; import { Watermark } from './components/watermark/watermark'; import { @@ -58,7 +58,10 @@ import { DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE, DEFAULT_FLOATING_GROUP_POSITION, } from '../constants'; -import { DockviewPanelRenderer, OverlayRenderContainer } from '../overlayRenderContainer'; +import { + DockviewPanelRenderer, + OverlayRenderContainer, +} from '../overlayRenderContainer'; function getTheme(element: HTMLElement): string | undefined { function toClassList(element: HTMLElement) { @@ -386,6 +389,17 @@ export class DockviewComponent this.onDidActivePanelChange )(() => { this._bufferOnDidLayoutChange.fire(); + }), + Disposable.from(() => { + // iterate over a copy of the array since .dispose() mutates the original array + for (const group of [...this._floatingGroups]) { + group.dispose(); + } + + // iterate over a copy of the array since .dispose() mutates the original array + for (const group of [...this._popoutGroups]) { + group.dispose(); + } }) ); diff --git a/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts b/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts index 69c1c0abc..4f2c0f9ad 100644 --- a/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts +++ b/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts @@ -283,7 +283,7 @@ export class DockviewGroupPanelModel break; } - this.groupPanel.api._onDidRenderPositionChange.fire({ + this.groupPanel.api._onDidLocationChange.fire({ location: this.location, }); } diff --git a/packages/dockview-core/src/lifecycle.ts b/packages/dockview-core/src/lifecycle.ts index c2a307adc..69936fff2 100644 --- a/packages/dockview-core/src/lifecycle.ts +++ b/packages/dockview-core/src/lifecycle.ts @@ -13,6 +13,14 @@ export namespace Disposable { // noop }, }; + + export function from(func: () => void): IDisposable { + return { + dispose: () => { + func(); + }, + }; + } } export class CompositeDisposable { diff --git a/packages/dockview-core/src/popoutWindow.ts b/packages/dockview-core/src/popoutWindow.ts index 2994e44ec..c73334549 100644 --- a/packages/dockview-core/src/popoutWindow.ts +++ b/packages/dockview-core/src/popoutWindow.ts @@ -75,10 +75,7 @@ export class PopoutWindow extends CompositeDisposable { this._window = { value: externalWindow, disposable }; - const grievingParent = content.parentElement; - const cleanUp = () => { - grievingParent?.appendChild(content); this._onDidClose.fire(); this._window = null; }; diff --git a/packages/docs/docs/components/dockview.mdx b/packages/docs/docs/components/dockview.mdx index 6dd3a8935..35231ef41 100644 --- a/packages/docs/docs/components/dockview.mdx +++ b/packages/docs/docs/components/dockview.mdx @@ -399,6 +399,17 @@ From within a panel you may say props.containerApi.addPopoutGroup(props.api.group); ``` +To programatically move the popout group back into the main grid you can use the `moveTo` method in many ways, one of the following would suffice + +```tsx +// option 1: add absolutely to the right-side of the grid +props.group.api.moveTo({position: 'right'}); + +// option 2: create a new group and move the contents of the popout group to it +const group = props.containerApi.addGroup(); +props.group.api.moveTo({ group }); +``` + = { panel_1: () => { return ; }, @@ -130,6 +130,10 @@ const RightControls = (props: IDockviewHeaderActionsProps) => { : 'expand_content' ); + const [popoutIcon, setPopoutIcon] = React.useState( + props.api.location === 'popout' ? 'close_fullscreen' : 'open_in_new' + ); + React.useEffect(() => { const disposable = props.containerApi.onDidMaxmizedGroupChange(() => { setIcon( @@ -139,8 +143,17 @@ const RightControls = (props: IDockviewHeaderActionsProps) => { ); }); + const disposable2 = props.api.onDidLocationChange(() => { + setPopoutIcon( + props.api.location === 'popout' + ? 'close_fullscreen' + : 'open_in_new' + ); + }); + return () => { disposable.dispose(); + disposable2.dispose(); }; }, [props.containerApi]); @@ -152,6 +165,14 @@ const RightControls = (props: IDockviewHeaderActionsProps) => { } }; + const onClick2 = () => { + if (props.api.location !== 'popout') { + props.containerApi.addPopoutGroup(props.group); + } else { + props.api.moveTo({ position: 'right' }); + } + }; + return (
{ > {props.isGroupActive && } {Component && } +
); diff --git a/packages/docs/sandboxes/floatinggroup-dockview/src/app.tsx b/packages/docs/sandboxes/floatinggroup-dockview/src/app.tsx index d90e8c5ff..990913d2e 100644 --- a/packages/docs/sandboxes/floatinggroup-dockview/src/app.tsx +++ b/packages/docs/sandboxes/floatinggroup-dockview/src/app.tsx @@ -259,7 +259,7 @@ const RightComponent = (props: IDockviewHeaderActionsProps) => { ); React.useEffect(() => { - const disposable = props.group.api.onDidRenderPositionChange( + const disposable = props.group.api.onDidLocationChange( (event) => { setFloating(event.location === 'floating'); } diff --git a/packages/docs/sandboxes/popoutgroup-dockview/src/app.tsx b/packages/docs/sandboxes/popoutgroup-dockview/src/app.tsx index e1d130070..d000bc3c4 100644 --- a/packages/docs/sandboxes/popoutgroup-dockview/src/app.tsx +++ b/packages/docs/sandboxes/popoutgroup-dockview/src/app.tsx @@ -218,7 +218,7 @@ const RightComponent = (props: IDockviewHeaderActionsProps) => { ); React.useEffect(() => { - const disposable = props.group.api.onDidRenderPositionChange( + const disposable = props.group.api.onDidLocationChange( (event) => [setPopout(event.location === 'popout')] );