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/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/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; };