Merge pull request #199 from mathuo/198-vanillajs-rendering-and-persistance

198 vanillajs rendering and persistance
This commit is contained in:
mathuo 2023-03-07 22:08:55 +08:00 committed by GitHub
commit d00da9234d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 1325 additions and 1131 deletions

View File

@ -0,0 +1,42 @@
import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel';
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
import {
GroupPanelPartInitParameters,
GroupPanelUpdateEvent,
IContentRenderer,
ITabRenderer,
} from '../../dockview/types';
export class DockviewPanelModelMock implements IDockviewPanelModel {
constructor(
readonly contentComponent: string,
readonly content: IContentRenderer,
readonly tabComponent?: string,
readonly tab?: ITabRenderer
) {
//
}
init(params: GroupPanelPartInitParameters): void {
//
}
update(event: GroupPanelUpdateEvent): void {
//
}
layout(width: number, height: number): void {
//
}
updateParentGroup(
group: DockviewGroupPanel,
isPanelVisible: boolean
): void {
//
}
dispose(): void {
//
}
}

View File

@ -1,7 +1,7 @@
import { DockviewPanelApiImpl, TitleEvent } from '../../api/dockviewPanelApi'; import { DockviewPanelApiImpl, TitleEvent } from '../../api/dockviewPanelApi';
import { DockviewComponent } from '../../dockview/dockviewComponent'; import { DockviewComponent } from '../../dockview/dockviewComponent';
import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel'; import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel';
import { GroupPanel } from '../../groupview/groupviewPanel'; import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
describe('groupPanelApi', () => { describe('groupPanelApi', () => {
test('title', () => { test('title', () => {
@ -10,7 +10,7 @@ describe('groupPanelApi', () => {
update: jest.fn(), update: jest.fn(),
} as any; } as any;
}); });
const groupMock = jest.fn<GroupPanel, []>(() => { const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
return {} as any; return {} as any;
}); });
@ -37,7 +37,7 @@ describe('groupPanelApi', () => {
onDidRemovePanel: jest.fn(), onDidRemovePanel: jest.fn(),
options: {}, options: {},
}; };
const groupViewPanel = new GroupPanel( const groupViewPanel = new DockviewGroupPanel(
<DockviewComponent>accessor, <DockviewComponent>accessor,
'', '',
{} {}
@ -45,7 +45,7 @@ describe('groupPanelApi', () => {
const cut = new DockviewPanelApiImpl( const cut = new DockviewPanelApiImpl(
<IDockviewPanel>groupPanel, <IDockviewPanel>groupPanel,
<GroupPanel>groupViewPanel <DockviewGroupPanel>groupViewPanel
); );
let events = 0; let events = 0;
@ -57,7 +57,7 @@ describe('groupPanelApi', () => {
expect(events).toBe(0); expect(events).toBe(0);
expect(cut.group).toBe(groupViewPanel); expect(cut.group).toBe(groupViewPanel);
const groupViewPanel2 = new GroupPanel( const groupViewPanel2 = new DockviewGroupPanel(
<DockviewComponent>accessor, <DockviewComponent>accessor,
'', '',
{} {}

View File

@ -1,32 +0,0 @@
import { DefaultGroupPanelView } from '../../dockview/defaultGroupPanelView';
import { IContentRenderer, ITabRenderer } from '../../groupview/types';
describe('defaultGroupPanelView', () => {
test('dispose cleanup', () => {
const contentMock = jest.fn<IContentRenderer, []>(() => {
const partial: Partial<IContentRenderer> = {
element: document.createElement('div'),
dispose: jest.fn(),
};
return partial as IContentRenderer;
});
const tabMock = jest.fn<ITabRenderer, []>(() => {
const partial: Partial<IContentRenderer> = {
element: document.createElement('div'),
dispose: jest.fn(),
};
return partial as IContentRenderer;
});
const content = new contentMock();
const tab = new tabMock();
const cut = new DefaultGroupPanelView({ content, tab });
cut.dispose();
expect(content.dispose).toHaveBeenCalled();
expect(tab.dispose).toHaveBeenCalled();
});
});

View File

@ -3,18 +3,13 @@ import {
GroupPanelPartInitParameters, GroupPanelPartInitParameters,
IContentRenderer, IContentRenderer,
ITabRenderer, ITabRenderer,
} from '../../groupview/types';
import { PanelUpdateEvent } from '../../panel/types';
import { Orientation } from '../../splitview/core/splitview';
import { GroupPanel } from '../../groupview/groupviewPanel';
import { CompositeDisposable } from '../../lifecycle';
import {
GroupPanelUpdateEvent, GroupPanelUpdateEvent,
GroupviewPanelState, GroupviewPanelState,
IGroupPanelInitParameters, IGroupPanelInitParameters,
} from '../../groupview/types'; } from '../../dockview/types';
import { IGroupPanelView } from '../../dockview/defaultGroupPanelView'; import { PanelUpdateEvent } from '../../panel/types';
import { DefaultTab } from '../../dockview/components/tab/defaultTab'; import { Orientation } from '../../splitview/core/splitview';
import { CompositeDisposable } from '../../lifecycle';
import { Emitter } from '../../events'; import { Emitter } from '../../events';
import { IDockviewPanel } from '../../dockview/dockviewPanel'; import { IDockviewPanel } from '../../dockview/dockviewPanel';
import { import {
@ -22,6 +17,10 @@ import {
DockviewPanelApiImpl, DockviewPanelApiImpl,
} from '../../api/dockviewPanelApi'; } from '../../api/dockviewPanelApi';
import { DefaultDockviewDeserialzier } from '../../dockview/deserializer'; import { DefaultDockviewDeserialzier } from '../../dockview/deserializer';
import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel';
import { DockviewPanelModelMock } from '../__mocks__/mockDockviewPanelMode';
import { DefaultTab } from '../../dockview/components/tab/defaultTab';
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
class PanelContentPartTest implements IContentRenderer { class PanelContentPartTest implements IContentRenderer {
element: HTMLElement = document.createElement('div'); element: HTMLElement = document.createElement('div');
@ -35,10 +34,6 @@ class PanelContentPartTest implements IContentRenderer {
this.element.classList.add(`testpanel-${id}`); this.element.classList.add(`testpanel-${id}`);
} }
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void {
//noop
}
init(parameters: GroupPanelPartInitParameters): void { init(parameters: GroupPanelPartInitParameters): void {
//noop //noop
} }
@ -77,10 +72,6 @@ class PanelTabPartTest implements ITabRenderer {
this.element.className = `panel-tab-part-${id}`; this.element.className = `panel-tab-part-${id}`;
} }
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void {
//noop
}
init(parameters: GroupPanelPartInitParameters): void { init(parameters: GroupPanelPartInitParameters): void {
//noop //noop
} }
@ -93,10 +84,6 @@ class PanelTabPartTest implements ITabRenderer {
//noop //noop
} }
toJSON(): object {
return { id: this.id };
}
focus(): void { focus(): void {
//noop //noop
} }
@ -107,43 +94,11 @@ class PanelTabPartTest implements ITabRenderer {
} }
} }
class TestGroupPanelView implements IGroupPanelView {
readonly tab: ITabRenderer = new DefaultTab();
constructor(public readonly content: IContentRenderer) {
//
}
update(event: GroupPanelUpdateEvent): void {
//
}
layout(width: number, height: number): void {
//
}
init(params: GroupPanelPartInitParameters): void {
//
}
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void {
//
}
toJSON(): {} {
return {};
}
dispose(): void {
//
}
}
class TestGroupPanel implements IDockviewPanel { class TestGroupPanel implements IDockviewPanel {
private _group: GroupPanel | undefined; private _group: DockviewGroupPanel | undefined;
readonly view: IGroupPanelView;
readonly api: DockviewPanelApi; readonly api: DockviewPanelApi;
readonly view: IDockviewPanelModel;
constructor( constructor(
public readonly id: string, public readonly id: string,
@ -151,20 +106,23 @@ class TestGroupPanel implements IDockviewPanel {
accessor: DockviewComponent accessor: DockviewComponent
) { ) {
this.api = new DockviewPanelApiImpl(this, this._group!); this.api = new DockviewPanelApiImpl(this, this._group!);
this._group = new GroupPanel(accessor, id, {}); this._group = new DockviewGroupPanel(accessor, id, {});
this.view = new TestGroupPanelView( this.view = new DockviewPanelModelMock(
new PanelContentPartTest(id, 'component') 'component',
new PanelContentPartTest(id, 'component'),
'tabComponent',
new DefaultTab()
); );
} }
get params(): Record<string, any> { get params(): Record<string, any> {
return {}; return {};
} }
get group(): GroupPanel { get group(): DockviewGroupPanel {
return this._group!; return this._group!;
} }
updateParentGroup(group: GroupPanel, isGroupActive: boolean): void { updateParentGroup(group: DockviewGroupPanel, isGroupActive: boolean): void {
this._group = group; this._group = group;
} }
@ -562,27 +520,27 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel2', title: 'panel2',
}, },
panel3: { panel3: {
id: 'panel3', id: 'panel3',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel3', title: 'panel3',
}, },
panel4: { panel4: {
id: 'panel4', id: 'panel4',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel4', title: 'panel4',
}, },
panel5: { panel5: {
id: 'panel5', id: 'panel5',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel5', title: 'panel5',
}, },
}, },
@ -647,27 +605,27 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel2', title: 'panel2',
}, },
panel3: { panel3: {
id: 'panel3', id: 'panel3',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel3', title: 'panel3',
}, },
panel4: { panel4: {
id: 'panel4', id: 'panel4',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel4', title: 'panel4',
}, },
panel5: { panel5: {
id: 'panel5', id: 'panel5',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel5', title: 'panel5',
}, },
}, },
@ -870,7 +828,7 @@ describe('dockviewComponent', () => {
let events: { let events: {
panel?: IDockviewPanel; panel?: IDockviewPanel;
group?: GroupPanel | undefined; group?: DockviewGroupPanel | undefined;
type: string; type: string;
}[] = []; }[] = [];
@ -1060,7 +1018,7 @@ describe('dockviewComponent', () => {
position: { referencePanel: 'panel2', direction: 'below' }, position: { referencePanel: 'panel2', direction: 'below' },
}); });
const removedGroups: GroupPanel[] = []; const removedGroups: DockviewGroupPanel[] = [];
const removedPanels: IDockviewPanel[] = []; const removedPanels: IDockviewPanel[] = [];
const disposable = new CompositeDisposable( const disposable = new CompositeDisposable(
@ -1098,17 +1056,14 @@ describe('dockviewComponent', () => {
view_1: { view_1: {
id: 'view_1', id: 'view_1',
title: 'view_1_title', title: 'view_1_title',
view: {},
}, },
view_2: { view_2: {
id: 'view_2', id: 'view_2',
title: 'view_2_title', title: 'view_2_title',
view: {},
}, },
view_3: { view_3: {
id: 'view_3', id: 'view_3',
title: 'view_3_title', title: 'view_3_title',
view: {},
}, },
}, },
options: {}, options: {},
@ -1516,9 +1471,9 @@ describe('dockviewComponent', () => {
dockview.layout(1000, 1000); dockview.layout(1000, 1000);
let addGroup: GroupPanel[] = []; let addGroup: DockviewGroupPanel[] = [];
let removeGroup: GroupPanel[] = []; let removeGroup: DockviewGroupPanel[] = [];
let activeGroup: (GroupPanel | undefined)[] = []; let activeGroup: (DockviewGroupPanel | undefined)[] = [];
let addPanel: IDockviewPanel[] = []; let addPanel: IDockviewPanel[] = [];
let removePanel: IDockviewPanel[] = []; let removePanel: IDockviewPanel[] = [];
let activePanel: (IDockviewPanel | undefined)[] = []; let activePanel: (IDockviewPanel | undefined)[] = [];
@ -1602,27 +1557,27 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel2', title: 'panel2',
}, },
panel3: { panel3: {
id: 'panel3', id: 'panel3',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel3', title: 'panel3',
}, },
panel4: { panel4: {
id: 'panel4', id: 'panel4',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel4', title: 'panel4',
}, },
panel5: { panel5: {
id: 'panel5', id: 'panel5',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel5', title: 'panel5',
}, },
}, },
@ -1736,30 +1691,28 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { contentComponent: 'default',
content: { id: 'default' }, tabComponent: '__non__existant_tab__',
tab: { id: '__non__existant_tab__' },
},
title: 'panel2', title: 'panel2',
}, },
panel3: { panel3: {
id: 'panel3', id: 'panel3',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel3', title: 'panel3',
}, },
panel4: { panel4: {
id: 'panel4', id: 'panel4',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel4', title: 'panel4',
}, },
panel5: { panel5: {
id: 'panel5', id: 'panel5',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel5', title: 'panel5',
}, },
}, },
@ -1814,15 +1767,14 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { contentComponent: 'default',
content: { id: 'default' }, tabComponent: 'test_tab_id',
tab: { id: 'test_tab_id' },
},
title: 'panel2', title: 'panel2',
}, },
}, },
@ -1863,15 +1815,13 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { contentComponent: 'default',
content: { id: 'default' }, tabComponent: 'test_tab_id',
tab: { id: 'test_tab_id' },
},
title: 'panel2', title: 'panel2',
}, },
}, },
@ -1926,20 +1876,18 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { contentComponent: 'default',
content: { id: 'default' }, tabComponent: 'test_tab_id',
tab: { id: 'test_tab_id' },
},
title: 'panel2', title: 'panel2',
}, },
panel3: { panel3: {
id: 'panel3', id: 'panel3',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel3', title: 'panel3',
}, },
}, },
@ -1959,7 +1907,7 @@ describe('dockviewComponent', () => {
expect(viewQuery2.length).toBe(1); expect(viewQuery2.length).toBe(1);
const viewQuery3 = group.element.querySelectorAll( const viewQuery3 = group.element.querySelectorAll(
'.groupview > .tabs-and-actions-container > .tabs-container > .tab > .panel-tab-part-test_tab_id' '.groupview > .tabs-and-actions-container > .tabs-container > .tab > .panel-tab-part-panel2'
); );
expect(viewQuery3.length).toBe(1); expect(viewQuery3.length).toBe(1);
}); });
@ -2009,7 +1957,7 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
}, },
@ -2061,12 +2009,12 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel2', title: 'panel2',
}, },
}, },
@ -2124,12 +2072,12 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel2', title: 'panel2',
}, },
}, },
@ -2196,18 +2144,18 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel2', title: 'panel2',
}, },
panel3: { panel3: {
id: 'panel3', id: 'panel3',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel3', title: 'panel3',
}, },
}, },
@ -2256,7 +2204,7 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
}, },
@ -2325,17 +2273,17 @@ describe('dockviewComponent', () => {
panels: { panels: {
panel1: { panel1: {
id: 'panel1', id: 'panel1',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel1', title: 'panel1',
}, },
panel2: { panel2: {
id: 'panel2', id: 'panel2',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel2', title: 'panel2',
}, },
panel3: { panel3: {
id: 'panel3', id: 'panel3',
view: { content: { id: 'default' } }, contentComponent: 'default',
title: 'panel3', title: 'panel3',
}, },
}, },

View File

@ -1,8 +1,8 @@
import { DockviewComponent } from '../../dockview/dockviewComponent'; import { DockviewComponent } from '../../dockview/dockviewComponent';
import { DockviewApi } from '../../api/component.api'; import { DockviewApi } from '../../api/component.api';
import { IGroupPanelView } from '../../dockview/defaultGroupPanelView';
import { DockviewPanel } from '../../dockview/dockviewPanel'; import { DockviewPanel } from '../../dockview/dockviewPanel';
import { GroupPanel } from '../../groupview/groupviewPanel'; import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel';
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
describe('dockviewPanel', () => { describe('dockviewPanel', () => {
test('update title', () => { test('update title', () => {
@ -14,13 +14,22 @@ describe('dockviewPanel', () => {
const accessorMock = jest.fn<DockviewComponent, []>(() => { const accessorMock = jest.fn<DockviewComponent, []>(() => {
return {} as any; return {} as any;
}); });
const groupMock = jest.fn<GroupPanel, []>(() => { const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
return {} as any; return {} as any;
}); });
const panelModelMock = jest.fn<Partial<IDockviewPanelModel>, []>(() => {
return {
update: jest.fn(),
init: jest.fn(),
};
});
const api = new dockviewApiMock(); const api = new dockviewApiMock();
const accessor = new accessorMock(); const accessor = new accessorMock();
const group = new groupMock(); const group = new groupMock();
const cut = new DockviewPanel('fake-id', accessor, api, group); const model = <IDockviewPanelModel>new panelModelMock();
const cut = new DockviewPanel('fake-id', accessor, api, group, model);
let latestTitle: string | undefined = undefined; let latestTitle: string | undefined = undefined;
@ -30,7 +39,7 @@ describe('dockviewPanel', () => {
expect(cut.title).toBe(''); expect(cut.title).toBe('');
cut.init({ title: 'new title', params: {}, view: null }); cut.init({ title: 'new title', params: {} });
expect(latestTitle).toBe('new title'); expect(latestTitle).toBe('new title');
expect(cut.title).toBe('new title'); expect(cut.title).toBe('new title');
@ -48,29 +57,29 @@ describe('dockviewPanel', () => {
const accessorMock = jest.fn<DockviewComponent, []>(() => { const accessorMock = jest.fn<DockviewComponent, []>(() => {
return {} as any; return {} as any;
}); });
const groupMock = jest.fn<GroupPanel, []>(() => { const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
return {} as any; return {} as any;
}); });
const panelModelMock = jest.fn<Partial<IDockviewPanelModel>, []>(() => {
return {
update: jest.fn(),
init: jest.fn(),
dispose: jest.fn(),
};
});
const api = new dockviewApiMock(); const api = new dockviewApiMock();
const accessor = new accessorMock(); const accessor = new accessorMock();
const group = new groupMock(); const group = new groupMock();
const model = <IDockviewPanelModel>new panelModelMock();
const cut = new DockviewPanel('fake-id', accessor, api, group); const cut = new DockviewPanel('fake-id', accessor, api, group, model);
const viewMock = jest.fn<IGroupPanelView, []>(() => { cut.init({ params: {}, title: 'title' });
return {
init: jest.fn(),
dispose: jest.fn(),
update: jest.fn(),
} as any;
});
const view = new viewMock();
cut.init({ params: {}, view, title: 'title' });
cut.dispose(); cut.dispose();
expect(view.dispose).toHaveBeenCalled(); expect(model.dispose).toHaveBeenCalled();
}); });
test('get params', () => { test('get params', () => {
@ -80,13 +89,23 @@ describe('dockviewPanel', () => {
const accessorMock = jest.fn<DockviewComponent, []>(() => { const accessorMock = jest.fn<DockviewComponent, []>(() => {
return {} as any; return {} as any;
}); });
const groupMock = jest.fn<GroupPanel, []>(() => { const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
return {} as any; return {} as any;
}); });
const panelModelMock = jest.fn<Partial<IDockviewPanelModel>, []>(() => {
return {
update: jest.fn(),
init: jest.fn(),
dispose: jest.fn(),
};
});
const api = new dockviewApiMock(); const api = new dockviewApiMock();
const accessor = new accessorMock(); const accessor = new accessorMock();
const group = new groupMock(); const group = new groupMock();
const cut = new DockviewPanel('fake-id', accessor, api, group); const model = <IDockviewPanelModel>new panelModelMock();
const cut = new DockviewPanel('fake-id', accessor, api, group, model);
expect(cut.params).toEqual(undefined); expect(cut.params).toEqual(undefined);
@ -102,17 +121,27 @@ describe('dockviewPanel', () => {
const accessorMock = jest.fn<DockviewComponent, []>(() => { const accessorMock = jest.fn<DockviewComponent, []>(() => {
return {} as any; return {} as any;
}); });
const groupMock = jest.fn<GroupPanel, []>(() => { const groupMock = jest.fn<DockviewGroupPanel, []>(() => {
return { return {
api: { api: {
setSize: jest.fn(), setSize: jest.fn(),
}, },
} as any; } as any;
}); });
const panelModelMock = jest.fn<Partial<IDockviewPanelModel>, []>(() => {
return {
update: jest.fn(),
init: jest.fn(),
dispose: jest.fn(),
};
});
const api = new dockviewApiMock(); const api = new dockviewApiMock();
const accessor = new accessorMock(); const accessor = new accessorMock();
const group = new groupMock(); const group = new groupMock();
const cut = new DockviewPanel('fake-id', accessor, api, group); const model = <IDockviewPanelModel>new panelModelMock();
const cut = new DockviewPanel('fake-id', accessor, api, group, model);
cut.api.setSize({ height: 123, width: 456 }); cut.api.setSize({ height: 123, width: 456 });

View File

@ -0,0 +1,171 @@
import {
DockviewComponent,
IDockviewComponent,
} from '../../dockview/dockviewComponent';
import { DockviewPanelModel } from '../../dockview/dockviewPanelModel';
import { IContentRenderer, ITabRenderer } from '../../dockview/types';
describe('dockviewGroupPanel', () => {
test('that dispose is called on content and tab renderers when present', () => {
const contentMock = jest.fn<IContentRenderer, []>(() => {
const partial: Partial<IContentRenderer> = {
element: document.createElement('div'),
dispose: jest.fn(),
};
return partial as IContentRenderer;
});
const tabMock = jest.fn<ITabRenderer, []>(() => {
const partial: Partial<IContentRenderer> = {
element: document.createElement('div'),
dispose: jest.fn(),
};
return partial as IContentRenderer;
});
const accessorMock = jest.fn<Partial<DockviewComponent>, []>(() => {
return {
options: {
components: {
contentComponent: contentMock,
},
tabComponents: {
tabComponent: tabMock,
},
},
};
});
const cut = new DockviewPanelModel(
<IDockviewComponent>new accessorMock(),
'id',
'contentComponent',
'tabComponent'
);
cut.dispose();
expect(cut.content.dispose).toHaveBeenCalled();
expect(cut.tab.dispose).toHaveBeenCalled();
});
test('that update is called on content and tab renderers when present', () => {
const contentMock = jest.fn<IContentRenderer, []>(() => {
const partial: Partial<IContentRenderer> = {
element: document.createElement('div'),
update: jest.fn(),
};
return partial as IContentRenderer;
});
const tabMock = jest.fn<ITabRenderer, []>(() => {
const partial: Partial<IContentRenderer> = {
element: document.createElement('div'),
update: jest.fn(),
};
return partial as IContentRenderer;
});
const accessorMock = jest.fn<Partial<DockviewComponent>, []>(() => {
return {
options: {
components: {
contentComponent: contentMock,
},
tabComponents: {
tabComponent: tabMock,
},
},
};
});
const cut = new DockviewPanelModel(
<IDockviewComponent>new accessorMock(),
'id',
'contentComponent',
'tabComponent'
);
cut.update({
params: {},
});
expect(cut.content.update).toHaveBeenCalled();
expect(cut.tab.update).toHaveBeenCalled();
});
test('that events are fired', () => {
const contentMock = jest.fn<IContentRenderer, []>(() => {
const partial: Partial<IContentRenderer> = {
element: document.createElement('div'),
onGroupChange: jest.fn(),
onPanelVisibleChange: jest.fn(),
};
return partial as IContentRenderer;
});
const tabMock = jest.fn<ITabRenderer, []>(() => {
const partial: Partial<IContentRenderer> = {
element: document.createElement('div'),
onGroupChange: jest.fn(),
onPanelVisibleChange: jest.fn(),
};
return partial as IContentRenderer;
});
const accessorMock = jest.fn<Partial<DockviewComponent>, []>(() => {
return {
options: {
components: {
contentComponent: contentMock,
},
tabComponents: {
tabComponent: tabMock,
},
},
};
});
const cut = new DockviewPanelModel(
<IDockviewComponent>new accessorMock(),
'id',
'contentComponent',
'tabComponent'
);
const group1 = jest.fn() as any;
const group2 = jest.fn() as any;
cut.updateParentGroup(group1, false);
expect(cut.content.onGroupChange).toHaveBeenNthCalledWith(1, group1);
expect(cut.tab.onGroupChange).toHaveBeenNthCalledWith(1, group1);
expect(cut.content.onPanelVisibleChange).toHaveBeenNthCalledWith(
1,
false
);
expect(cut.tab.onPanelVisibleChange).toHaveBeenNthCalledWith(1, false);
expect(cut.content.onGroupChange).toHaveBeenCalledTimes(1);
expect(cut.tab.onGroupChange).toHaveBeenCalledTimes(1);
expect(cut.content.onPanelVisibleChange).toHaveBeenCalledTimes(1);
expect(cut.tab.onPanelVisibleChange).toHaveBeenCalledTimes(1);
cut.updateParentGroup(group1, true);
expect(cut.content.onPanelVisibleChange).toHaveBeenNthCalledWith(
2,
true
);
expect(cut.tab.onPanelVisibleChange).toHaveBeenNthCalledWith(2, true);
expect(cut.content.onGroupChange).toHaveBeenCalledTimes(1);
expect(cut.tab.onGroupChange).toHaveBeenCalledTimes(1);
expect(cut.content.onPanelVisibleChange).toHaveBeenCalledTimes(2);
expect(cut.tab.onPanelVisibleChange).toHaveBeenCalledTimes(2);
cut.updateParentGroup(group2, true);
expect(cut.content.onGroupChange).toHaveBeenNthCalledWith(2, group2);
expect(cut.tab.onGroupChange).toHaveBeenNthCalledWith(2, group2);
expect(cut.content.onGroupChange).toHaveBeenCalledTimes(2);
expect(cut.tab.onGroupChange).toHaveBeenCalledTimes(2);
expect(cut.content.onPanelVisibleChange).toHaveBeenCalledTimes(2);
expect(cut.tab.onPanelVisibleChange).toHaveBeenCalledTimes(2);
});
});

View File

@ -1,5 +1,5 @@
import { DockviewComponent } from '../../dockview/dockviewComponent'; import { DockviewComponent } from '../../dockview/dockviewComponent';
import { GroupPanel } from '../../groupview/groupviewPanel'; import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
describe('gridviewPanel', () => { describe('gridviewPanel', () => {
test('get panel', () => { test('get panel', () => {
@ -13,7 +13,7 @@ describe('gridviewPanel', () => {
const accessor = new accessorMock(); const accessor = new accessorMock();
const cut = new GroupPanel(accessor, 'id', {}); const cut = new DockviewGroupPanel(accessor, 'id', {});
expect(cut.params).toEqual(undefined); expect(cut.params).toEqual(undefined);

View File

@ -1,26 +1,28 @@
import { DockviewComponent } from '../../dockview/dockviewComponent'; import { DockviewComponent } from '../../dockview/dockviewComponent';
import { import {
GroupPanelUpdateEvent,
GroupviewPanelState, GroupviewPanelState,
IGroupPanelInitParameters, IGroupPanelInitParameters,
} from '../../groupview/types';
import {
GroupPanelPartInitParameters, GroupPanelPartInitParameters,
IContentRenderer, IContentRenderer,
ITabRenderer, ITabRenderer,
IWatermarkRenderer, IWatermarkRenderer,
} from '../../groupview/types'; } from '../../dockview/types';
import { PanelUpdateEvent } from '../../panel/types'; import { PanelUpdateEvent } from '../../panel/types';
import { GroupOptions, Groupview } from '../../groupview/groupview';
import { import {
DefaultGroupPanelView, DockviewGroupPanelModel,
IGroupPanelView, GroupOptions,
} from '../../dockview/defaultGroupPanelView'; } from '../../dockview/dockviewGroupPanelModel';
import { GroupPanel } from '../../groupview/groupviewPanel';
import { fireEvent } from '@testing-library/dom'; import { fireEvent } from '@testing-library/dom';
import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer'; import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer';
import { CompositeDisposable } from '../../lifecycle'; import { CompositeDisposable } from '../../lifecycle';
import { DockviewPanelApi } from '../../api/dockviewPanelApi'; import { DockviewPanelApi } from '../../api/dockviewPanelApi';
import { IDockviewPanel } from '../../dockview/dockviewPanel'; import { IDockviewPanel } from '../../dockview/dockviewPanel';
import {
IDockviewPanelModel,
DockviewPanelModel,
} from '../../dockview/dockviewPanelModel';
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
enum GroupChangeKind2 { enum GroupChangeKind2 {
ADD_PANEL, ADD_PANEL,
@ -28,6 +30,41 @@ enum GroupChangeKind2 {
PANEL_ACTIVE, PANEL_ACTIVE,
} }
class TestModel implements IDockviewPanelModel {
readonly content: IContentRenderer;
readonly contentComponent: string;
readonly tab: ITabRenderer;
constructor(id: string) {
this.content = new TestHeaderPart(id);
this.contentComponent = id;
this.tab = new TestContentPart(id);
}
update(event: GroupPanelUpdateEvent): void {
//
}
layout(width: number, height: number): void {
//
}
init(params: GroupPanelPartInitParameters): void {
//
}
updateParentGroup(
group: DockviewGroupPanel,
isPanelVisible: boolean
): void {
//
}
dispose(): void {
//
}
}
class Watermark implements IWatermarkRenderer { class Watermark implements IWatermarkRenderer {
public readonly element = document.createElement('div'); public readonly element = document.createElement('div');
@ -87,10 +124,6 @@ class TestContentPart implements IContentRenderer {
//void //void
} }
updateParentGroup(group: GroupPanel, isPanelVisible: boolean) {
//noop
}
focus() { focus() {
//noop //noop
} }
@ -122,10 +155,6 @@ class TestHeaderPart implements ITabRenderer {
//void //void
} }
updateParentGroup(group: GroupPanel, isPanelVisible: boolean) {
//noop
}
focus() { focus() {
//noop //noop
} }
@ -140,9 +169,9 @@ class TestHeaderPart implements ITabRenderer {
} }
export class TestPanel implements IDockviewPanel { export class TestPanel implements IDockviewPanel {
private _view: IGroupPanelView | undefined; private _group: DockviewGroupPanel | undefined;
private _group: GroupPanel | undefined;
private _params: IGroupPanelInitParameters; private _params: IGroupPanelInitParameters;
readonly view: IDockviewPanelModel;
get title() { get title() {
return ''; return '';
@ -152,33 +181,24 @@ export class TestPanel implements IDockviewPanel {
return this._group!; return this._group!;
} }
get view() {
return this._view;
}
get params(): Record<string, any> { get params(): Record<string, any> {
return {}; return {};
} }
constructor(public readonly id: string, public api: DockviewPanelApi) { constructor(public readonly id: string, public api: DockviewPanelApi) {
this.view = new TestModel(id);
this.init({ this.init({
view: new DefaultGroupPanelView({
tab: new TestHeaderPart(id),
content: new TestContentPart(id),
}),
title: `${id}`, title: `${id}`,
params: {}, params: {},
}); });
} }
init(params: IGroupPanelInitParameters) { init(params: IGroupPanelInitParameters) {
this._view = params.view;
this._params = params; this._params = params;
} }
updateParentGroup(group: GroupPanel, isGroupActive: boolean) { updateParentGroup(group: DockviewGroupPanel, isGroupActive: boolean): void {
this._group = group; //
} }
layout(width: number, height: number) { layout(width: number, height: number) {
@ -196,7 +216,6 @@ export class TestPanel implements IDockviewPanel {
toJSON(): GroupviewPanelState { toJSON(): GroupviewPanelState {
return { return {
id: this.id, id: this.id,
view: this._view?.toJSON(),
title: this._params?.title, title: this._params?.title,
}; };
} }
@ -207,7 +226,7 @@ export class TestPanel implements IDockviewPanel {
} }
describe('groupview', () => { describe('groupview', () => {
let groupview: GroupPanel; let groupview: DockviewGroupPanel;
let dockview: DockviewComponent; let dockview: DockviewComponent;
let options: GroupOptions; let options: GroupOptions;
@ -232,41 +251,16 @@ describe('groupview', () => {
options = { options = {
tabHeight: 30, tabHeight: 30,
}; };
groupview = new GroupPanel(dockview, 'groupview-1', options); groupview = new DockviewGroupPanel(dockview, 'groupview-1', options);
groupview.initialize(); groupview.initialize();
}); });
test('serialized layout shows active panel', () => {
const panel1 = new TestPanel('panel1', jest.fn() as any);
const panel2 = new TestPanel('panel2', jest.fn() as any);
const panel3 = new TestPanel('panel3', jest.fn() as any);
const groupview2 = new GroupPanel(dockview, 'groupview-2', {
tabHeight: 25,
panels: [panel1, panel2, panel3],
activePanel: panel2,
});
groupview2.initialize();
expect(groupview2.model.activePanel).toBe(panel2);
expect(
groupview2.element.querySelector('.content-part-panel1')
).toBeFalsy();
expect(
groupview2.element.querySelector('.content-part-panel2')
).toBeTruthy();
expect(
groupview2.element.querySelector('.content-part-panel3')
).toBeFalsy();
});
test('panel events are captured during de-serialization', () => { test('panel events are captured during de-serialization', () => {
const panel1 = new TestPanel('panel1', jest.fn() as any); const panel1 = new TestPanel('panel1', jest.fn() as any);
const panel2 = new TestPanel('panel2', jest.fn() as any); const panel2 = new TestPanel('panel2', jest.fn() as any);
const panel3 = new TestPanel('panel3', jest.fn() as any); const panel3 = new TestPanel('panel3', jest.fn() as any);
const groupview2 = new GroupPanel(dockview, 'groupview-2', { const groupview2 = new DockviewGroupPanel(dockview, 'groupview-2', {
tabHeight: 25, tabHeight: 25,
panels: [panel1, panel2, panel3], panels: [panel1, panel2, panel3],
activePanel: panel2, activePanel: panel2,
@ -520,7 +514,7 @@ describe('groupview', () => {
} }
); );
const cut = new Groupview( const cut = new DockviewGroupPanelModel(
document.createElement('div'), document.createElement('div'),
dockviewComponent, dockviewComponent,
'id', 'id',
@ -545,7 +539,7 @@ describe('groupview', () => {
} }
); );
const cut = new Groupview( const cut = new DockviewGroupPanelModel(
document.createElement('div'), document.createElement('div'),
dockviewComponent, dockviewComponent,
'id', 'id',
@ -576,7 +570,7 @@ describe('groupview', () => {
); );
const groupviewContainer = document.createElement('div'); const groupviewContainer = document.createElement('div');
const cut = new Groupview( const cut = new DockviewGroupPanelModel(
groupviewContainer, groupviewContainer,
dockviewComponent, dockviewComponent,
'id', 'id',
@ -623,28 +617,32 @@ describe('groupview', () => {
}; };
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
}; };
}); }
);
const container = document.createElement('div'); const container = document.createElement('div');
const cut = new Groupview( const cut = new DockviewGroupPanelModel(
container, container,
accessor, accessor,
'groupviewid', 'groupviewid',
{}, {},
new groupPanelMock() as GroupPanel new groupPanelMock() as DockviewGroupPanel
); );
const element = container const element = container
@ -680,15 +678,17 @@ describe('groupview', () => {
}; };
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -696,12 +696,12 @@ describe('groupview', () => {
}); });
const container = document.createElement('div'); const container = document.createElement('div');
const cut = new Groupview( const cut = new DockviewGroupPanelModel(
container, container,
accessor, accessor,
'groupviewid', 'groupviewid',
{}, {},
new groupPanelMock() as GroupPanel new groupPanelMock() as DockviewGroupPanel
); );
cut.openPanel(new TestPanel('panel1', jest.fn() as any)); cut.openPanel(new TestPanel('panel1', jest.fn() as any));
@ -744,15 +744,17 @@ describe('groupview', () => {
}; };
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -760,12 +762,12 @@ describe('groupview', () => {
}); });
const container = document.createElement('div'); const container = document.createElement('div');
const cut = new Groupview( const cut = new DockviewGroupPanelModel(
container, container,
accessor, accessor,
'groupviewid', 'groupviewid',
{}, {},
new groupPanelMock() as GroupPanel new groupPanelMock() as DockviewGroupPanel
); );
cut.openPanel(new TestPanel('panel1', jest.fn() as any)); cut.openPanel(new TestPanel('panel1', jest.fn() as any));
@ -809,15 +811,17 @@ describe('groupview', () => {
}; };
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -825,12 +829,12 @@ describe('groupview', () => {
}); });
const container = document.createElement('div'); const container = document.createElement('div');
const cut = new Groupview( const cut = new DockviewGroupPanelModel(
container, container,
accessor, accessor,
'groupviewid', 'groupviewid',
{}, {},
new groupPanelMock() as GroupPanel new groupPanelMock() as DockviewGroupPanel
); );
cut.openPanel(new TestPanel('panel1', jest.fn() as any)); cut.openPanel(new TestPanel('panel1', jest.fn() as any));
@ -861,15 +865,17 @@ describe('groupview', () => {
}); });
test('that watermark is added', () => { test('that watermark is added', () => {
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -878,12 +884,12 @@ describe('groupview', () => {
const container = document.createElement('div'); const container = document.createElement('div');
const cut = new Groupview( const cut = new DockviewGroupPanelModel(
container, container,
dockview, dockview,
'groupviewid', 'groupviewid',
{}, {},
new groupPanelMock() as GroupPanel new groupPanelMock() as DockviewGroupPanel
); );
cut.initialize(); cut.initialize();

View File

@ -1,15 +1,14 @@
import { fireEvent } from '@testing-library/dom'; import { fireEvent } from '@testing-library/dom';
import { Emitter, Event } from '../../../events'; import { Emitter, Event } from '../../../events';
import { ContentContainer } from '../../../groupview/panel/content'; import { ContentContainer } from '../../../dockview/components/panel/content';
import { import {
GroupPanelContentPartInitParameters, GroupPanelContentPartInitParameters,
IContentRenderer, IContentRenderer,
} from '../../../groupview/types'; } from '../../../dockview/types';
import { CompositeDisposable } from '../../../lifecycle'; import { CompositeDisposable } from '../../../lifecycle';
import { PanelUpdateEvent } from '../../../panel/types'; import { PanelUpdateEvent } from '../../../panel/types';
import { IGroupPanelView } from '../../../dockview/defaultGroupPanelView';
import { GroupPanel } from '../../../groupview/groupviewPanel';
import { IDockviewPanel } from '../../../dockview/dockviewPanel'; import { IDockviewPanel } from '../../../dockview/dockviewPanel';
import { IDockviewPanelModel } from '../../../dockview/dockviewPanelModel';
class TestContentRenderer class TestContentRenderer
extends CompositeDisposable extends CompositeDisposable
@ -27,10 +26,6 @@ class TestContentRenderer
this.element = document.createElement('div'); this.element = document.createElement('div');
} }
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void {
//
}
init(parameters: GroupPanelContentPartInitParameters): void { init(parameters: GroupPanelContentPartInitParameters): void {
// //
} }
@ -77,7 +72,7 @@ describe('contentContainer', () => {
const panel = { const panel = {
view: { view: {
content: contentRenderer, content: contentRenderer,
} as Partial<IGroupPanelView>, } as Partial<IDockviewPanelModel>,
} as Partial<IDockviewPanel>; } as Partial<IDockviewPanel>;
cut.openPanel(panel as IDockviewPanel); cut.openPanel(panel as IDockviewPanel);
@ -111,7 +106,7 @@ describe('contentContainer', () => {
const panel2 = { const panel2 = {
view: { view: {
content: contentRenderer2, content: contentRenderer2,
} as Partial<IGroupPanelView>, } as Partial<IDockviewPanelModel>,
} as Partial<IDockviewPanel>; } as Partial<IDockviewPanel>;
cut.openPanel(panel2 as IDockviewPanel); cut.openPanel(panel2 as IDockviewPanel);

View File

@ -1,9 +1,9 @@
import { fireEvent } from '@testing-library/dom'; import { fireEvent } from '@testing-library/dom';
import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer'; import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer';
import { DockviewComponent } from '../../dockview/dockviewComponent'; import { DockviewComponent } from '../../dockview/dockviewComponent';
import { Groupview } from '../../groupview/groupview'; import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
import { GroupPanel } from '../../groupview/groupviewPanel'; import { DockviewGroupPanelModel } from '../../dockview/dockviewGroupPanelModel';
import { Tab } from '../../groupview/tab'; import { Tab } from '../../dockview/components/tab/tab';
describe('tab', () => { describe('tab', () => {
test('that empty tab has inactive-tab class', () => { test('that empty tab has inactive-tab class', () => {
@ -34,15 +34,17 @@ describe('tab', () => {
id: 'testcomponentid', id: 'testcomponentid',
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -50,7 +52,7 @@ describe('tab', () => {
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new Tab('panelId', accessor, groupPanel); const cut = new Tab('panelId', accessor, groupPanel);
@ -77,15 +79,17 @@ describe('tab', () => {
id: 'testcomponentid', id: 'testcomponentid',
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -93,7 +97,7 @@ describe('tab', () => {
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new Tab('panel1', accessor, groupPanel); const cut = new Tab('panel1', accessor, groupPanel);
@ -125,15 +129,17 @@ describe('tab', () => {
id: 'testcomponentid', id: 'testcomponentid',
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -141,7 +147,7 @@ describe('tab', () => {
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new Tab('panel1', accessor, groupPanel); const cut = new Tab('panel1', accessor, groupPanel);
@ -173,15 +179,17 @@ describe('tab', () => {
id: 'testcomponentid', id: 'testcomponentid',
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -189,7 +197,7 @@ describe('tab', () => {
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new Tab('panel1', accessor, groupPanel); const cut = new Tab('panel1', accessor, groupPanel);
@ -227,15 +235,17 @@ describe('tab', () => {
id: 'testcomponentid', id: 'testcomponentid',
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -243,7 +253,7 @@ describe('tab', () => {
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new Tab('panel1', accessor, groupPanel); const cut = new Tab('panel1', accessor, groupPanel);

View File

@ -1,13 +1,13 @@
import { DockviewComponent } from '../../../dockview/dockviewComponent'; import { DockviewComponent } from '../../../dockview/dockviewComponent';
import { GroupPanel } from '../../../groupview/groupviewPanel'; import { TabsContainer } from '../../../dockview/components/titlebar/tabsContainer';
import { TabsContainer } from '../../../groupview/titlebar/tabsContainer';
import { fireEvent } from '@testing-library/dom'; import { fireEvent } from '@testing-library/dom';
import { Groupview } from '../../../groupview/groupview';
import { import {
LocalSelectionTransfer, LocalSelectionTransfer,
PanelTransfer, PanelTransfer,
} from '../../../dnd/dataTransfer'; } from '../../../dnd/dataTransfer';
import { TestPanel } from '../groupview.spec'; import { TestPanel } from '../dockviewGroupPanelModel.spec';
import { DockviewGroupPanelModel } from '../../../dockview/dockviewGroupPanelModel';
import { DockviewGroupPanel } from '../../../dockview/dockviewGroupPanel';
describe('tabsContainer', () => { describe('tabsContainer', () => {
test('that an external event does not render a drop target and calls through to the group mode', () => { test('that an external event does not render a drop target and calls through to the group mode', () => {
@ -18,22 +18,24 @@ describe('tabsContainer', () => {
options: {}, options: {},
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
model: groupView, model: groupView,
}; };
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new TabsContainer(accessor, groupPanel); const cut = new TabsContainer(accessor, groupPanel);
@ -71,15 +73,17 @@ describe('tabsContainer', () => {
options: {}, options: {},
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -88,7 +92,7 @@ describe('tabsContainer', () => {
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new TabsContainer(accessor, groupPanel); const cut = new TabsContainer(accessor, groupPanel);
@ -137,15 +141,17 @@ describe('tabsContainer', () => {
options: {}, options: {},
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -154,7 +160,7 @@ describe('tabsContainer', () => {
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new TabsContainer(accessor, groupPanel); const cut = new TabsContainer(accessor, groupPanel);
@ -200,15 +206,17 @@ describe('tabsContainer', () => {
options: {}, options: {},
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -217,7 +225,7 @@ describe('tabsContainer', () => {
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new TabsContainer(accessor, groupPanel); const cut = new TabsContainer(accessor, groupPanel);
@ -263,15 +271,17 @@ describe('tabsContainer', () => {
options: {}, options: {},
}; };
}); });
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
canDisplayOverlay: jest.fn(), canDisplayOverlay: jest.fn(),
}; };
}); }
);
const groupView = new groupviewMock() as Groupview; const groupView = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
id: 'testgroupid', id: 'testgroupid',
model: groupView, model: groupView,
@ -279,7 +289,7 @@ describe('tabsContainer', () => {
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new TabsContainer(accessor, groupPanel); const cut = new TabsContainer(accessor, groupPanel);

View File

@ -2,7 +2,7 @@ export class ActionContainer {
private _element: HTMLElement; private _element: HTMLElement;
private _list: HTMLElement; private _list: HTMLElement;
get element() { get element(): HTMLElement {
return this._element; return this._element;
} }
@ -16,7 +16,7 @@ export class ActionContainer {
this._element.appendChild(this._list); this._element.appendChild(this._list);
} }
public add(element: HTMLElement) { public add(element: HTMLElement): void {
const listItem = document.createElement('li'); const listItem = document.createElement('li');
listItem.className = 'action-item'; listItem.className = 'action-item';
this._list.appendChild(element); this._list.appendChild(element);

View File

@ -12,7 +12,7 @@ import { Direction } from '../gridview/baseComponentGridview';
import { import {
AddComponentOptions, AddComponentOptions,
IGridviewComponent, IGridviewComponent,
SerializedGridview, SerializedGridviewComponent,
} from '../gridview/gridviewComponent'; } from '../gridview/gridviewComponent';
import { IGridviewPanel } from '../gridview/gridviewPanel'; import { IGridviewPanel } from '../gridview/gridviewPanel';
@ -30,7 +30,10 @@ import {
} from '../splitview/splitviewComponent'; } from '../splitview/splitviewComponent';
import { IView, Orientation, Sizing } from '../splitview/core/splitview'; import { IView, Orientation, Sizing } from '../splitview/core/splitview';
import { ISplitviewPanel } from '../splitview/splitviewPanel'; import { ISplitviewPanel } from '../splitview/splitviewPanel';
import { GroupPanel, IGroupviewPanel } from '../groupview/groupviewPanel'; import {
DockviewGroupPanel,
IDockviewGroupPanel,
} from '../dockview/dockviewGroupPanel';
import { Emitter, Event } from '../events'; import { Emitter, Event } from '../events';
import { IDockviewPanel } from '../dockview/dockviewPanel'; import { IDockviewPanel } from '../dockview/dockviewPanel';
import { PaneviewDropEvent } from '../paneview/draggablePaneviewPanel'; import { PaneviewDropEvent } from '../paneview/draggablePaneviewPanel';
@ -226,7 +229,7 @@ export class PaneviewApi implements CommonApi<SerializedPaneview> {
} }
} }
export class GridviewApi implements CommonApi<SerializedGridview> { export class GridviewApi implements CommonApi<SerializedGridviewComponent> {
get minimumHeight(): number { get minimumHeight(): number {
return this.component.minimumHeight; return this.component.minimumHeight;
} }
@ -312,11 +315,11 @@ export class GridviewApi implements CommonApi<SerializedGridview> {
return this.component.getPanel(id); return this.component.getPanel(id);
} }
fromJSON(data: SerializedGridview): void { fromJSON(data: SerializedGridviewComponent): void {
return this.component.fromJSON(data); return this.component.fromJSON(data);
} }
toJSON(): SerializedGridview { toJSON(): SerializedGridviewComponent {
return this.component.toJSON(); return this.component.toJSON();
} }
@ -362,15 +365,15 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
return this.component.totalPanels; return this.component.totalPanels;
} }
get onDidActiveGroupChange(): Event<GroupPanel | undefined> { get onDidActiveGroupChange(): Event<DockviewGroupPanel | undefined> {
return this.component.onDidActiveGroupChange; return this.component.onDidActiveGroupChange;
} }
get onDidAddGroup(): Event<GroupPanel> { get onDidAddGroup(): Event<DockviewGroupPanel> {
return this.component.onDidAddGroup; return this.component.onDidAddGroup;
} }
get onDidRemoveGroup(): Event<GroupPanel> { get onDidRemoveGroup(): Event<DockviewGroupPanel> {
return this.component.onDidRemoveGroup; return this.component.onDidRemoveGroup;
} }
@ -402,7 +405,7 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
return this.component.panels; return this.component.panels;
} }
get groups(): GroupPanel[] { get groups(): DockviewGroupPanel[] {
return this.component.groups; return this.component.groups;
} }
@ -410,7 +413,7 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
return this.component.activePanel; return this.component.activePanel;
} }
get activeGroup(): GroupPanel | undefined { get activeGroup(): DockviewGroupPanel | undefined {
return this.component.activeGroup; return this.component.activeGroup;
} }
@ -440,7 +443,7 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
return this.component.addPanel(options); return this.component.addPanel(options);
} }
addGroup(options?: AddGroupOptions): IGroupviewPanel { addGroup(options?: AddGroupOptions): IDockviewGroupPanel {
return this.component.addGroup(options); return this.component.addGroup(options);
} }
@ -456,11 +459,11 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
return this.component.closeAllGroups(); return this.component.closeAllGroups();
} }
removeGroup(group: IGroupviewPanel): void { removeGroup(group: IDockviewGroupPanel): void {
this.component.removeGroup(<GroupPanel>group); this.component.removeGroup(<DockviewGroupPanel>group);
} }
getGroup(id: string): GroupPanel | undefined { getGroup(id: string): DockviewGroupPanel | undefined {
return this.component.getPanel(id); return this.component.getPanel(id);
} }

View File

@ -1,6 +1,6 @@
import { Emitter, Event } from '../events'; import { Emitter, Event } from '../events';
import { GridviewPanelApiImpl, GridviewPanelApi } from './gridviewPanelApi'; import { GridviewPanelApiImpl, GridviewPanelApi } from './gridviewPanelApi';
import { GroupPanel } from '../groupview/groupviewPanel'; import { DockviewGroupPanel } from '../dockview/dockviewGroupPanel';
import { MutableDisposable } from '../lifecycle'; import { MutableDisposable } from '../lifecycle';
import { IDockviewPanel } from '../dockview/dockviewPanel'; import { IDockviewPanel } from '../dockview/dockviewPanel';
@ -13,7 +13,7 @@ export interface TitleEvent {
* because it belongs to a groupview * because it belongs to a groupview
*/ */
export interface DockviewPanelApi extends Omit<GridviewPanelApi, 'setVisible'> { export interface DockviewPanelApi extends Omit<GridviewPanelApi, 'setVisible'> {
readonly group: GroupPanel; readonly group: DockviewGroupPanel;
readonly isGroupActive: boolean; readonly isGroupActive: boolean;
readonly title: string; readonly title: string;
readonly onDidActiveGroupChange: Event<void>; readonly onDidActiveGroupChange: Event<void>;
@ -26,7 +26,7 @@ export class DockviewPanelApiImpl
extends GridviewPanelApiImpl extends GridviewPanelApiImpl
implements DockviewPanelApi implements DockviewPanelApi
{ {
private _group: GroupPanel; private _group: DockviewGroupPanel;
readonly _onDidTitleChange = new Emitter<TitleEvent>(); readonly _onDidTitleChange = new Emitter<TitleEvent>();
readonly onDidTitleChange = this._onDidTitleChange.event; readonly onDidTitleChange = this._onDidTitleChange.event;
@ -47,7 +47,7 @@ export class DockviewPanelApiImpl
return !!this.group?.isActive; return !!this.group?.isActive;
} }
set group(value: GroupPanel) { set group(value: DockviewGroupPanel) {
const isOldGroupActive = this.isGroupActive; const isOldGroupActive = this.isGroupActive;
this._group = value; this._group = value;
@ -65,11 +65,11 @@ export class DockviewPanelApiImpl
} }
} }
get group(): GroupPanel { get group(): DockviewGroupPanel {
return this._group; return this._group;
} }
constructor(private panel: IDockviewPanel, group: GroupPanel) { constructor(private panel: IDockviewPanel, group: DockviewGroupPanel) {
super(panel.id); super(panel.id);
this.initialize(panel); this.initialize(panel);

View File

@ -21,7 +21,7 @@ export abstract class DragHandler extends CompositeDisposable {
abstract getData(dataTransfer?: DataTransfer | null): IDisposable; abstract getData(dataTransfer?: DataTransfer | null): IDisposable;
private configure() { private configure(): void {
this.addDisposables( this.addDisposables(
this._onDragStart, this._onDragStart,
addDisposableListener(this.el, 'dragstart', (event) => { addDisposableListener(this.el, 'dragstart', (event) => {

View File

@ -3,7 +3,7 @@ import { addClasses } from '../dom';
export function addGhostImage( export function addGhostImage(
dataTransfer: DataTransfer, dataTransfer: DataTransfer,
ghostElement: HTMLElement ghostElement: HTMLElement
) { ): void {
// class dockview provides to force ghost image to be drawn on a different layer and prevent weird rendering issues // class dockview provides to force ghost image to be drawn on a different layer and prevent weird rendering issues
addClasses(ghostElement, 'dv-dragged'); addClasses(ghostElement, 'dv-dragged');

View File

@ -1,4 +1,4 @@
import { GroupPanel } from '../groupview/groupviewPanel'; import { DockviewGroupPanel } from '../dockview/dockviewGroupPanel';
import { IDisposable } from '../lifecycle'; import { IDisposable } from '../lifecycle';
import { DragHandler } from './abstractDragHandler'; import { DragHandler } from './abstractDragHandler';
import { LocalSelectionTransfer, PanelTransfer } from './dataTransfer'; import { LocalSelectionTransfer, PanelTransfer } from './dataTransfer';
@ -11,7 +11,7 @@ export class GroupDragHandler extends DragHandler {
constructor( constructor(
element: HTMLElement, element: HTMLElement,
private readonly accessorId: string, private readonly accessorId: string,
private readonly group: GroupPanel private readonly group: DockviewGroupPanel
) { ) {
super(element); super(element);
} }

View File

@ -2,10 +2,10 @@ import {
CompositeDisposable, CompositeDisposable,
IDisposable, IDisposable,
MutableDisposable, MutableDisposable,
} from '../../lifecycle'; } from '../../../lifecycle';
import { Emitter, Event } from '../../events'; import { Emitter, Event } from '../../../events';
import { trackFocus } from '../../dom'; import { trackFocus } from '../../../dom';
import { IDockviewPanel } from '../../dockview/dockviewPanel'; import { IDockviewPanel } from '../../dockviewPanel';
export interface IContentContainer extends IDisposable { export interface IContentContainer extends IDisposable {
onDidFocus: Event<void>; onDidFocus: Event<void>;
@ -74,9 +74,8 @@ export class ContentContainer
const disposable = new CompositeDisposable(); const disposable = new CompositeDisposable();
if (this.panel.view) { if (this.panel.view) {
const _onDidFocus: Event<void> = const _onDidFocus = this.panel.view.content.onDidFocus;
this.panel.view.content.onDidFocus!; const _onDidBlur = this.panel.view.content.onDidBlur;
const _onDidBlur: Event<void> = this.panel.view.content.onDidBlur!;
const { onDidFocus, onDidBlur } = trackFocus(this._element); const { onDidFocus, onDidBlur } = trackFocus(this._element);

View File

@ -1,15 +1,10 @@
import { CompositeDisposable } from '../../../lifecycle'; import { CompositeDisposable } from '../../../lifecycle';
import { import { ITabRenderer, GroupPanelPartInitParameters } from '../../types';
ITabRenderer,
GroupPanelPartInitParameters,
} from '../../../groupview/types';
import { addDisposableListener } from '../../../events'; import { addDisposableListener } from '../../../events';
import { PanelUpdateEvent } from '../../../panel/types'; import { PanelUpdateEvent } from '../../../panel/types';
import { GroupPanel } from '../../../groupview/groupviewPanel'; import { DockviewGroupPanel } from '../../dockviewGroupPanel';
import { createCloseButton } from '../../../svg'; import { createCloseButton } from '../../../svg';
export const DEFAULT_TAB_IDENTIFIER = '__default__tab__';
export class DefaultTab extends CompositeDisposable implements ITabRenderer { export class DefaultTab extends CompositeDisposable implements ITabRenderer {
private _element: HTMLElement; private _element: HTMLElement;
@ -26,10 +21,6 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
return this._element; return this._element;
} }
get id() {
return DEFAULT_TAB_IDENTIFIER;
}
constructor() { constructor() {
super(); super();
@ -69,18 +60,13 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
this.render(); this.render();
} }
public toJSON() {
return { id: this.id };
}
focus() { focus() {
//noop //noop
} }
public init(params: GroupPanelPartInitParameters) { public init(params: GroupPanelPartInitParameters) {
this.params = params; this.params = params;
this._content.textContent = this._content.textContent = params.title;
typeof params.title === 'string' ? params.title : this.id;
addDisposableListener(this.action, 'click', (ev) => { addDisposableListener(this.action, 'click', (ev) => {
ev.preventDefault(); // ev.preventDefault(); //
@ -88,7 +74,10 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
}); });
} }
public updateParentGroup(group: GroupPanel, isPanelVisible: boolean) { public updateParentGroup(
group: DockviewGroupPanel,
isPanelVisible: boolean
) {
const changed = const changed =
this._isPanelVisible !== isPanelVisible || this._isPanelVisible !== isPanelVisible ||
this._isGroupActive !== group.isActive; this._isGroupActive !== group.isActive;
@ -107,10 +96,7 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
private render() { private render() {
if (this._content.textContent !== this.params.title) { if (this._content.textContent !== this.params.title) {
this._content.textContent = this._content.textContent = this.params.title;
typeof this.params.title === 'string'
? this.params.title
: this.id;
} }
} }
} }

View File

@ -1,17 +1,16 @@
import { addDisposableListener, Emitter, Event } from '../events'; import { addDisposableListener, Emitter, Event } from '../../../events';
import { CompositeDisposable, IDisposable } from '../lifecycle'; import { CompositeDisposable, IDisposable } from '../../../lifecycle';
import { import {
getPanelData, getPanelData,
LocalSelectionTransfer, LocalSelectionTransfer,
PanelTransfer, PanelTransfer,
} from '../dnd/dataTransfer'; } from '../../../dnd/dataTransfer';
import { toggleClass } from '../dom'; import { toggleClass } from '../../../dom';
import { IDockviewComponent } from '../dockview/dockviewComponent'; import { IDockviewComponent } from '../../dockviewComponent';
import { ITabRenderer } from './types'; import { DockviewDropTargets, ITabRenderer } from '../../types';
import { GroupPanel } from './groupviewPanel'; import { DockviewGroupPanel } from '../../dockviewGroupPanel';
import { DroptargetEvent, Droptarget } from '../dnd/droptarget'; import { DroptargetEvent, Droptarget } from '../../../dnd/droptarget';
import { DockviewDropTargets } from './dnd'; import { DragHandler } from '../../../dnd/abstractDragHandler';
import { DragHandler } from '../dnd/abstractDragHandler';
export interface ITab { export interface ITab {
readonly panelId: string; readonly panelId: string;
@ -40,7 +39,7 @@ export class Tab extends CompositeDisposable implements ITab {
constructor( constructor(
public readonly panelId: string, public readonly panelId: string,
private readonly accessor: IDockviewComponent, private readonly accessor: IDockviewComponent,
private readonly group: GroupPanel private readonly group: DockviewGroupPanel
) { ) {
super(); super();

View File

@ -2,14 +2,14 @@ import {
IDisposable, IDisposable,
CompositeDisposable, CompositeDisposable,
IValueDisposable, IValueDisposable,
} from '../../lifecycle'; } from '../../../lifecycle';
import { addDisposableListener, Emitter, Event } from '../../events'; import { addDisposableListener, Emitter, Event } from '../../../events';
import { ITab, Tab } from '../tab'; import { ITab, Tab } from '../tab/tab';
import { DockviewComponent } from '../../dockview/dockviewComponent'; import { DockviewComponent } from '../../dockviewComponent';
import { GroupPanel } from '../groupviewPanel'; import { DockviewGroupPanel } from '../../dockviewGroupPanel';
import { VoidContainer } from './voidContainer'; import { VoidContainer } from './voidContainer';
import { toggleClass } from '../../dom'; import { toggleClass } from '../../../dom';
import { IDockviewPanel } from '../../dockview/dockviewPanel'; import { IDockviewPanel } from '../../dockviewPanel';
export interface TabDropIndexEvent { export interface TabDropIndexEvent {
event: DragEvent; event: DragEvent;
@ -135,7 +135,7 @@ export class TabsContainer
constructor( constructor(
private readonly accessor: DockviewComponent, private readonly accessor: DockviewComponent,
private readonly group: GroupPanel private readonly group: DockviewGroupPanel
) { ) {
super(); super();

View File

@ -1,12 +1,12 @@
import { last } from '../../array'; import { last } from '../../../array';
import { getPanelData } from '../../dnd/dataTransfer'; import { getPanelData } from '../../../dnd/dataTransfer';
import { Droptarget, DroptargetEvent } from '../../dnd/droptarget'; import { Droptarget, DroptargetEvent } from '../../../dnd/droptarget';
import { GroupDragHandler } from '../../dnd/groupDragHandler'; import { GroupDragHandler } from '../../../dnd/groupDragHandler';
import { DockviewComponent } from '../../dockview/dockviewComponent'; import { DockviewComponent } from '../../dockviewComponent';
import { addDisposableListener, Emitter, Event } from '../../events'; import { addDisposableListener, Emitter, Event } from '../../../events';
import { CompositeDisposable } from '../../lifecycle'; import { CompositeDisposable } from '../../../lifecycle';
import { DockviewDropTargets } from '../dnd'; import { DockviewGroupPanel } from '../../dockviewGroupPanel';
import { GroupPanel } from '../groupviewPanel'; import { DockviewDropTargets } from '../../types';
export class VoidContainer extends CompositeDisposable { export class VoidContainer extends CompositeDisposable {
private readonly _element: HTMLElement; private readonly _element: HTMLElement;
@ -21,7 +21,7 @@ export class VoidContainer extends CompositeDisposable {
constructor( constructor(
private readonly accessor: DockviewComponent, private readonly accessor: DockviewComponent,
private readonly group: GroupPanel private readonly group: DockviewGroupPanel
) { ) {
super(); super();

View File

@ -1,12 +1,9 @@
import { import { GroupPanelPartInitParameters, IWatermarkRenderer } from '../../types';
GroupPanelPartInitParameters,
IWatermarkRenderer,
} from '../../../groupview/types';
import { ActionContainer } from '../../../actionbar/actionsContainer'; import { ActionContainer } from '../../../actionbar/actionsContainer';
import { addDisposableListener } from '../../../events'; import { addDisposableListener } from '../../../events';
import { toggleClass } from '../../../dom'; import { toggleClass } from '../../../dom';
import { CompositeDisposable } from '../../../lifecycle'; import { CompositeDisposable } from '../../../lifecycle';
import { GroupPanel } from '../../../groupview/groupviewPanel'; import { DockviewGroupPanel } from '../../dockviewGroupPanel';
import { PanelUpdateEvent } from '../../../panel/types'; import { PanelUpdateEvent } from '../../../panel/types';
import { createCloseButton } from '../../../svg'; import { createCloseButton } from '../../../svg';
@ -15,11 +12,11 @@ export class Watermark
implements IWatermarkRenderer implements IWatermarkRenderer
{ {
private _element: HTMLElement; private _element: HTMLElement;
private group: GroupPanel | undefined; private group: DockviewGroupPanel | undefined;
private params: GroupPanelPartInitParameters | undefined; private params: GroupPanelPartInitParameters | undefined;
get id() { get element() {
return 'watermark'; return this._element;
} }
constructor() { constructor() {
@ -67,10 +64,6 @@ export class Watermark
// noop // noop
} }
toJSON() {
return {};
}
layout(_width: number, _height: number) { layout(_width: number, _height: number) {
// noop // noop
} }
@ -87,13 +80,13 @@ export class Watermark
this.render(); this.render();
} }
updateParentGroup(group: GroupPanel, _visible: boolean): void { updateParentGroup(group: DockviewGroupPanel, _visible: boolean): void {
this.group = group; this.group = group;
this.render(); this.render();
} }
get element() { dispose() {
return this._element; super.dispose();
} }
private render() { private render() {
@ -102,8 +95,4 @@ export class Watermark
); );
toggleClass(this.element, 'has-actions', isOneGroup); toggleClass(this.element, 'has-actions', isOneGroup);
} }
dispose() {
super.dispose();
}
} }

View File

@ -1,75 +0,0 @@
import { DefaultTab } from './components/tab/defaultTab';
import {
GroupPanelPartInitParameters,
IContentRenderer,
ITabRenderer,
GroupPanelUpdateEvent,
} from '../groupview/types';
import { GroupPanel } from '../groupview/groupviewPanel';
import { IDisposable } from '../lifecycle';
export interface IGroupPanelView extends IDisposable {
readonly content: IContentRenderer;
readonly tab?: ITabRenderer;
update(event: GroupPanelUpdateEvent): void;
layout(width: number, height: number): void;
init(params: GroupPanelPartInitParameters): void;
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void;
toJSON(): {};
}
export class DefaultGroupPanelView implements IGroupPanelView {
private readonly _content: IContentRenderer;
private readonly _tab: ITabRenderer;
get content(): IContentRenderer {
return this._content;
}
get tab(): ITabRenderer {
return this._tab;
}
constructor(renderers: { content: IContentRenderer; tab?: ITabRenderer }) {
this._content = renderers.content;
this._tab = renderers.tab ?? new DefaultTab();
}
init(params: GroupPanelPartInitParameters): void {
this.content.init({ ...params, tab: this.tab });
this.tab.init(params);
}
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void {
this._content.updateParentGroup(group, isPanelVisible);
this._tab?.updateParentGroup(group, isPanelVisible);
}
layout(width: number, height: number): void {
this.content.layout(width, height);
}
update(event: GroupPanelUpdateEvent): void {
this.content.update(event);
this.tab.update(event);
}
toJSON(): {} {
let tab =
this.tab instanceof DefaultTab ? undefined : this.tab.toJSON();
if (tab && Object.keys(tab).length === 0) {
tab = undefined;
}
return {
content: this.content.toJSON(),
tab,
};
}
dispose(): void {
this.content.dispose();
this.tab.dispose();
}
}

View File

@ -1,34 +1,53 @@
import { GroupviewPanelState, ITabRenderer } from '../groupview/types'; import { GroupviewPanelState, ITabRenderer } from './types';
import { GroupPanel } from '../groupview/groupviewPanel'; import { DockviewGroupPanel } from './dockviewGroupPanel';
import { DockviewPanel, IDockviewPanel } from './dockviewPanel'; import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
import { DockviewComponent } from './dockviewComponent'; import { IDockviewComponent } from './dockviewComponent';
import { createComponent } from '../panel/componentFactory'; import { createComponent } from '../panel/componentFactory';
import { DefaultTab } from './components/tab/defaultTab'; import { DefaultTab } from './components/tab/defaultTab';
import { DefaultGroupPanelView } from './defaultGroupPanelView'; import { DockviewPanelModel } from './dockviewPanelModel';
import { DockviewApi } from '../api/component.api'; import { DockviewApi } from '../api/component.api';
export interface IPanelDeserializer { export interface IPanelDeserializer {
fromJSON(panelData: GroupviewPanelState, group: GroupPanel): IDockviewPanel; fromJSON(
panelData: GroupviewPanelState,
group: DockviewGroupPanel
): IDockviewPanel;
}
// depreciated
interface LegacyState extends GroupviewPanelState {
view?: {
tab?: { id: string };
content: { id: string };
};
} }
export class DefaultDockviewDeserialzier implements IPanelDeserializer { export class DefaultDockviewDeserialzier implements IPanelDeserializer {
constructor(private readonly layout: DockviewComponent) {} constructor(private readonly layout: IDockviewComponent) {}
public fromJSON( public fromJSON(
panelData: GroupviewPanelState, panelData: GroupviewPanelState,
group: GroupPanel group: DockviewGroupPanel
): IDockviewPanel { ): IDockviewPanel {
const panelId = panelData.id; const panelId = panelData.id;
const params = panelData.params; const params = panelData.params;
const title = panelData.title; const title = panelData.title;
const viewData = panelData.view;
const viewData = (panelData as LegacyState).view!;
const contentComponent = viewData
? viewData.content.id
: panelData.contentComponent || 'unknown';
const tabComponent = viewData
? viewData.tab?.id
: panelData.tabComponent;
let tab: ITabRenderer; let tab: ITabRenderer;
if (viewData.tab?.id) { if (tabComponent) {
tab = createComponent( tab = createComponent(
viewData.tab.id, panelId,
viewData.tab.id, tabComponent,
this.layout.options.tabComponents, this.layout.options.tabComponents,
this.layout.options.frameworkTabComponents, this.layout.options.frameworkTabComponents,
this.layout.options.frameworkComponentFactory?.tab, this.layout.options.frameworkComponentFactory?.tab,
@ -36,7 +55,7 @@ export class DefaultDockviewDeserialzier implements IPanelDeserializer {
); );
} else if (this.layout.options.defaultTabComponent) { } else if (this.layout.options.defaultTabComponent) {
tab = createComponent( tab = createComponent(
this.layout.options.defaultTabComponent, panelId,
this.layout.options.defaultTabComponent, this.layout.options.defaultTabComponent,
this.layout.options.tabComponents, this.layout.options.tabComponents,
this.layout.options.frameworkTabComponents, this.layout.options.frameworkTabComponents,
@ -47,27 +66,23 @@ export class DefaultDockviewDeserialzier implements IPanelDeserializer {
tab = new DefaultTab(); tab = new DefaultTab();
} }
const view = new DefaultGroupPanelView({ const view = new DockviewPanelModel(
content: createComponent( this.layout,
viewData.content.id, panelId,
viewData.content.id, contentComponent,
this.layout.options.components, tabComponent
this.layout.options.frameworkComponents, );
this.layout.options.frameworkComponentFactory?.content
),
tab,
});
const panel = new DockviewPanel( const panel = new DockviewPanel(
panelId, panelId,
this.layout, this.layout,
new DockviewApi(this.layout), new DockviewApi(this.layout),
group group,
view
); );
panel.init({ panel.init({
view, title: title || panelId,
title,
params: params || {}, params: params || {},
}); });

View File

@ -11,11 +11,10 @@ import { CompositeDisposable } from '../lifecycle';
import { Event, Emitter } from '../events'; import { Event, Emitter } from '../events';
import { Watermark } from './components/watermark/watermark'; import { Watermark } from './components/watermark/watermark';
import { import {
IContentRenderer,
ITabRenderer,
IWatermarkRenderer, IWatermarkRenderer,
GroupviewPanelState, GroupviewPanelState,
} from '../groupview/types'; DockviewDropTargets,
} from './types';
import { sequentialNumberGenerator } from '../math'; import { sequentialNumberGenerator } from '../math';
import { IPanelDeserializer } from './deserializer'; import { IPanelDeserializer } from './deserializer';
import { createComponent } from '../panel/componentFactory'; import { createComponent } from '../panel/componentFactory';
@ -37,16 +36,14 @@ import {
} from '../gridview/baseComponentGridview'; } from '../gridview/baseComponentGridview';
import { DockviewApi } from '../api/component.api'; import { DockviewApi } from '../api/component.api';
import { Orientation, Sizing } from '../splitview/core/splitview'; import { Orientation, Sizing } from '../splitview/core/splitview';
import { DefaultTab } from './components/tab/defaultTab';
import { import {
GroupOptions, GroupOptions,
GroupPanelViewState, GroupPanelViewState,
GroupviewDropEvent, GroupviewDropEvent,
} from '../groupview/groupview'; } from './dockviewGroupPanelModel';
import { GroupPanel, IGroupviewPanel } from '../groupview/groupviewPanel'; import { DockviewGroupPanel, IDockviewGroupPanel } from './dockviewGroupPanel';
import { DefaultGroupPanelView } from './defaultGroupPanelView'; import { DockviewPanelModel } from './dockviewPanelModel';
import { getPanelData } from '../dnd/dataTransfer'; import { getPanelData } from '../dnd/dataTransfer';
import { DockviewDropTargets } from '../groupview/dnd';
export interface PanelReference { export interface PanelReference {
update: (event: { params: { [key: string]: any } }) => void; update: (event: { params: { [key: string]: any } }) => void;
@ -80,10 +77,10 @@ export type DockviewComponentUpdateOptions = Pick<
export interface DockviewDropEvent extends GroupviewDropEvent { export interface DockviewDropEvent extends GroupviewDropEvent {
api: DockviewApi; api: DockviewApi;
group: GroupPanel | null; group: DockviewGroupPanel | null;
} }
export interface IDockviewComponent extends IBaseGrid<GroupPanel> { export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
readonly activePanel: IDockviewPanel | undefined; readonly activePanel: IDockviewPanel | undefined;
readonly totalPanels: number; readonly totalPanels: number;
readonly panels: IDockviewPanel[]; readonly panels: IDockviewPanel[];
@ -93,21 +90,21 @@ export interface IDockviewComponent extends IBaseGrid<GroupPanel> {
deserializer: IPanelDeserializer | undefined; deserializer: IPanelDeserializer | undefined;
updateOptions(options: DockviewComponentUpdateOptions): void; updateOptions(options: DockviewComponentUpdateOptions): void;
moveGroupOrPanel( moveGroupOrPanel(
referenceGroup: GroupPanel, referenceGroup: DockviewGroupPanel,
groupId: string, groupId: string,
itemId: string, itemId: string,
target: Position, target: Position,
index?: number index?: number
): void; ): void;
doSetGroupActive: (group: GroupPanel, skipFocus?: boolean) => void; doSetGroupActive: (group: DockviewGroupPanel, skipFocus?: boolean) => void;
removeGroup: (group: GroupPanel) => void; removeGroup: (group: DockviewGroupPanel) => void;
options: DockviewComponentOptions; options: DockviewComponentOptions;
addPanel(options: AddPanelOptions): IDockviewPanel; addPanel(options: AddPanelOptions): IDockviewPanel;
removePanel(panel: IDockviewPanel): void; removePanel(panel: IDockviewPanel): void;
getGroupPanel: (id: string) => IDockviewPanel | undefined; getGroupPanel: (id: string) => IDockviewPanel | undefined;
createWatermarkComponent(): IWatermarkRenderer; createWatermarkComponent(): IWatermarkRenderer;
// lifecycle // lifecycle
addGroup(options?: AddGroupOptions): IGroupviewPanel; addGroup(options?: AddGroupOptions): IDockviewGroupPanel;
closeAllGroups(): void; closeAllGroups(): void;
// events // events
moveToNext(options?: MovementOptions): void; moveToNext(options?: MovementOptions): void;
@ -124,7 +121,7 @@ export interface IDockviewComponent extends IBaseGrid<GroupPanel> {
} }
export class DockviewComponent export class DockviewComponent
extends BaseGrid<GroupPanel> extends BaseGrid<DockviewGroupPanel>
implements IDockviewComponent implements IDockviewComponent
{ {
private readonly nextGroupId = sequentialNumberGenerator(); private readonly nextGroupId = sequentialNumberGenerator();
@ -301,7 +298,7 @@ export class DockviewComponent
this.updateWatermark(); this.updateWatermark();
} }
private orthogonalize(position: Position): GroupPanel { private orthogonalize(position: Position): DockviewGroupPanel {
switch (position) { switch (position) {
case 'top': case 'top':
case 'bottom': case 'bottom':
@ -381,7 +378,7 @@ export class DockviewComponent
} }
const location = getGridLocation(options.group.element); const location = getGridLocation(options.group.element);
const next = <GroupPanel>this.gridview.next(location)?.view; const next = <DockviewGroupPanel>this.gridview.next(location)?.view;
this.doSetGroupActive(next); this.doSetGroupActive(next);
} }
@ -403,7 +400,7 @@ export class DockviewComponent
const location = getGridLocation(options.group.element); const location = getGridLocation(options.group.element);
const next = this.gridview.previous(location)?.view; const next = this.gridview.previous(location)?.view;
if (next) { if (next) {
this.doSetGroupActive(next as GroupPanel); this.doSetGroupActive(next as DockviewGroupPanel);
} }
} }
@ -532,7 +529,7 @@ export class DockviewComponent
throw new Error(`panel with id ${options.id} already exists`); throw new Error(`panel with id ${options.id} already exists`);
} }
let referenceGroup: GroupPanel | undefined; let referenceGroup: DockviewGroupPanel | undefined;
if (options.position) { if (options.position) {
if (isPanelOptionsWithPanel(options.position)) { if (isPanelOptionsWithPanel(options.position)) {
@ -660,16 +657,16 @@ export class DockviewComponent
} }
} else if (this.watermark) { } else if (this.watermark) {
this.watermark.element.parentElement!.remove(); this.watermark.element.parentElement!.remove();
this.watermark.dispose(); this.watermark.dispose?.();
this.watermark = null; this.watermark = null;
} }
} }
addGroup(options?: AddGroupOptions): GroupPanel { addGroup(options?: AddGroupOptions): DockviewGroupPanel {
const group = this.createGroup(); const group = this.createGroup();
if (options) { if (options) {
let referenceGroup: GroupPanel | undefined; let referenceGroup: DockviewGroupPanel | undefined;
if (isGroupOptionsWithPanel(options)) { if (isGroupOptionsWithPanel(options)) {
const referencePanel = const referencePanel =
@ -726,7 +723,7 @@ export class DockviewComponent
} }
} }
removeGroup(group: GroupPanel, skipActive = false): void { removeGroup(group: DockviewGroupPanel, skipActive = false): void {
const panels = [...group.panels]; // reassign since group panels will mutate const panels = [...group.panels]; // reassign since group panels will mutate
for (const panel of panels) { for (const panel of panels) {
@ -740,7 +737,7 @@ export class DockviewComponent
} }
moveGroupOrPanel( moveGroupOrPanel(
referenceGroup: GroupPanel, referenceGroup: DockviewGroupPanel,
groupId: string, groupId: string,
itemId: string | undefined, itemId: string | undefined,
target: Position, target: Position,
@ -831,8 +828,8 @@ export class DockviewComponent
} }
private moveGroup( private moveGroup(
sourceGroup: GroupPanel, sourceGroup: DockviewGroupPanel,
referenceGroup: GroupPanel, referenceGroup: DockviewGroupPanel,
target: Position target: Position
): void { ): void {
if (sourceGroup) { if (sourceGroup) {
@ -872,7 +869,10 @@ export class DockviewComponent
} }
} }
doSetGroupActive(group: GroupPanel | undefined, skipFocus?: boolean): void { doSetGroupActive(
group: DockviewGroupPanel | undefined,
skipFocus?: boolean
): void {
const isGroupAlreadyFocused = this._activeGroup === group; const isGroupAlreadyFocused = this._activeGroup === group;
super.doSetGroupActive(group, skipFocus); super.doSetGroupActive(group, skipFocus);
@ -881,7 +881,7 @@ export class DockviewComponent
} }
} }
createGroup(options?: GroupOptions): GroupPanel { createGroup(options?: GroupOptions): DockviewGroupPanel {
if (!options) { if (!options) {
options = { tabHeight: this.tabHeight }; options = { tabHeight: this.tabHeight };
} }
@ -905,7 +905,7 @@ export class DockviewComponent
} }
} }
const view = new GroupPanel(this, id, options); const view = new DockviewGroupPanel(this, id, options);
view.init({ params: {}, accessor: <any>null }); // required to initialized .part and allow for correct disposal of group view.init({ params: {}, accessor: <any>null }); // required to initialized .part and allow for correct disposal of group
if (!this._groups.has(view.id)) { if (!this._groups.has(view.id)) {
@ -948,19 +948,27 @@ export class DockviewComponent
private createPanel( private createPanel(
options: AddPanelOptions, options: AddPanelOptions,
group: GroupPanel group: DockviewGroupPanel
): IDockviewPanel { ): IDockviewPanel {
const view = new DefaultGroupPanelView({ const contentComponent = options.component;
content: this.createContentComponent(options.id, options.component), const tabComponent =
tab: this.createTabComponent( options.tabComponent || this.options.defaultTabComponent;
options.id,
options.tabComponent || this.options.defaultTabComponent
),
});
const panel = new DockviewPanel(options.id, this, this._api, group); const view = new DockviewPanelModel(
this,
options.id,
contentComponent,
tabComponent
);
const panel = new DockviewPanel(
options.id,
this,
this._api,
group,
view
);
panel.init({ panel.init({
view,
title: options.title || options.id, title: options.title || options.id,
params: options?.params || {}, params: options?.params || {},
}); });
@ -968,40 +976,15 @@ export class DockviewComponent
return panel; return panel;
} }
private createContentComponent( private createGroupAtLocation(
id: string, location: number[] = [0]
componentName: string ): DockviewGroupPanel {
): IContentRenderer {
return createComponent(
id,
componentName,
this.options.components || {},
this.options.frameworkComponents,
this.options.frameworkComponentFactory?.content
);
}
private createTabComponent(
id: string,
componentName?: string
): ITabRenderer {
return createComponent(
id,
componentName,
this.options.tabComponents || {},
this.options.frameworkTabComponents,
this.options.frameworkComponentFactory?.tab,
() => new DefaultTab()
);
}
private createGroupAtLocation(location: number[] = [0]): GroupPanel {
const group = this.createGroup(); const group = this.createGroup();
this.doAddGroup(group, location); this.doAddGroup(group, location);
return group; return group;
} }
private findGroup(panel: IDockviewPanel): GroupPanel | undefined { private findGroup(panel: IDockviewPanel): DockviewGroupPanel | undefined {
return Array.from(this._groups.values()).find((group) => return Array.from(this._groups.values()).find((group) =>
group.value.model.containsPanel(panel) group.value.model.containsPanel(panel)
)?.value; )?.value;

View File

@ -1,29 +1,31 @@
import { IFrameworkPart } from '../panel/types'; import { IFrameworkPart } from '../panel/types';
import { DockviewComponent } from '../dockview/dockviewComponent'; import { DockviewComponent } from '../dockview/dockviewComponent';
import { GridviewPanelApi } from '../api/gridviewPanelApi';
import { import {
GridviewPanelApi, DockviewGroupPanelModel,
GridviewPanelApiImpl, GroupOptions,
} from '../api/gridviewPanelApi'; IHeader,
import { Groupview, GroupOptions, IHeader } from './groupview'; } from './dockviewGroupPanelModel';
import { GridviewPanel, IGridviewPanel } from '../gridview/gridviewPanel'; import { GridviewPanel, IGridviewPanel } from '../gridview/gridviewPanel';
import { IDockviewPanel } from '../dockview/dockviewPanel'; import { IDockviewPanel } from '../dockview/dockviewPanel';
export interface IGroupviewPanel extends IGridviewPanel { export interface IDockviewGroupPanel extends IGridviewPanel {
model: Groupview; model: DockviewGroupPanelModel;
locked: boolean; locked: boolean;
readonly size: number; readonly size: number;
readonly panels: IDockviewPanel[]; readonly panels: IDockviewPanel[];
readonly activePanel: IDockviewPanel | undefined; readonly activePanel: IDockviewPanel | undefined;
} }
export type IGroupviewPanelPublic = IGroupviewPanel; export type IDockviewGroupPanelPublic = IDockviewGroupPanel;
export type GroupviewPanelApi = GridviewPanelApi; export type DockviewGroupPanelApi = GridviewPanelApi;
class GroupviewApi extends GridviewPanelApiImpl implements GroupviewPanelApi {} export class DockviewGroupPanel
extends GridviewPanel
export class GroupPanel extends GridviewPanel implements IGroupviewPanel { implements IDockviewGroupPanel
private readonly _model: Groupview; {
private readonly _model: DockviewGroupPanelModel;
get panels(): IDockviewPanel[] { get panels(): IDockviewPanel[] {
return this._model.panels; return this._model.panels;
@ -37,7 +39,7 @@ export class GroupPanel extends GridviewPanel implements IGroupviewPanel {
return this._model.size; return this._model.size;
} }
get model(): Groupview { get model(): DockviewGroupPanelModel {
return this._model; return this._model;
} }
@ -76,10 +78,16 @@ export class GroupPanel extends GridviewPanel implements IGroupviewPanel {
) { ) {
super(id, 'groupview_default'); super(id, 'groupview_default');
this._model = new Groupview(this.element, accessor, id, options, this); this._model = new DockviewGroupPanelModel(
this.element,
accessor,
id,
options,
this
);
} }
initialize() { initialize(): void {
this._model.initialize(); this._model.initialize();
} }
@ -98,6 +106,7 @@ export class GroupPanel extends GridviewPanel implements IGroupviewPanel {
} }
toJSON(): any { toJSON(): any {
// TODO fix typing
return this.model.toJSON(); return this.model.toJSON();
} }
} }

View File

@ -1,29 +1,34 @@
import { DockviewApi } from '../api/component.api'; import { DockviewApi } from '../api/component.api';
import { getPanelData, PanelTransfer } from '../dnd/dataTransfer'; import { getPanelData, PanelTransfer } from '../dnd/dataTransfer';
import { Droptarget, Position } from '../dnd/droptarget'; import { Droptarget, Position } from '../dnd/droptarget';
import { DockviewComponent } from '../dockview/dockviewComponent'; import { DockviewComponent } from './dockviewComponent';
import { isAncestor, toggleClass } from '../dom'; import { isAncestor, toggleClass } from '../dom';
import { addDisposableListener, Emitter, Event } from '../events'; import { addDisposableListener, Emitter, Event } from '../events';
import { IGridPanelView } from '../gridview/baseComponentGridview'; import { IGridPanelView } from '../gridview/baseComponentGridview';
import { IViewSize } from '../gridview/gridview'; import { IViewSize } from '../gridview/gridview';
import { CompositeDisposable, IDisposable } from '../lifecycle'; import { CompositeDisposable } from '../lifecycle';
import { PanelInitParameters, PanelUpdateEvent } from '../panel/types'; import { PanelInitParameters, PanelUpdateEvent } from '../panel/types';
import { ContentContainer, IContentContainer } from './panel/content'; import {
import { ITabsContainer, TabsContainer } from './titlebar/tabsContainer'; ContentContainer,
import { IWatermarkRenderer } from './types'; IContentContainer,
import { GroupPanel } from './groupviewPanel'; } from './components/panel/content';
import { DockviewDropTargets } from './dnd'; import {
import { IDockviewPanel } from '../dockview/dockviewPanel'; ITabsContainer,
import { IGroupControlRenderer } from '../dockview/options'; TabsContainer,
} from './components/titlebar/tabsContainer';
import { DockviewDropTargets, IWatermarkRenderer } from './types';
import { DockviewGroupPanel } from './dockviewGroupPanel';
import { IDockviewPanel } from './dockviewPanel';
import { IGroupControlRenderer } from './options';
export interface DndService { export interface DndService {
canDisplayOverlay( canDisplayOverlay(
group: IGroupview, group: IDockviewGroupPanelModel,
event: DragEvent, event: DragEvent,
target: DockviewDropTargets target: DockviewDropTargets
): boolean; ): boolean;
onDrop( onDrop(
group: IGroupview, group: IDockviewGroupPanelModel,
event: DragEvent, event: DragEvent,
position: Position, position: Position,
index?: number index?: number
@ -77,7 +82,7 @@ export interface IHeader {
height: number | undefined; height: number | undefined;
} }
export interface IGroupview extends IDisposable, IGridPanelView { export interface IDockviewGroupPanelModel extends IGridPanelView {
readonly isActive: boolean; readonly isActive: boolean;
readonly size: number; readonly size: number;
readonly panels: IDockviewPanel[]; readonly panels: IDockviewPanel[];
@ -117,7 +122,10 @@ export interface IGroupview extends IDisposable, IGridPanelView {
): boolean; ): boolean;
} }
export class Groupview extends CompositeDisposable implements IGroupview { export class DockviewGroupPanelModel
extends CompositeDisposable
implements IDockviewGroupPanelModel
{
private readonly tabsContainer: ITabsContainer; private readonly tabsContainer: ITabsContainer;
private readonly contentContainer: IContentContainer; private readonly contentContainer: IContentContainer;
private readonly dropTarget: Droptarget; private readonly dropTarget: Droptarget;
@ -232,7 +240,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
private accessor: DockviewComponent, private accessor: DockviewComponent,
public id: string, public id: string,
private readonly options: GroupOptions, private readonly options: GroupOptions,
private readonly groupPanel: GroupPanel private readonly groupPanel: DockviewGroupPanel
) { ) {
super(); super();
@ -427,7 +435,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
} }
focus(): void { focus(): void {
this._activePanel?.focus(); this._activePanel?.focus?.();
} }
public openPanel( public openPanel(
@ -525,7 +533,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
): void { ): void {
if (!force && this.isActive === isGroupActive) { if (!force && this.isActive === isGroupActive) {
if (!skipFocus) { if (!skipFocus) {
this._activePanel?.focus(); this._activePanel?.focus?.();
} }
return; return;
} }
@ -545,7 +553,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
if (isGroupActive) { if (isGroupActive) {
if (!skipFocus) { if (!skipFocus) {
this._activePanel?.focus(); this._activePanel?.focus?.();
} }
} }
} }
@ -681,7 +689,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
} }
if (!this.isEmpty && this.watermark) { if (!this.isEmpty && this.watermark) {
this.watermark.element.remove(); this.watermark.element.remove();
this.watermark.dispose(); this.watermark.dispose?.();
this.watermark = undefined; this.watermark = undefined;
this.tabsContainer.show(); this.tabsContainer.show();
} }
@ -760,7 +768,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
public dispose(): void { public dispose(): void {
super.dispose(); super.dispose();
this.watermark?.dispose(); this.watermark?.dispose?.();
for (const panel of this.panels) { for (const panel of this.panels) {
panel.dispose(); panel.dispose();

View File

@ -7,20 +7,20 @@ import {
GroupPanelUpdateEvent, GroupPanelUpdateEvent,
GroupviewPanelState, GroupviewPanelState,
IGroupPanelInitParameters, IGroupPanelInitParameters,
} from '../groupview/types'; } from './types';
import { GroupPanel } from '../groupview/groupviewPanel'; import { DockviewGroupPanel } from './dockviewGroupPanel';
import { CompositeDisposable, IDisposable } from '../lifecycle'; import { CompositeDisposable, IDisposable } from '../lifecycle';
import { IPanel, Parameters } from '../panel/types'; import { IPanel, Parameters } from '../panel/types';
import { IGroupPanelView } from './defaultGroupPanelView'; import { IDockviewPanelModel } from './dockviewPanelModel';
import { DockviewComponent } from './dockviewComponent'; import { IDockviewComponent } from './dockviewComponent';
export interface IDockviewPanel extends IDisposable, IPanel { export interface IDockviewPanel extends IDisposable, IPanel {
readonly view?: IGroupPanelView; readonly view: IDockviewPanelModel;
readonly group: GroupPanel; readonly group: DockviewGroupPanel;
readonly api: DockviewPanelApi; readonly api: DockviewPanelApi;
readonly title: string; readonly title: string;
readonly params: Record<string, any> | undefined; readonly params: Record<string, any> | undefined;
updateParentGroup(group: GroupPanel, isGroupActive: boolean): void; updateParentGroup(group: DockviewGroupPanel, isGroupActive: boolean): void;
init(params: IGroupPanelInitParameters): void; init(params: IGroupPanelInitParameters): void;
toJSON(): GroupviewPanelState; toJSON(): GroupviewPanelState;
update(event: GroupPanelUpdateEvent): void; update(event: GroupPanelUpdateEvent): void;
@ -31,11 +31,9 @@ export class DockviewPanel
implements IDockviewPanel implements IDockviewPanel
{ {
readonly api: DockviewPanelApiImpl; readonly api: DockviewPanelApiImpl;
private _group: GroupPanel; private _group: DockviewGroupPanel;
private _params?: Parameters; private _params?: Parameters;
private _view?: IGroupPanelView;
private _title: string; private _title: string;
get params(): Parameters | undefined { get params(): Parameters | undefined {
@ -46,19 +44,16 @@ export class DockviewPanel
return this._title; return this._title;
} }
get group(): GroupPanel { get group(): DockviewGroupPanel {
return this._group; return this._group;
} }
get view(): IGroupPanelView | undefined {
return this._view;
}
constructor( constructor(
public readonly id: string, public readonly id: string,
accessor: DockviewComponent, accessor: IDockviewComponent,
private readonly containerApi: DockviewApi, private readonly containerApi: DockviewApi,
group: GroupPanel group: DockviewGroupPanel,
readonly view: IDockviewPanelModel
) { ) {
super(); super();
this._title = ''; this._title = '';
@ -80,11 +75,8 @@ export class DockviewPanel
public init(params: IGroupPanelInitParameters): void { public init(params: IGroupPanelInitParameters): void {
this._params = params.params; this._params = params.params;
this._view = params.view;
if (typeof params.title === 'string') {
this.setTitle(params.title); this.setTitle(params.title);
}
this.view?.init({ this.view?.init({
...params, ...params,
@ -100,7 +92,8 @@ export class DockviewPanel
public toJSON(): GroupviewPanelState { public toJSON(): GroupviewPanelState {
return <GroupviewPanelState>{ return <GroupviewPanelState>{
id: this.id, id: this.id,
view: this.view!.toJSON(), contentComponent: this.view.contentComponent,
tabComponent: this.view.tabComponent,
params: params:
Object.keys(this._params || {}).length > 0 Object.keys(this._params || {}).length > 0
? this._params ? this._params
@ -133,12 +126,10 @@ export class DockviewPanel
...event.params.params, ...event.params.params,
}; };
if (typeof params.title === 'string') {
if (params.title !== this.title) { if (params.title !== this.title) {
this._title = params.title; this._title = params.title;
this.api._onDidTitleChange.fire({ title: this.title }); this.api._onDidTitleChange.fire({ title: this.title });
} }
}
this.view?.update({ this.view?.update({
params: { params: {
@ -148,7 +139,10 @@ export class DockviewPanel
}); });
} }
public updateParentGroup(group: GroupPanel, isGroupActive: boolean): void { public updateParentGroup(
group: DockviewGroupPanel,
isGroupActive: boolean
): void {
this._group = group; this._group = group;
this.api.group = group; this.api.group = group;

View File

@ -0,0 +1,120 @@
import { DefaultTab } from './components/tab/defaultTab';
import {
GroupPanelPartInitParameters,
IContentRenderer,
ITabRenderer,
GroupPanelUpdateEvent,
} from './types';
import { DockviewGroupPanel } from './dockviewGroupPanel';
import { IDisposable } from '../lifecycle';
import { createComponent } from '../panel/componentFactory';
import { IDockviewComponent } from './dockviewComponent';
export interface IDockviewPanelModel extends IDisposable {
readonly contentComponent: string;
readonly tabComponent?: string;
readonly content: IContentRenderer;
readonly tab?: ITabRenderer;
update(event: GroupPanelUpdateEvent): void;
layout(width: number, height: number): void;
init(params: GroupPanelPartInitParameters): void;
updateParentGroup(group: DockviewGroupPanel, isPanelVisible: boolean): void;
}
export class DockviewPanelModel implements IDockviewPanelModel {
private readonly _content: IContentRenderer;
private readonly _tab: ITabRenderer;
private _group: DockviewGroupPanel | null = null;
private _isPanelVisible: boolean | null = null;
get content(): IContentRenderer {
return this._content;
}
get tab(): ITabRenderer {
return this._tab;
}
constructor(
private readonly accessor: IDockviewComponent,
private readonly id: string,
readonly contentComponent: string,
readonly tabComponent?: string
) {
this._content = this.createContentComponent(this.id, contentComponent);
this._tab =
this.createTabComponent(this.id, tabComponent) ?? new DefaultTab();
}
init(params: GroupPanelPartInitParameters): void {
this.content.init({ ...params, tab: this.tab });
this.tab.init(params);
}
updateParentGroup(
group: DockviewGroupPanel,
isPanelVisible: boolean
): void {
if (group !== this._group) {
this._group = group;
if (this._content.onGroupChange) {
this._content.onGroupChange(group);
}
if (this._tab.onGroupChange) {
this._tab.onGroupChange(group);
}
}
if (isPanelVisible !== this._isPanelVisible) {
this._isPanelVisible = isPanelVisible;
if (this._content.onPanelVisibleChange) {
this._content.onPanelVisibleChange(isPanelVisible);
}
if (this._tab.onPanelVisibleChange) {
this._tab.onPanelVisibleChange(isPanelVisible);
}
}
}
layout(width: number, height: number): void {
this.content.layout?.(width, height);
}
update(event: GroupPanelUpdateEvent): void {
this.content.update?.(event);
this.tab.update?.(event);
}
dispose(): void {
this.content.dispose?.();
this.tab.dispose?.();
}
private createContentComponent(
id: string,
componentName: string
): IContentRenderer {
return createComponent(
id,
componentName,
this.accessor.options.components || {},
this.accessor.options.frameworkComponents,
this.accessor.options.frameworkComponentFactory?.content
);
}
private createTabComponent(
id: string,
componentName?: string
): ITabRenderer {
return createComponent(
id,
componentName,
this.accessor.options.tabComponents || {},
this.accessor.options.frameworkTabComponents,
this.accessor.options.frameworkComponentFactory?.tab,
() => new DefaultTab()
);
}
}

View File

@ -6,11 +6,14 @@ import {
ITabRenderer, ITabRenderer,
WatermarkConstructor, WatermarkConstructor,
IWatermarkRenderer, IWatermarkRenderer,
} from '../groupview/types'; DockviewDropTargets,
import { GroupPanel, GroupviewPanelApi } from '../groupview/groupviewPanel'; } from './types';
import {
DockviewGroupPanel,
DockviewGroupPanelApi,
} from './dockviewGroupPanel';
import { ISplitviewStyles, Orientation } from '../splitview/core/splitview'; import { ISplitviewStyles, Orientation } from '../splitview/core/splitview';
import { FrameworkFactory } from '../types'; import { FrameworkFactory } from '../types';
import { DockviewDropTargets } from '../groupview/dnd';
import { PanelTransfer } from '../dnd/dataTransfer'; import { PanelTransfer } from '../dnd/dataTransfer';
import { IDisposable } from '../lifecycle'; import { IDisposable } from '../lifecycle';
import { Position } from '../dnd/droptarget'; import { Position } from '../dnd/droptarget';
@ -18,7 +21,10 @@ import { IDockviewPanel } from './dockviewPanel';
export interface IGroupControlRenderer extends IDisposable { export interface IGroupControlRenderer extends IDisposable {
readonly element: HTMLElement; readonly element: HTMLElement;
init(params: { containerApi: DockviewApi; api: GroupviewPanelApi }): void; init(params: {
containerApi: DockviewApi;
api: DockviewGroupPanelApi;
}): void;
} }
export interface GroupPanelFrameworkComponentFactory { export interface GroupPanelFrameworkComponentFactory {
@ -61,7 +67,7 @@ export interface DockviewDndOverlayEvent {
nativeEvent: DragEvent; nativeEvent: DragEvent;
target: DockviewDropTargets; target: DockviewDropTargets;
position: Position; position: Position;
group?: GroupPanel; group?: DockviewGroupPanel;
getData: () => PanelTransfer | undefined; getData: () => PanelTransfer | undefined;
} }
@ -74,7 +80,9 @@ export interface DockviewComponentOptions extends DockviewRenderFunctions {
styles?: ISplitviewStyles; styles?: ISplitviewStyles;
defaultTabComponent?: string; defaultTabComponent?: string;
showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean; showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
createGroupControlElement?: (group: GroupPanel) => IGroupControlRenderer; createGroupControlElement?: (
group: DockviewGroupPanel
) => IGroupControlRenderer;
singleTabMode?: 'fullwidth' | 'default'; singleTabMode?: 'fullwidth' | 'default';
} }
@ -93,7 +101,7 @@ type RelativePanel = {
type RelativeGroup = { type RelativeGroup = {
direction?: Direction; direction?: Direction;
referenceGroup: string | GroupPanel; referenceGroup: string | DockviewGroupPanel;
}; };
type AbsolutePosition = { type AbsolutePosition = {
@ -136,7 +144,7 @@ type AddGroupOptionsWithPanel = {
}; };
type AddGroupOptionsWithGroup = { type AddGroupOptionsWithGroup = {
referenceGroup: string | GroupPanel; referenceGroup: string | DockviewGroupPanel;
direction?: Omit<Direction, 'within'>; direction?: Omit<Direction, 'within'>;
}; };
@ -169,5 +177,5 @@ export interface MovementOptions2 {
export interface MovementOptions extends MovementOptions2 { export interface MovementOptions extends MovementOptions2 {
includePanel?: boolean; includePanel?: boolean;
group?: GroupPanel; group?: DockviewGroupPanel;
} }

View File

@ -1,4 +1,4 @@
import { IDockviewComponent } from '../dockview/dockviewComponent'; import { IDockviewComponent } from './dockviewComponent';
import { DockviewPanelApi } from '../api/dockviewPanelApi'; import { DockviewPanelApi } from '../api/dockviewPanelApi';
import { import {
PanelInitParameters, PanelInitParameters,
@ -7,19 +7,19 @@ import {
Parameters, Parameters,
} from '../panel/types'; } from '../panel/types';
import { DockviewApi } from '../api/component.api'; import { DockviewApi } from '../api/component.api';
import { GroupPanel } from './groupviewPanel';
import { Event } from '../events'; import { Event } from '../events';
import { IGroupPanelView } from '../dockview/defaultGroupPanelView'; import { Optional } from '../types';
import { DockviewGroupPanel } from './dockviewGroupPanel';
export interface IRenderable { export enum DockviewDropTargets {
id: string; Tab,
element: HTMLElement; Panel,
onDidFocus?: Event<void>; TabContainer,
onDidBlur?: Event<void>; Edge,
} }
export interface HeaderPartInitParameters { export interface HeaderPartInitParameters {
title?: string; title: string;
} }
export interface GroupPanelPartInitParameters export interface GroupPanelPartInitParameters
@ -34,26 +34,38 @@ export interface GroupPanelContentPartInitParameters
tab: ITabRenderer; tab: ITabRenderer;
} }
export interface IWatermarkRenderer extends IPanel { export interface IWatermarkRenderer
extends Optional<
Omit<IPanel, 'id'>,
'dispose' | 'update' | 'layout' | 'toJSON'
> {
readonly element: HTMLElement; readonly element: HTMLElement;
init: (params: GroupPanelPartInitParameters) => void; init: (params: GroupPanelPartInitParameters) => void;
updateParentGroup(group: GroupPanel, visible: boolean): void; updateParentGroup(group: DockviewGroupPanel, visible: boolean): void;
} }
export interface ITabRenderer extends IPanel { export interface ITabRenderer
extends Optional<
Omit<IPanel, 'id'>,
'dispose' | 'update' | 'layout' | 'toJSON'
> {
readonly element: HTMLElement; readonly element: HTMLElement;
init(parameters: GroupPanelPartInitParameters): void; init(parameters: GroupPanelPartInitParameters): void;
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void; onGroupChange?(group: DockviewGroupPanel): void;
onPanelVisibleChange?(isPanelVisible: boolean): void;
} }
export interface IContentRenderer extends IPanel { export interface IContentRenderer
extends Optional<
Omit<IPanel, 'id'>,
'dispose' | 'update' | 'layout' | 'toJSON'
> {
readonly element: HTMLElement; readonly element: HTMLElement;
readonly actions?: HTMLElement;
readonly onDidFocus?: Event<void>; readonly onDidFocus?: Event<void>;
readonly onDidBlur?: Event<void>; readonly onDidBlur?: Event<void>;
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void;
init(parameters: GroupPanelContentPartInitParameters): void; init(parameters: GroupPanelContentPartInitParameters): void;
layout(width: number, height: number): void; onGroupChange?(group: DockviewGroupPanel): void;
onPanelVisibleChange?(isPanelVisible: boolean): void;
} }
// watermark component // watermark component
@ -64,13 +76,6 @@ export interface WatermarkPartInitParameters {
// constructors // constructors
export interface PanelHeaderPartConstructor {
new (): ITabRenderer;
}
export interface PanelContentPartConstructor {
new (): IContentRenderer;
}
export interface WatermarkConstructor { export interface WatermarkConstructor {
new (): IWatermarkRenderer; new (): IWatermarkRenderer;
} }
@ -78,7 +83,7 @@ export interface WatermarkConstructor {
export interface IGroupPanelInitParameters export interface IGroupPanelInitParameters
extends PanelInitParameters, extends PanelInitParameters,
HeaderPartInitParameters { HeaderPartInitParameters {
view: IGroupPanelView; //
} }
export type GroupPanelUpdateEvent = PanelUpdateEvent<{ export type GroupPanelUpdateEvent = PanelUpdateEvent<{
@ -88,7 +93,8 @@ export type GroupPanelUpdateEvent = PanelUpdateEvent<{
export interface GroupviewPanelState { export interface GroupviewPanelState {
id: string; id: string;
view?: any; contentComponent?: string;
tabComponent?: string;
title?: string; title?: string;
params?: { [key: string]: any }; params?: { [key: string]: any };
} }

View File

@ -25,7 +25,10 @@ export function watchElementResize(
}; };
} }
export const removeClasses = (element: HTMLElement, ...classes: string[]) => { export const removeClasses = (
element: HTMLElement,
...classes: string[]
): void => {
for (const classname of classes) { for (const classname of classes) {
if (element.classList.contains(classname)) { if (element.classList.contains(classname)) {
element.classList.remove(classname); element.classList.remove(classname);
@ -33,7 +36,10 @@ export const removeClasses = (element: HTMLElement, ...classes: string[]) => {
} }
}; };
export const addClasses = (element: HTMLElement, ...classes: string[]) => { export const addClasses = (
element: HTMLElement,
...classes: string[]
): void => {
for (const classname of classes) { for (const classname of classes) {
if (!element.classList.contains(classname)) { if (!element.classList.contains(classname)) {
element.classList.add(classname); element.classList.add(classname);
@ -45,7 +51,7 @@ export const toggleClass = (
element: HTMLElement, element: HTMLElement,
className: string, className: string,
isToggled: boolean isToggled: boolean
) => { ): void => {
const hasClass = element.classList.contains(className); const hasClass = element.classList.contains(className);
if (isToggled && !hasClass) { if (isToggled && !hasClass) {
element.classList.add(className); element.classList.add(className);
@ -74,8 +80,8 @@ export function getElementsByTagName(tag: string): HTMLElement[] {
} }
export interface IFocusTracker extends IDisposable { export interface IFocusTracker extends IDisposable {
onDidFocus: Event<void>; readonly onDidFocus: Event<void>;
onDidBlur: Event<void>; readonly onDidBlur: Event<void>;
refreshState?(): void; refreshState?(): void;
} }
@ -153,11 +159,11 @@ class FocusTracker extends CompositeDisposable implements IFocusTracker {
} }
} }
refreshState() { refreshState(): void {
this._refreshStateHandler(); this._refreshStateHandler();
} }
public dispose() { public dispose(): void {
super.dispose(); super.dispose();
this._onDidBlur.dispose(); this._onDidBlur.dispose();

View File

@ -5,7 +5,7 @@ export interface Event<T> {
} }
export interface EmitterOptions { export interface EmitterOptions {
replay?: boolean; readonly replay?: boolean;
} }
export namespace Event { export namespace Event {
@ -35,7 +35,7 @@ export class Emitter<T> implements IDisposable {
constructor(private readonly options?: EmitterOptions) {} constructor(private readonly options?: EmitterOptions) {}
get event() { get event(): Event<T> {
if (!this._event) { if (!this._event) {
this._event = (listener: (e: T) => void): IDisposable => { this._event = (listener: (e: T) => void): IDisposable => {
if (this.options?.replay && this._last !== undefined) { if (this.options?.replay && this._last !== undefined) {
@ -57,14 +57,14 @@ export class Emitter<T> implements IDisposable {
return this._event; return this._event;
} }
public fire(e: T) { public fire(e: T): void {
this._last = e; this._last = e;
for (const listener of this._listeners) { for (const listener of this._listeners) {
listener(e); listener(e);
} }
} }
public dispose() { public dispose(): void {
this._listeners = []; this._listeners = [];
this._disposed = true; this._disposed = true;
} }

View File

@ -92,40 +92,40 @@ export abstract class BaseGrid<T extends IGridPanelView>
protected readonly _bufferOnDidLayoutChange = new TickDelayedEvent(); protected readonly _bufferOnDidLayoutChange = new TickDelayedEvent();
get id() { get id(): string {
return this._id; return this._id;
} }
get element() { get element(): HTMLElement {
return this._element; return this._element;
} }
get size() { get size(): number {
return this._groups.size; return this._groups.size;
} }
get groups() { get groups(): T[] {
return Array.from(this._groups.values()).map((_) => _.value); return Array.from(this._groups.values()).map((_) => _.value);
} }
get width() { get width(): number {
return this.gridview.width; return this.gridview.width;
} }
get height() { get height(): number {
return this.gridview.height; return this.gridview.height;
} }
get minimumHeight() { get minimumHeight(): number {
return this.gridview.minimumHeight; return this.gridview.minimumHeight;
} }
get maximumHeight() { get maximumHeight(): number {
return this.gridview.maximumHeight; return this.gridview.maximumHeight;
} }
get minimumWidth() { get minimumWidth(): number {
return this.gridview.minimumWidth; return this.gridview.minimumWidth;
} }
get maximumWidth() { get maximumWidth(): number {
return this.gridview.maximumWidth; return this.gridview.maximumWidth;
} }
@ -176,16 +176,20 @@ export abstract class BaseGrid<T extends IGridPanelView>
public abstract clear(): void; public abstract clear(): void;
public setVisible(panel: T, visible: boolean) { public setVisible(panel: T, visible: boolean): void {
this.gridview.setViewVisible(getGridLocation(panel.element), visible); this.gridview.setViewVisible(getGridLocation(panel.element), visible);
this._onDidLayoutChange.fire(); this._onDidLayoutChange.fire();
} }
public isVisible(panel: T) { public isVisible(panel: T): boolean {
return this.gridview.isViewVisible(getGridLocation(panel.element)); return this.gridview.isViewVisible(getGridLocation(panel.element));
} }
protected doAddGroup(group: T, location: number[] = [0], size?: number) { protected doAddGroup(
group: T,
location: number[] = [0],
size?: number
): void {
this.gridview.addView(group, size ?? Sizing.Distribute, location); this.gridview.addView(group, size ?? Sizing.Distribute, location);
this._onDidAddGroup.fire(group); this._onDidAddGroup.fire(group);
@ -196,7 +200,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
protected doRemoveGroup( protected doRemoveGroup(
group: T, group: T,
options?: { skipActive?: boolean; skipDispose?: boolean } options?: { skipActive?: boolean; skipDispose?: boolean }
) { ): T {
if (!this._groups.has(group.id)) { if (!this._groups.has(group.id)) {
throw new Error('invalid operation'); throw new Error('invalid operation');
} }
@ -228,21 +232,21 @@ export abstract class BaseGrid<T extends IGridPanelView>
return this._groups.get(id)?.value; return this._groups.get(id)?.value;
} }
public doSetGroupActive(group: T | undefined, skipFocus?: boolean) { public doSetGroupActive(group: T | undefined, skipFocus?: boolean): void {
if (this._activeGroup === group) { if (this._activeGroup === group) {
return; return;
} }
if (this._activeGroup) { if (this._activeGroup) {
this._activeGroup.setActive(false); this._activeGroup.setActive(false);
if (!skipFocus) { if (!skipFocus) {
this._activeGroup.focus(); this._activeGroup.focus?.();
} }
} }
if (group) { if (group) {
group.setActive(true); group.setActive(true);
if (!skipFocus) { if (!skipFocus) {
group.focus(); group.focus?.();
} }
} }
@ -251,11 +255,11 @@ export abstract class BaseGrid<T extends IGridPanelView>
this._onDidActiveGroupChange.fire(group); this._onDidActiveGroupChange.fire(group);
} }
public removeGroup(group: T) { public removeGroup(group: T): void {
this.doRemoveGroup(group); this.doRemoveGroup(group);
} }
public moveToNext(options?: MovementOptions2) { public moveToNext(options?: MovementOptions2): void {
if (!options) { if (!options) {
options = {}; options = {};
} }
@ -271,7 +275,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
this.doSetGroupActive(next as T); this.doSetGroupActive(next as T);
} }
public moveToPrevious(options?: MovementOptions2) { public moveToPrevious(options?: MovementOptions2): void {
if (!options) { if (!options) {
options = {}; options = {};
} }

View File

@ -40,15 +40,15 @@ export abstract class BasePanelView<T extends PanelApiImpl>
*/ */
protected abstract getComponent(): IFrameworkPart; protected abstract getComponent(): IFrameworkPart;
get element() { get element(): HTMLElement {
return this._element; return this._element;
} }
get width() { get width(): number {
return this._width; return this._width;
} }
get height() { get height(): number {
return this._height; return this._height;
} }
@ -83,11 +83,11 @@ export abstract class BasePanelView<T extends PanelApiImpl>
); );
} }
focus() { focus(): void {
this.api._onFocusEvent.fire(); this.api._onFocusEvent.fire();
} }
layout(width: number, height: number) { layout(width: number, height: number): void {
this._width = width; this._width = width;
this._height = height; this._height = height;
this.api._onDidDimensionChange.fire({ width, height }); this.api._onDidDimensionChange.fire({ width, height });
@ -104,7 +104,7 @@ export abstract class BasePanelView<T extends PanelApiImpl>
this.part = this.getComponent(); this.part = this.getComponent();
} }
update(event: PanelUpdateEvent) { update(event: PanelUpdateEvent): void {
this._params = { this._params = {
...this._params, ...this._params,
params: { params: {
@ -125,7 +125,7 @@ export abstract class BasePanelView<T extends PanelApiImpl>
}; };
} }
dispose() { dispose(): void {
super.dispose(); super.dispose();
this.api.dispose(); this.api.dispose();

View File

@ -22,6 +22,8 @@ export class BranchNode extends CompositeDisposable implements IView {
private splitview: Splitview; private splitview: Splitview;
private _orthogonalSize: number; private _orthogonalSize: number;
private _size: number; private _size: number;
private _childrenDisposable: IDisposable = Disposable.NONE;
public readonly children: Node[] = []; public readonly children: Node[] = [];
private readonly _onDidChange = new Emitter<{ private readonly _onDidChange = new Emitter<{
@ -61,11 +63,11 @@ export class BranchNode extends CompositeDisposable implements IView {
return this.splitview.maximumSize; return this.splitview.maximumSize;
} }
get orthogonalSize() { get orthogonalSize(): number {
return this._orthogonalSize; return this._orthogonalSize;
} }
get size() { get size(): number {
return this._size; return this._size;
} }
@ -168,7 +170,7 @@ export class BranchNode extends CompositeDisposable implements IView {
this.setupChildrenEvents(); this.setupChildrenEvents();
} }
setVisible(visible: boolean) { setVisible(visible: boolean): void {
for (const child of this.children) { for (const child of this.children) {
child.setVisible(visible); child.setVisible(visible);
} }
@ -258,7 +260,7 @@ export class BranchNode extends CompositeDisposable implements IView {
return this.splitview.getViewCachedVisibleSize(index); return this.splitview.getViewCachedVisibleSize(index);
} }
public removeChild(index: number, sizing?: Sizing) { public removeChild(index: number, sizing?: Sizing): void {
if (index < 0 || index >= this.children.length) { if (index < 0 || index >= this.children.length) {
throw new Error('Invalid index'); throw new Error('Invalid index');
} }
@ -279,9 +281,7 @@ export class BranchNode extends CompositeDisposable implements IView {
return child; return child;
} }
private _childrenDisposable: IDisposable = Disposable.NONE; private setupChildrenEvents(): void {
private setupChildrenEvents() {
this._childrenDisposable.dispose(); this._childrenDisposable.dispose();
this._childrenDisposable = Event.any( this._childrenDisposable = Event.any(
@ -295,7 +295,7 @@ export class BranchNode extends CompositeDisposable implements IView {
}); });
} }
public dispose() { public dispose(): void {
super.dispose(); super.dispose();
this._childrenDisposable.dispose(); this._childrenDisposable.dispose();
this.children.forEach((child) => child.dispose()); this.children.forEach((child) => child.dispose());

View File

@ -261,6 +261,14 @@ export interface INodeDescriptor {
export interface IViewDeserializer { export interface IViewDeserializer {
fromJSON: (data: ISerializedLeafNode) => IGridView; fromJSON: (data: ISerializedLeafNode) => IGridView;
} }
export interface SerializedGridview<T> {
root: SerializedGridObject<T>;
width: number;
height: number;
orientation: Orientation;
}
export class Gridview implements IDisposable { export class Gridview implements IDisposable {
private _root: BranchNode | undefined; private _root: BranchNode | undefined;
public readonly element: HTMLElement; public readonly element: HTMLElement;
@ -277,7 +285,41 @@ export class Gridview implements IDisposable {
return this._root ? this._root.children.length : 0; return this._root ? this._root.children.length : 0;
} }
public serialize() { public get orientation(): Orientation {
return this.root.orientation;
}
public set orientation(orientation: Orientation) {
if (this.root.orientation === orientation) {
return;
}
const { size, orthogonalSize } = this.root;
this.root = flipNode(this.root, orthogonalSize, size);
this.root.layout(size, orthogonalSize);
}
get width(): number {
return this.root.width;
}
get height(): number {
return this.root.height;
}
get minimumWidth(): number {
return this.root.minimumWidth;
}
get minimumHeight(): number {
return this.root.minimumHeight;
}
get maximumWidth(): number {
return this.root.maximumHeight;
}
get maximumHeight(): number {
return this.root.maximumHeight;
}
public serialize(): SerializedGridview<any> {
const root = serializeBranchNode(this.getView(), this.orientation); const root = serializeBranchNode(this.getView(), this.orientation);
return { return {
@ -288,7 +330,7 @@ export class Gridview implements IDisposable {
}; };
} }
public dispose() { public dispose(): void {
this.disposable.dispose(); this.disposable.dispose();
this._onDidChange.dispose(); this._onDidChange.dispose();
this.root.dispose(); this.root.dispose();
@ -296,7 +338,7 @@ export class Gridview implements IDisposable {
this.element.remove(); this.element.remove();
} }
public clear() { public clear(): void {
const orientation = this.root.orientation; const orientation = this.root.orientation;
this.root = new BranchNode( this.root = new BranchNode(
orientation, orientation,
@ -307,7 +349,7 @@ export class Gridview implements IDisposable {
); );
} }
public deserialize(json: any, deserializer: IViewDeserializer) { public deserialize(json: any, deserializer: IViewDeserializer): void {
const orientation = json.orientation; const orientation = json.orientation;
const height = const height =
orientation === Orientation.VERTICAL ? json.height : json.width; orientation === Orientation.VERTICAL ? json.height : json.width;
@ -378,20 +420,6 @@ export class Gridview implements IDisposable {
return result; return result;
} }
public get orientation() {
return this.root.orientation;
}
public set orientation(orientation: Orientation) {
if (this.root.orientation === orientation) {
return;
}
const { size, orthogonalSize } = this.root;
this.root = flipNode(this.root, orthogonalSize, size);
this.root.layout(size, orthogonalSize);
}
private get root(): BranchNode { private get root(): BranchNode {
return this._root!; return this._root!;
} }
@ -448,11 +476,11 @@ export class Gridview implements IDisposable {
}); });
} }
public next(location: number[]) { public next(location: number[]): LeafNode {
return this.progmaticSelect(location); return this.progmaticSelect(location);
} }
public previous(location: number[]) { public previous(location: number[]): LeafNode {
return this.progmaticSelect(location, true); return this.progmaticSelect(location, true);
} }
@ -492,7 +520,7 @@ export class Gridview implements IDisposable {
return { box, children }; return { box, children };
} }
private progmaticSelect(location: number[], reverse = false) { private progmaticSelect(location: number[], reverse = false): LeafNode {
const [path, node] = this.getNode(location); const [path, node] = this.getNode(location);
if (!(node instanceof LeafNode)) { if (!(node instanceof LeafNode)) {
@ -513,26 +541,6 @@ export class Gridview implements IDisposable {
return findLeaf(this.root, reverse); return findLeaf(this.root, reverse);
} }
get width(): number {
return this.root.width;
}
get height(): number {
return this.root.height;
}
get minimumWidth(): number {
return this.root.minimumWidth;
}
get minimumHeight(): number {
return this.root.minimumHeight;
}
get maximumWidth(): number {
return this.root.maximumHeight;
}
get maximumHeight(): number {
return this.root.maximumHeight;
}
constructor( constructor(
readonly proportionalLayout: boolean, readonly proportionalLayout: boolean,
readonly styles: ISplitviewStyles | undefined, readonly styles: ISplitviewStyles | undefined,
@ -581,7 +589,11 @@ export class Gridview implements IDisposable {
parent.moveChild(from, to); parent.moveChild(from, to);
} }
public addView(view: IGridView, size: number | Sizing, location: number[]) { public addView(
view: IGridView,
size: number | Sizing,
location: number[]
): void {
const [rest, index] = tail(location); const [rest, index] = tail(location);
const [pathToParent, parent] = this.getNode(rest); const [pathToParent, parent] = this.getNode(rest);
@ -636,7 +648,7 @@ export class Gridview implements IDisposable {
} }
} }
public remove(view: IGridView, sizing?: Sizing) { public remove(view: IGridView, sizing?: Sizing): IGridView {
const location = getGridLocation(view.element); const location = getGridLocation(view.element);
return this.removeView(location, sizing); return this.removeView(location, sizing);
} }
@ -721,7 +733,7 @@ export class Gridview implements IDisposable {
return node.view; return node.view;
} }
public layout(width: number, height: number) { public layout(width: number, height: number): void {
const [size, orthogonalSize] = const [size, orthogonalSize] =
this.root.orientation === Orientation.HORIZONTAL this.root.orientation === Orientation.HORIZONTAL
? [height, width] ? [height, width]

View File

@ -2,6 +2,7 @@ import {
getRelativeLocation, getRelativeLocation,
SerializedGridObject, SerializedGridObject,
getGridLocation, getGridLocation,
SerializedGridview,
} from './gridview'; } from './gridview';
import { tail, sequenceEquals } from '../array'; import { tail, sequenceEquals } from '../array';
import { CompositeDisposable } from '../lifecycle'; import { CompositeDisposable } from '../lifecycle';
@ -26,13 +27,8 @@ import { createComponent } from '../panel/componentFactory';
import { Emitter, Event } from '../events'; import { Emitter, Event } from '../events';
import { Position } from '../dnd/droptarget'; import { Position } from '../dnd/droptarget';
export interface SerializedGridview { export interface SerializedGridviewComponent {
grid: { grid: SerializedGridview<GridPanelViewState>;
height: number;
width: number;
orientation: Orientation;
root: SerializedGridObject<GridPanelViewState>;
};
activePanel?: string; activePanel?: string;
} }
@ -64,8 +60,8 @@ export interface IGridviewComponent extends IBaseGrid<GridviewPanel> {
addPanel(options: AddComponentOptions): IGridviewPanel; addPanel(options: AddComponentOptions): IGridviewPanel;
removePanel(panel: IGridviewPanel, sizing?: Sizing): void; removePanel(panel: IGridviewPanel, sizing?: Sizing): void;
focus(): void; focus(): void;
fromJSON(serializedGridview: SerializedGridview): void; fromJSON(serializedGridview: SerializedGridviewComponent): void;
toJSON(): SerializedGridview; toJSON(): SerializedGridviewComponent;
movePanel( movePanel(
panel: IGridviewPanel, panel: IGridviewPanel,
options: { direction: Direction; reference: string; size?: number } options: { direction: Direction; reference: string; size?: number }
@ -84,7 +80,7 @@ export class GridviewComponent
private readonly _onDidLayoutfromJSON = new Emitter<void>(); private readonly _onDidLayoutfromJSON = new Emitter<void>();
readonly onDidLayoutFromJSON: Event<void> = this._onDidLayoutfromJSON.event; readonly onDidLayoutFromJSON: Event<void> = this._onDidLayoutfromJSON.event;
get orientation() { get orientation(): Orientation {
return this.gridview.orientation; return this.gridview.orientation;
} }
@ -92,7 +88,7 @@ export class GridviewComponent
this.gridview.orientation = value; this.gridview.orientation = value;
} }
get options() { get options(): GridviewComponentOptions {
return this._options; return this._options;
} }
@ -135,7 +131,7 @@ export class GridviewComponent
this.layout(this.gridview.width, this.gridview.height, true); this.layout(this.gridview.width, this.gridview.height, true);
} }
removePanel(panel: GridviewPanel) { removePanel(panel: GridviewPanel): void {
this.removeGroup(panel); this.removeGroup(panel);
} }
@ -144,7 +140,7 @@ export class GridviewComponent
* *
* @returns A JSON respresentation of the layout * @returns A JSON respresentation of the layout
*/ */
public toJSON(): SerializedGridview { public toJSON(): SerializedGridviewComponent {
const data = this.gridview.serialize() as { const data = this.gridview.serialize() as {
height: number; height: number;
width: number; width: number;
@ -168,11 +164,11 @@ export class GridviewComponent
}); });
} }
focus() { focus(): void {
this.activeGroup?.focus(); this.activeGroup?.focus();
} }
public fromJSON(serializedGridview: SerializedGridview) { public fromJSON(serializedGridview: SerializedGridviewComponent): void {
this.clear(); this.clear();
const { grid, activePanel } = serializedGridview; const { grid, activePanel } = serializedGridview;
@ -339,7 +335,7 @@ export class GridviewComponent
return view; return view;
} }
private registerPanel(panel: GridviewPanel) { private registerPanel(panel: GridviewPanel): void {
const disposable = new CompositeDisposable( const disposable = new CompositeDisposable(
panel.api.onDidFocusChange((event) => { panel.api.onDidFocusChange((event) => {
if (!event.isFocused) { if (!event.isFocused) {
@ -366,7 +362,7 @@ export class GridviewComponent
referenceGroup: IGridPanelComponentView, referenceGroup: IGridPanelComponentView,
groupId: string, groupId: string,
target: Position target: Position
) { ): void {
const sourceGroup = this.getPanel(groupId); const sourceGroup = this.getPanel(groupId);
if (!sourceGroup) { if (!sourceGroup) {
@ -411,11 +407,11 @@ export class GridviewComponent
this.doAddGroup(targetGroup, location); this.doAddGroup(targetGroup, location);
} }
removeGroup(group: GridviewPanel) { removeGroup(group: GridviewPanel): void {
super.removeGroup(group); super.removeGroup(group);
} }
public dispose() { public dispose(): void {
super.dispose(); super.dispose();
this._onDidLayoutfromJSON.dispose(); this._onDidLayoutfromJSON.dispose();

View File

@ -62,11 +62,11 @@ export abstract class GridviewPanel
return this._priority; return this._priority;
} }
get snap() { get snap(): boolean {
return this._snap; return this._snap;
} }
get minimumWidth() { get minimumWidth(): number {
const width = const width =
typeof this._minimumWidth === 'function' typeof this._minimumWidth === 'function'
? this._minimumWidth() ? this._minimumWidth()
@ -80,7 +80,7 @@ export abstract class GridviewPanel
return width; return width;
} }
get minimumHeight() { get minimumHeight(): number {
const height = const height =
typeof this._minimumHeight === 'function' typeof this._minimumHeight === 'function'
? this._minimumHeight() ? this._minimumHeight()
@ -94,7 +94,7 @@ export abstract class GridviewPanel
return height; return height;
} }
get maximumHeight() { get maximumHeight(): number {
const height = const height =
typeof this._maximumHeight === 'function' typeof this._maximumHeight === 'function'
? this._maximumHeight() ? this._maximumHeight()
@ -108,7 +108,7 @@ export abstract class GridviewPanel
return height; return height;
} }
get maximumWidth() { get maximumWidth(): number {
const width = const width =
typeof this._maximumWidth === 'function' typeof this._maximumWidth === 'function'
? this._maximumWidth() ? this._maximumWidth()
@ -122,7 +122,7 @@ export abstract class GridviewPanel
return width; return width;
} }
get isActive() { get isActive(): boolean {
return this.api.isActive; return this.api.isActive;
} }
@ -177,11 +177,11 @@ export abstract class GridviewPanel
); );
} }
setVisible(isVisible: boolean) { setVisible(isVisible: boolean): void {
this.api._onDidVisibilityChange.fire({ isVisible }); this.api._onDidVisibilityChange.fire({ isVisible });
} }
setActive(isActive: boolean) { setActive(isActive: boolean): void {
this.api._onDidActiveChange.fire({ isActive }); this.api._onDidActiveChange.fire({ isActive });
} }
@ -209,7 +209,7 @@ export abstract class GridviewPanel
} }
} }
private updateConstraints() { private updateConstraints(): void {
this.api._onDidConstraintsChange.fire({ this.api._onDidConstraintsChange.fire({
minimumWidth: this._evaluatedMinimumWidth, minimumWidth: this._evaluatedMinimumWidth,
maximumWidth: this._evaluatedMaximumWidth, maximumWidth: this._evaluatedMaximumWidth,

View File

@ -43,7 +43,7 @@ export class LeafNode implements IView {
return this.view.priority; return this.view.priority;
} }
get snap() { get snap(): boolean | undefined {
return this.view.snap; return this.view.snap;
} }
@ -71,25 +71,25 @@ export class LeafNode implements IView {
: this.maximumHeight; : this.maximumHeight;
} }
get orthogonalSize() { get orthogonalSize(): number {
return this._orthogonalSize; return this._orthogonalSize;
} }
get size() { get size(): number {
return this._size; return this._size;
} }
get element() { get element(): HTMLElement {
return this.view.element; return this.view.element;
} }
get width() { get width(): number {
return this.orientation === Orientation.HORIZONTAL return this.orientation === Orientation.HORIZONTAL
? this.orthogonalSize ? this.orthogonalSize
: this.size; : this.size;
} }
get height() { get height(): number {
return this.orientation === Orientation.HORIZONTAL return this.orientation === Orientation.HORIZONTAL
? this.size ? this.size
: this.orthogonalSize; : this.orthogonalSize;
@ -122,21 +122,21 @@ export class LeafNode implements IView {
}); });
} }
public setVisible(visible: boolean) { public setVisible(visible: boolean): void {
if (this.view.setVisible) { if (this.view.setVisible) {
this.view.setVisible(visible); this.view.setVisible(visible);
this._onDidChange.fire({}); this._onDidChange.fire({});
} }
} }
public layout(size: number, orthogonalSize: number) { public layout(size: number, orthogonalSize: number): void {
this._size = size; this._size = size;
this._orthogonalSize = orthogonalSize; this._orthogonalSize = orthogonalSize;
this.view.layout(this.width, this.height); this.view.layout(this.width, this.height);
} }
public dispose() { public dispose(): void {
this._onDidChange.dispose(); this._onDidChange.dispose();
this._disposable.dispose(); this._disposable.dispose();
} }

View File

@ -1,6 +0,0 @@
export enum DockviewDropTargets {
Tab,
Panel,
TabContainer,
Edge,
}

View File

@ -23,16 +23,15 @@ export * from './splitview/core/options';
export * from './paneview/paneview'; export * from './paneview/paneview';
export * from './gridview/gridview'; export * from './gridview/gridview';
export * from './groupview/groupview'; export * from './dockview/dockviewGroupPanelModel';
export * from './gridview/baseComponentGridview'; export * from './gridview/baseComponentGridview';
export * from './paneview/draggablePaneviewPanel'; export * from './paneview/draggablePaneviewPanel';
export * from './groupview/panel/content'; export * from './dockview/components/panel/content';
export * from './groupview/tab'; export * from './dockview/components/tab/tab';
export * from './groupview/dnd'; export * from './dockview/types';
export * from './groupview/types'; export * from './dockview/dockviewGroupPanel';
export * from './groupview/groupviewPanel';
export * from './dockview/options'; export * from './dockview/options';
export * from './dockview/dockviewPanel'; export * from './dockview/dockviewPanel';
@ -48,9 +47,8 @@ export { PaneviewComponentOptions } from './paneview/options';
export * from './gridview/gridviewPanel'; export * from './gridview/gridviewPanel';
export * from './splitview/splitviewPanel'; export * from './splitview/splitviewPanel';
export * from './paneview/paneviewPanel'; export * from './paneview/paneviewPanel';
export * from './groupview/types'; export * from './dockview/types';
export { Event } from './events';
export { export {
Position, Position,
positionToDirection, positionToDirection,

View File

@ -3,8 +3,8 @@ export interface IDisposable {
} }
export interface IValueDisposable<T> { export interface IValueDisposable<T> {
value: T; readonly value: T;
disposable: IDisposable; readonly disposable: IDisposable;
} }
export namespace Disposable { export namespace Disposable {
@ -26,11 +26,11 @@ export class CompositeDisposable {
this.disposables = args; this.disposables = args;
} }
public addDisposables(...args: IDisposable[]) { public addDisposables(...args: IDisposable[]): void {
args.forEach((arg) => this.disposables.push(arg)); args.forEach((arg) => this.disposables.push(arg));
} }
public dispose() { public dispose(): void {
this.disposables.forEach((arg) => arg.dispose()); this.disposables.forEach((arg) => arg.dispose());
} }
} }
@ -45,7 +45,7 @@ export class MutableDisposable implements IDisposable {
this._disposable = disposable; this._disposable = disposable;
} }
public dispose() { public dispose(): void {
if (this._disposable) { if (this._disposable) {
this._disposable.dispose(); this._disposable.dispose();
this._disposable = Disposable.NONE; this._disposable = Disposable.NONE;

View File

@ -22,7 +22,7 @@ export interface IPanel extends IDisposable {
layout(width: number, height: number): void; layout(width: number, height: number): void;
update(event: PanelUpdateEvent<Parameters>): void; update(event: PanelUpdateEvent<Parameters>): void;
toJSON(): object; toJSON(): object;
focus(): void; focus?(): void;
} }
export interface IFrameworkPart extends IDisposable { export interface IFrameworkPart extends IDisposable {

View File

@ -18,7 +18,7 @@ export class DefaultHeader
private readonly _expander: HTMLElement; private readonly _expander: HTMLElement;
private apiRef: { api: PaneviewPanelApiImpl | null } = { api: null }; private apiRef: { api: PaneviewPanelApiImpl | null } = { api: null };
get element() { get element(): HTMLElement {
return this._element; return this._element;
} }
@ -42,7 +42,7 @@ export class DefaultHeader
); );
} }
init(params: PanePanelInitParameter & { api: PaneviewPanelApiImpl }) { init(params: PanePanelInitParameter & { api: PaneviewPanelApiImpl }): void {
this.apiRef.api = params.api; this.apiRef.api = params.api;
this._content.textContent = params.title; this._content.textContent = params.title;
@ -54,7 +54,7 @@ export class DefaultHeader
}); });
} }
private updateIcon() { private updateIcon(): void {
const isExpanded = !!this.apiRef.api?.isExpanded; const isExpanded = !!this.apiRef.api?.isExpanded;
toggleClass(this._expander, 'collapsed', !isExpanded); toggleClass(this._expander, 'collapsed', !isExpanded);
@ -75,11 +75,11 @@ export class DefaultHeader
} }
} }
update(_params: PanelUpdateEvent) { update(_params: PanelUpdateEvent): void {
// //
} }
dispose() { dispose(): void {
this.disposable.dispose(); this.disposable.dispose();
super.dispose(); super.dispose();
} }

View File

@ -45,7 +45,7 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
} }
} }
private initDragFeatures() { private initDragFeatures(): void {
if (!this.header) { if (!this.header) {
return; return;
} }
@ -110,7 +110,7 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
); );
} }
private onDrop(event: DroptargetEvent) { private onDrop(event: DroptargetEvent): void {
const data = getPaneData(); const data = getPaneData();
if (!data || data.viewId !== this.accessor.id) { if (!data || data.viewId !== this.accessor.id) {

View File

@ -25,30 +25,30 @@ export class Paneview extends CompositeDisposable implements IDisposable {
private readonly _onDidChange = new Emitter<void>(); private readonly _onDidChange = new Emitter<void>();
readonly onDidChange: Event<void> = this._onDidChange.event; readonly onDidChange: Event<void> = this._onDidChange.event;
get onDidAddView() { get onDidAddView(): Event<PaneviewPanel> {
return <Event<PaneviewPanel>>this.splitview.onDidAddView; return <Event<PaneviewPanel>>this.splitview.onDidAddView;
} }
get onDidRemoveView() { get onDidRemoveView(): Event<PaneviewPanel> {
return <Event<PaneviewPanel>>this.splitview.onDidRemoveView; return <Event<PaneviewPanel>>this.splitview.onDidRemoveView;
} }
get minimumSize() { get minimumSize(): number {
return this.splitview.minimumSize; return this.splitview.minimumSize;
} }
get maximumSize() { get maximumSize(): number {
return this.splitview.maximumSize; return this.splitview.maximumSize;
} }
get orientation() { get orientation(): Orientation {
return this.splitview.orientation; return this.splitview.orientation;
} }
get size() { get size(): number {
return this.splitview.size; return this.splitview.size;
} }
get orthogonalSize() { get orthogonalSize(): number {
return this.splitview.orthogonalSize; return this.splitview.orthogonalSize;
} }
@ -113,7 +113,7 @@ export class Paneview extends CompositeDisposable implements IDisposable {
size?: number | Sizing, size?: number | Sizing,
index = this.splitview.length, index = this.splitview.length,
skipLayout = false skipLayout = false
) { ): void {
const disposable = pane.onDidChangeExpansionState(() => { const disposable = pane.onDidChangeExpansionState(() => {
this.setupAnimation(); this.setupAnimation();
this._onDidChange.fire(undefined); this._onDidChange.fire(undefined);
@ -134,7 +134,7 @@ export class Paneview extends CompositeDisposable implements IDisposable {
this.splitview.addView(pane, size, index, skipLayout); this.splitview.addView(pane, size, index, skipLayout);
} }
getViewSize(index: number) { getViewSize(index: number): number {
return this.splitview.getViewSize(index); return this.splitview.getViewSize(index);
} }
@ -145,7 +145,7 @@ export class Paneview extends CompositeDisposable implements IDisposable {
public removePane( public removePane(
index: number, index: number,
options: { skipDispose: boolean } = { skipDispose: false } options: { skipDispose: boolean } = { skipDispose: false }
) { ): PaneItem {
const paneItem = this.paneItems.splice(index, 1)[0]; const paneItem = this.paneItems.splice(index, 1)[0];
this.splitview.removeView(index); this.splitview.removeView(index);
@ -157,7 +157,7 @@ export class Paneview extends CompositeDisposable implements IDisposable {
return paneItem; return paneItem;
} }
public moveView(from: number, to: number) { public moveView(from: number, to: number): void {
if (from === to) { if (from === to) {
return; return;
} }
@ -176,7 +176,7 @@ export class Paneview extends CompositeDisposable implements IDisposable {
this.splitview.layout(size, orthogonalSize); this.splitview.layout(size, orthogonalSize);
} }
private setupAnimation() { private setupAnimation(): void {
if (this.skipAnimation) { if (this.skipAnimation) {
return; return;
} }
@ -194,7 +194,7 @@ export class Paneview extends CompositeDisposable implements IDisposable {
}, 200); }, 200);
} }
public dispose() { public dispose(): void {
super.dispose(); super.dispose();
if (this.animationTimer) { if (this.animationTimer) {

View File

@ -175,25 +175,25 @@ export class PaneviewComponent
); );
} }
get paneview() { get paneview(): Paneview {
return this._paneview; return this._paneview;
} }
get minimumSize() { get minimumSize(): number {
return this.paneview.minimumSize; return this.paneview.minimumSize;
} }
get maximumSize() { get maximumSize(): number {
return this.paneview.maximumSize; return this.paneview.maximumSize;
} }
get height() { get height(): number {
return this.paneview.orientation === Orientation.HORIZONTAL return this.paneview.orientation === Orientation.HORIZONTAL
? this.paneview.orthogonalSize ? this.paneview.orthogonalSize
: this.paneview.size; : this.paneview.size;
} }
get width() { get width(): number {
return this.paneview.orientation === Orientation.HORIZONTAL return this.paneview.orientation === Orientation.HORIZONTAL
? this.paneview.size ? this.paneview.size
: this.paneview.orthogonalSize; : this.paneview.orthogonalSize;
@ -234,8 +234,8 @@ export class PaneviewComponent
this.addDisposables(this._disposable); this.addDisposables(this._disposable);
} }
focus() { focus(): void {
// //noop
} }
updateOptions(options: Partial<PaneviewComponentOptions>): void { updateOptions(options: Partial<PaneviewComponentOptions>): void {
@ -311,7 +311,7 @@ export class PaneviewComponent
return view; return view;
} }
removePanel(panel: PaneviewPanel) { removePanel(panel: PaneviewPanel): void {
const views = this.panels; const views = this.panels;
const index = views.findIndex((_) => _ === panel); const index = views.findIndex((_) => _ === panel);
this.paneview.removePane(index); this.paneview.removePane(index);
@ -462,7 +462,7 @@ export class PaneviewComponent
this.paneview.dispose(); this.paneview.dispose();
} }
private doAddPanel(panel: PaneFramework) { private doAddPanel(panel: PaneFramework): void {
const disposable = panel.onDidDrop((event) => { const disposable = panel.onDidDrop((event) => {
this._onDidDrop.fire(event); this._onDidDrop.fire(event);
}); });
@ -470,7 +470,7 @@ export class PaneviewComponent
this._viewDisposables.set(panel.id, disposable); this._viewDisposables.set(panel.id, disposable);
} }
private doRemovePanel(panel: PaneviewPanel) { private doRemovePanel(panel: PaneviewPanel): void {
const disposable = this._viewDisposables.get(panel.id); const disposable = this._viewDisposables.get(panel.id);
if (disposable) { if (disposable) {

View File

@ -96,7 +96,7 @@ export abstract class PaneviewPanel
this._orientation = value; this._orientation = value;
} }
get orientation() { get orientation(): Orientation {
return this._orientation; return this._orientation;
} }
@ -116,11 +116,11 @@ export abstract class PaneviewPanel
return headerSize + maximumBodySize; return headerSize + maximumBodySize;
} }
get size() { get size(): number {
return this._size; return this._size;
} }
get orthogonalSize() { get orthogonalSize(): number {
return this._orthogonalSize; return this._orthogonalSize;
} }
@ -128,7 +128,7 @@ export abstract class PaneviewPanel
this._orthogonalSize = size; this._orthogonalSize = size;
} }
get minimumBodySize() { get minimumBodySize(): number {
return this._minimumBodySize; return this._minimumBodySize;
} }
@ -136,7 +136,7 @@ export abstract class PaneviewPanel
this._minimumBodySize = typeof value === 'number' ? value : 0; this._minimumBodySize = typeof value === 'number' ? value : 0;
} }
get maximumBodySize() { get maximumBodySize(): number {
return this._maximumBodySize; return this._maximumBodySize;
} }
@ -217,11 +217,11 @@ export abstract class PaneviewPanel
this.renderOnce(); this.renderOnce();
} }
setVisible(isVisible: boolean) { setVisible(isVisible: boolean): void {
this.api._onDidVisibilityChange.fire({ isVisible }); this.api._onDidVisibilityChange.fire({ isVisible });
} }
setActive(isActive: boolean) { setActive(isActive: boolean): void {
this.api._onDidActiveChange.fire({ isActive }); this.api._onDidActiveChange.fire({ isActive });
} }
@ -253,7 +253,7 @@ export abstract class PaneviewPanel
this._onDidChangeExpansionState.fire(expanded); this._onDidChangeExpansionState.fire(expanded);
} }
layout(size: number, orthogonalSize: number) { layout(size: number, orthogonalSize: number): void {
this._size = size; this._size = size;
this._orthogonalSize = orthogonalSize; this._orthogonalSize = orthogonalSize;
const [width, height] = const [width, height] =
@ -299,7 +299,7 @@ export abstract class PaneviewPanel
}; };
} }
private renderOnce() { private renderOnce(): void {
this.header = document.createElement('div'); this.header = document.createElement('div');
this.header.tabIndex = 0; this.header.tabIndex = 0;

View File

@ -105,6 +105,8 @@ export class Splitview {
private contentSize = 0; private contentSize = 0;
private _proportions: number[] | undefined = undefined; private _proportions: number[] | undefined = undefined;
private proportionalLayout: boolean; private proportionalLayout: boolean;
private _startSnappingEnabled = true;
private _endSnappingEnabled = true;
private readonly _onDidSashEnd = new Emitter<void>(); private readonly _onDidSashEnd = new Emitter<void>();
readonly onDidSashEnd = this._onDidSashEnd.event; readonly onDidSashEnd = this._onDidSashEnd.event;
@ -113,7 +115,7 @@ export class Splitview {
private readonly _onDidRemoveView = new Emitter<IView>(); private readonly _onDidRemoveView = new Emitter<IView>();
readonly onDidRemoveView = this._onDidRemoveView.event; readonly onDidRemoveView = this._onDidRemoveView.event;
get size() { get size(): number {
return this._size; return this._size;
} }
@ -121,7 +123,7 @@ export class Splitview {
this._size = value; this._size = value;
} }
get orthogonalSize() { get orthogonalSize(): number {
return this._orthogonalSize; return this._orthogonalSize;
} }
@ -129,15 +131,15 @@ export class Splitview {
this._orthogonalSize = value; this._orthogonalSize = value;
} }
public get length() { public get length(): number {
return this.views.length; return this.views.length;
} }
public get proportions() { public get proportions(): number[] | undefined {
return this._proportions ? [...this._proportions] : undefined; return this._proportions ? [...this._proportions] : undefined;
} }
get orientation() { get orientation(): Orientation {
return this._orientation; return this._orientation;
} }
@ -166,10 +168,10 @@ export class Splitview {
: this.views.reduce((r, item) => r + item.maximumSize, 0); : this.views.reduce((r, item) => r + item.maximumSize, 0);
} }
private _startSnappingEnabled = true;
get startSnappingEnabled(): boolean { get startSnappingEnabled(): boolean {
return this._startSnappingEnabled; return this._startSnappingEnabled;
} }
set startSnappingEnabled(startSnappingEnabled: boolean) { set startSnappingEnabled(startSnappingEnabled: boolean) {
if (this._startSnappingEnabled === startSnappingEnabled) { if (this._startSnappingEnabled === startSnappingEnabled) {
return; return;
@ -179,10 +181,10 @@ export class Splitview {
this.updateSashEnablement(); this.updateSashEnablement();
} }
private _endSnappingEnabled = true;
get endSnappingEnabled(): boolean { get endSnappingEnabled(): boolean {
return this._endSnappingEnabled; return this._endSnappingEnabled;
} }
set endSnappingEnabled(endSnappingEnabled: boolean) { set endSnappingEnabled(endSnappingEnabled: boolean) {
if (this._endSnappingEnabled === endSnappingEnabled) { if (this._endSnappingEnabled === endSnappingEnabled) {
return; return;
@ -321,7 +323,7 @@ export class Splitview {
this.relayout(lowPriorityIndexes, highPriorityIndexes); this.relayout(lowPriorityIndexes, highPriorityIndexes);
} }
public getViews<T extends IView>() { public getViews<T extends IView>(): T[] {
return this.views.map((x) => x.view as T); return this.views.map((x) => x.view as T);
} }
@ -345,7 +347,7 @@ export class Splitview {
size: number | Sizing = { type: 'distribute' }, size: number | Sizing = { type: 'distribute' },
index: number = this.views.length, index: number = this.views.length,
skipLayout?: boolean skipLayout?: boolean
) { ): void {
const container = document.createElement('div'); const container = document.createElement('div');
container.className = 'view'; container.className = 'view';
@ -622,7 +624,7 @@ export class Splitview {
return viewItem.cachedVisibleSize; return viewItem.cachedVisibleSize;
} }
public moveView(from: number, to: number) { public moveView(from: number, to: number): void {
const cachedVisibleSize = this.getViewCachedVisibleSize(from); const cachedVisibleSize = this.getViewCachedVisibleSize(from);
const sizing = const sizing =
typeof cachedVisibleSize === 'undefined' typeof cachedVisibleSize === 'undefined'
@ -632,7 +634,7 @@ export class Splitview {
this.addView(view, sizing, to); this.addView(view, sizing, to);
} }
public layout(size: number, orthogonalSize: number) { public layout(size: number, orthogonalSize: number): void {
const previousSize = Math.max(this.size, this.contentSize); const previousSize = Math.max(this.size, this.contentSize);
this.size = size; this.size = size;
this.orthogonalSize = orthogonalSize; this.orthogonalSize = orthogonalSize;
@ -672,7 +674,7 @@ export class Splitview {
private relayout( private relayout(
lowPriorityIndexes?: number[], lowPriorityIndexes?: number[],
highPriorityIndexes?: number[] highPriorityIndexes?: number[]
) { ): void {
const contentSize = this.views.reduce((r, i) => r + i.size, 0); const contentSize = this.views.reduce((r, i) => r + i.size, 0);
this.resize( this.resize(
@ -687,7 +689,7 @@ export class Splitview {
this.saveProportions(); this.saveProportions();
} }
private distributeEmptySpace(lowPriorityIndex?: number) { private distributeEmptySpace(lowPriorityIndex?: number): void {
const contentSize = this.views.reduce((r, i) => r + i.size, 0); const contentSize = this.views.reduce((r, i) => r + i.size, 0);
let emptyDelta = this.size - contentSize; let emptyDelta = this.size - contentSize;
@ -733,7 +735,7 @@ export class Splitview {
} }
} }
private layoutViews() { private layoutViews(): void {
this.contentSize = this.views.reduce((r, i) => r + i.size, 0); this.contentSize = this.views.reduce((r, i) => r + i.size, 0);
let sum = 0; let sum = 0;
const x: number[] = []; const x: number[] = [];
@ -875,7 +877,7 @@ export class Splitview {
} }
} }
private updateSash(sash: ISashItem, state: SashState) { private updateSash(sash: ISashItem, state: SashState): void {
toggleClass(sash.container, 'disabled', state === SashState.DISABLED); toggleClass(sash.container, 'disabled', state === SashState.DISABLED);
toggleClass(sash.container, 'enabled', state === SashState.ENABLED); toggleClass(sash.container, 'enabled', state === SashState.ENABLED);
toggleClass(sash.container, 'maximum', state === SashState.MAXIMUM); toggleClass(sash.container, 'maximum', state === SashState.MAXIMUM);
@ -1011,19 +1013,19 @@ export class Splitview {
return delta; return delta;
}; };
private createViewContainer() { private createViewContainer(): HTMLElement {
const element = document.createElement('div'); const element = document.createElement('div');
element.className = 'view-container'; element.className = 'view-container';
return element; return element;
} }
private createSashContainer() { private createSashContainer(): HTMLElement {
const element = document.createElement('div'); const element = document.createElement('div');
element.className = 'sash-container'; element.className = 'sash-container';
return element; return element;
} }
private createContainer() { private createContainer(): HTMLElement {
const element = document.createElement('div'); const element = document.createElement('div');
const orientationClassname = const orientationClassname =
this._orientation === Orientation.HORIZONTAL this._orientation === Orientation.HORIZONTAL
@ -1033,7 +1035,7 @@ export class Splitview {
return element; return element;
} }
public dispose() { public dispose(): void {
this._onDidSashEnd.dispose(); this._onDidSashEnd.dispose();
this._onDidAddView.dispose(); this._onDidAddView.dispose();
this._onDidRemoveView.dispose(); this._onDidRemoveView.dispose();

View File

@ -4,6 +4,8 @@ import { IView, LayoutPriority } from './splitview';
export class ViewItem { export class ViewItem {
private _size: number; private _size: number;
private _cachedVisibleSize: number | undefined = undefined;
set size(size: number) { set size(size: number) {
this._size = size; this._size = size;
} }
@ -12,7 +14,6 @@ export class ViewItem {
return this._size; return this._size;
} }
private _cachedVisibleSize: number | undefined = undefined;
get cachedVisibleSize(): number | undefined { get cachedVisibleSize(): number | undefined {
return this._cachedVisibleSize; return this._cachedVisibleSize;
} }
@ -21,31 +22,6 @@ export class ViewItem {
return typeof this._cachedVisibleSize === 'undefined'; return typeof this._cachedVisibleSize === 'undefined';
} }
setVisible(visible: boolean, size?: number): void {
if (visible === this.visible) {
return;
}
if (visible) {
this.size = clamp(
this._cachedVisibleSize ?? 0,
this.viewMinimumSize,
this.viewMaximumSize
);
this._cachedVisibleSize = undefined;
} else {
this._cachedVisibleSize =
typeof size === 'number' ? size : this.size;
this.size = 0;
}
this.container.classList.toggle('visible', visible);
if (this.view.setVisible) {
this.view.setVisible(visible);
}
}
get minimumSize(): number { get minimumSize(): number {
return this.visible ? this.view.minimumSize : 0; return this.visible ? this.view.minimumSize : 0;
} }
@ -87,12 +63,30 @@ export class ViewItem {
} }
} }
// layout(offset: number, layoutContext: TLayoutContext | undefined): void { setVisible(visible: boolean, size?: number): void {
// this.layoutContainer(offset); if (visible === this.visible) {
// this.view.layout(this.size, offset, layoutContext); return;
// } }
// abstract layoutContainer(offset: number): void; if (visible) {
this.size = clamp(
this._cachedVisibleSize ?? 0,
this.viewMinimumSize,
this.viewMaximumSize
);
this._cachedVisibleSize = undefined;
} else {
this._cachedVisibleSize =
typeof size === 'number' ? size : this.size;
this.size = 0;
}
this.container.classList.toggle('visible', visible);
if (this.view.setVisible) {
this.view.setVisible(visible);
}
}
dispose(): IView { dispose(): IView {
this.disposable.dispose(); this.disposable.dispose();

View File

@ -1,13 +1,11 @@
export interface Constructor<T> {
new (): T;
}
export interface FrameworkFactory<T> { export interface FrameworkFactory<T> {
createComponent: (id: string, componentId: string, component: any) => T; createComponent: (id: string, componentId: string, component: any) => T;
} }
export type FunctionOrValue<T> = (() => T) | T;
export function isBooleanValue(value: any): value is boolean { export function isBooleanValue(value: any): value is boolean {
return typeof value === 'boolean'; return typeof value === 'boolean';
} }
export type FunctionOrValue<T> = (() => T) | T;
export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

View File

@ -1,26 +1,32 @@
import { GroupPanel, GroupviewPanelApi, Groupview } from 'dockview-core'; import {
DockviewGroupPanel,
DockviewGroupPanelApi,
DockviewGroupPanelModel,
} from 'dockview-core';
import { ReactGroupControlsRendererPart } from '../../../dockview/groupControlsRenderer'; import { ReactGroupControlsRendererPart } from '../../../dockview/groupControlsRenderer';
describe('groupControlsRenderer', () => { describe('groupControlsRenderer', () => {
test('#1', () => { test('#1', () => {
const groupviewMock = jest.fn<Partial<Groupview>, []>(() => { const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => {
return { return {
onDidAddPanel: jest.fn(), onDidAddPanel: jest.fn(),
onDidRemovePanel: jest.fn(), onDidRemovePanel: jest.fn(),
onDidActivePanelChange: jest.fn(), onDidActivePanelChange: jest.fn(),
}; };
}); }
);
const groupview = new groupviewMock() as Groupview; const groupview = new groupviewMock() as DockviewGroupPanelModel;
const groupPanelMock = jest.fn<Partial<GroupPanel>, []>(() => { const groupPanelMock = jest.fn<Partial<DockviewGroupPanel>, []>(() => {
return { return {
api: {} as GroupviewPanelApi as any, api: {} as DockviewGroupPanelApi as any,
model: groupview, model: groupview,
}; };
}); });
const groupPanel = new groupPanelMock() as GroupPanel; const groupPanel = new groupPanelMock() as DockviewGroupPanel;
const cut = new ReactGroupControlsRendererPart( const cut = new ReactGroupControlsRendererPart(
jest.fn(), jest.fn(),

View File

@ -1,24 +0,0 @@
import { DEFAULT_TAB_IDENTIFIER } from 'dockview-core';
import { ReactPanelHeaderPart } from '../../../dockview/reactHeaderPart';
describe('reactHeaderPart', () => {
test('that tab id is present in toJSON when not the default tab', () => {
const cut = new ReactPanelHeaderPart(
'test-id',
jest.fn(),
<any>jest.fn()
);
expect(cut.toJSON()).toEqual({ id: 'test-id' });
});
test('that tab id is not present in the toJSON when is default tab', () => {
const cut = new ReactPanelHeaderPart(
DEFAULT_TAB_IDENTIFIER,
jest.fn(),
<any>jest.fn()
);
expect(cut.toJSON()).toEqual({});
});
});

View File

@ -10,8 +10,7 @@ import {
IContentRenderer, IContentRenderer,
ITabRenderer, ITabRenderer,
watchElementResize, watchElementResize,
GroupPanel, DockviewGroupPanel,
DEFAULT_TAB_IDENTIFIER,
DefaultDockviewDeserialzier, DefaultDockviewDeserialzier,
} from 'dockview-core'; } from 'dockview-core';
import { ReactPanelContentPart } from './reactContentPart'; import { ReactPanelContentPart } from './reactContentPart';
@ -28,9 +27,9 @@ import {
function createGroupControlElement( function createGroupControlElement(
component: React.FunctionComponent<IDockviewGroupControlProps> | undefined, component: React.FunctionComponent<IDockviewGroupControlProps> | undefined,
store: ReactPortalStore store: ReactPortalStore
): ((groupPanel: GroupPanel) => IGroupControlRenderer) | undefined { ): ((groupPanel: DockviewGroupPanel) => IGroupControlRenderer) | undefined {
return component return component
? (groupPanel: GroupPanel) => { ? (groupPanel: DockviewGroupPanel) => {
return new ReactGroupControlsRendererPart( return new ReactGroupControlsRendererPart(
component, component,
store, store,
@ -72,6 +71,8 @@ export interface IDockviewReactProps {
singleTabMode?: 'fullwidth' | 'default'; singleTabMode?: 'fullwidth' | 'default';
} }
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
export const DockviewReact = React.forwardRef( export const DockviewReact = React.forwardRef(
(props: IDockviewReactProps, ref: React.ForwardedRef<HTMLDivElement>) => { (props: IDockviewReactProps, ref: React.ForwardedRef<HTMLDivElement>) => {
const domRef = React.useRef<HTMLDivElement>(null); const domRef = React.useRef<HTMLDivElement>(null);
@ -144,16 +145,22 @@ export const DockviewReact = React.forwardRef(
const element = document.createElement('div'); const element = document.createElement('div');
const frameworkTabComponents = props.tabComponents || {};
if (props.defaultTabComponent) {
frameworkTabComponents[DEFAULT_REACT_TAB] =
props.defaultTabComponent;
}
const dockview = new DockviewComponent(element, { const dockview = new DockviewComponent(element, {
frameworkComponentFactory: factory, frameworkComponentFactory: factory,
frameworkComponents: props.components, frameworkComponents: props.components,
frameworkTabComponents: { frameworkTabComponents,
...(props.tabComponents || {}),
[DEFAULT_TAB_IDENTIFIER]: props.defaultTabComponent,
},
tabHeight: props.tabHeight, tabHeight: props.tabHeight,
watermarkFrameworkComponent: props.watermarkComponent, watermarkFrameworkComponent: props.watermarkComponent,
defaultTabComponent: DEFAULT_TAB_IDENTIFIER, defaultTabComponent: props.defaultTabComponent
? DEFAULT_REACT_TAB
: undefined,
styles: props.hideBorders styles: props.hideBorders
? { separatorBorder: 'transparent' } ? { separatorBorder: 'transparent' }
: undefined, : undefined,
@ -241,12 +248,19 @@ export const DockviewReact = React.forwardRef(
if (!dockviewRef.current) { if (!dockviewRef.current) {
return; return;
} }
const frameworkTabComponents = props.tabComponents || {};
if (props.defaultTabComponent) {
frameworkTabComponents[DEFAULT_REACT_TAB] =
props.defaultTabComponent;
}
dockviewRef.current.updateOptions({ dockviewRef.current.updateOptions({
defaultTabComponent: DEFAULT_TAB_IDENTIFIER, defaultTabComponent: props.defaultTabComponent
frameworkTabComponents: { ? DEFAULT_REACT_TAB
...(props.tabComponents || {}), : undefined,
[DEFAULT_TAB_IDENTIFIER]: props.defaultTabComponent, frameworkTabComponents,
},
}); });
}, [props.defaultTabComponent]); }, [props.defaultTabComponent]);

View File

@ -5,13 +5,13 @@ import {
DockviewCompositeDisposable, DockviewCompositeDisposable,
DockviewMutableDisposable, DockviewMutableDisposable,
DockviewApi, DockviewApi,
GroupPanel, DockviewGroupPanel,
GroupviewPanelApi, DockviewGroupPanelApi,
PanelUpdateEvent, PanelUpdateEvent,
} from 'dockview-core'; } from 'dockview-core';
export interface IDockviewGroupControlProps { export interface IDockviewGroupControlProps {
api: GroupviewPanelApi; api: DockviewGroupPanelApi;
containerApi: DockviewApi; containerApi: DockviewApi;
panels: IDockviewPanel[]; panels: IDockviewPanel[];
activePanel: IDockviewPanel | undefined; activePanel: IDockviewPanel | undefined;
@ -31,26 +31,26 @@ export class ReactGroupControlsRendererPart {
return this._part; return this._part;
} }
get group(): GroupPanel { get group(): DockviewGroupPanel {
return this._group; return this._group;
} }
constructor( constructor(
private readonly component: React.FunctionComponent<IDockviewGroupControlProps>, private readonly component: React.FunctionComponent<IDockviewGroupControlProps>,
private readonly reactPortalStore: ReactPortalStore, private readonly reactPortalStore: ReactPortalStore,
private readonly _group: GroupPanel private readonly _group: DockviewGroupPanel
) { ) {
this._element = document.createElement('div'); this._element = document.createElement('div');
this._element.className = 'dockview-react-part'; this._element.className = 'dockview-react-part';
} }
focus() { focus(): void {
// TODO // TODO
} }
public init(parameters: { public init(parameters: {
containerApi: DockviewApi; containerApi: DockviewApi;
api: GroupviewPanelApi; api: DockviewGroupPanelApi;
}): void { }): void {
this.mutableDisposable.value = new DockviewCompositeDisposable( this.mutableDisposable.value = new DockviewCompositeDisposable(
this._group.model.onDidAddPanel(() => { this._group.model.onDidAddPanel(() => {
@ -81,20 +81,20 @@ export class ReactGroupControlsRendererPart {
); );
} }
public update(event: PanelUpdateEvent) { public update(event: PanelUpdateEvent): void {
this._part?.update(event.params); this._part?.update(event.params);
} }
public dispose() { public dispose(): void {
this.mutableDisposable.dispose(); this.mutableDisposable.dispose();
this._part?.dispose(); this._part?.dispose();
} }
private updatePanels() { private updatePanels(): void {
this.update({ params: { panels: this._group.model.panels } }); this.update({ params: { panels: this._group.model.panels } });
} }
private updateActivePanel() { private updateActivePanel(): void {
this.update({ this.update({
params: { params: {
activePanel: this._group.model.activePanel, activePanel: this._group.model.activePanel,
@ -102,7 +102,7 @@ export class ReactGroupControlsRendererPart {
}); });
} }
private updateGroupActive() { private updateGroupActive(): void {
this.update({ this.update({
params: { params: {
isGroupActive: this._group.api.isActive, isGroupActive: this._group.api.isActive,

View File

@ -3,8 +3,8 @@ import { ReactPart, ReactPortalStore } from '../react';
import { IDockviewPanelProps } from '../dockview/dockview'; import { IDockviewPanelProps } from '../dockview/dockview';
import { import {
DockviewEmitter, DockviewEmitter,
Event, DockviewEvent,
GroupPanel, DockviewGroupPanel,
PanelUpdateEvent, PanelUpdateEvent,
IContentRenderer, IContentRenderer,
GroupPanelContentPartInitParameters, GroupPanelContentPartInitParameters,
@ -14,13 +14,13 @@ export class ReactPanelContentPart implements IContentRenderer {
private _element: HTMLElement; private _element: HTMLElement;
private part?: ReactPart<IDockviewPanelProps>; private part?: ReactPart<IDockviewPanelProps>;
// //
private _group: GroupPanel | undefined; private _group: DockviewGroupPanel | undefined;
private readonly _onDidFocus = new DockviewEmitter<void>(); private readonly _onDidFocus = new DockviewEmitter<void>();
readonly onDidFocus: Event<void> = this._onDidFocus.event; readonly onDidFocus: DockviewEvent<void> = this._onDidFocus.event;
private readonly _onDidBlur = new DockviewEmitter<void>(); private readonly _onDidBlur = new DockviewEmitter<void>();
readonly onDidBlur: Event<void> = this._onDidBlur.event; readonly onDidBlur: DockviewEvent<void> = this._onDidBlur.event;
get element(): HTMLElement { get element(): HTMLElement {
return this._element; return this._element;
@ -35,7 +35,7 @@ export class ReactPanelContentPart implements IContentRenderer {
this._element.className = 'dockview-react-part'; this._element.className = 'dockview-react-part';
} }
focus() { focus(): void {
// TODO // TODO
} }
@ -52,18 +52,12 @@ export class ReactPanelContentPart implements IContentRenderer {
); );
} }
public toJSON() {
return {
id: this.id,
};
}
public update(event: PanelUpdateEvent) { public update(event: PanelUpdateEvent) {
this.part?.update(event.params); this.part?.update(event.params);
} }
public updateParentGroup( public updateParentGroup(
group: GroupPanel, group: DockviewGroupPanel,
_isPanelVisible: boolean _isPanelVisible: boolean
): void { ): void {
this._group = group; this._group = group;
@ -73,7 +67,7 @@ export class ReactPanelContentPart implements IContentRenderer {
// noop // noop
} }
public dispose() { public dispose(): void {
this._onDidFocus.dispose(); this._onDidFocus.dispose();
this._onDidBlur.dispose(); this._onDidBlur.dispose();
this.part?.dispose(); this.part?.dispose();

View File

@ -2,9 +2,8 @@ import * as React from 'react';
import { ReactPart, ReactPortalStore } from '../react'; import { ReactPart, ReactPortalStore } from '../react';
import { IGroupPanelBaseProps } from './dockview'; import { IGroupPanelBaseProps } from './dockview';
import { import {
DEFAULT_TAB_IDENTIFIER,
PanelUpdateEvent, PanelUpdateEvent,
GroupPanel, DockviewGroupPanel,
ITabRenderer, ITabRenderer,
GroupPanelPartInitParameters, GroupPanelPartInitParameters,
} from 'dockview-core'; } from 'dockview-core';
@ -13,7 +12,7 @@ export class ReactPanelHeaderPart implements ITabRenderer {
private _element: HTMLElement; private _element: HTMLElement;
private part?: ReactPart<IGroupPanelBaseProps>; private part?: ReactPart<IGroupPanelBaseProps>;
get element() { get element(): HTMLElement {
return this._element; return this._element;
} }
@ -26,7 +25,7 @@ export class ReactPanelHeaderPart implements ITabRenderer {
this._element.className = 'dockview-react-part'; this._element.className = 'dockview-react-part';
} }
focus() { focus(): void {
//noop //noop
} }
@ -43,32 +42,22 @@ export class ReactPanelHeaderPart implements ITabRenderer {
); );
} }
public update(event: PanelUpdateEvent) { public update(event: PanelUpdateEvent): void {
this.part?.update(event.params); this.part?.update(event.params);
} }
public toJSON() { public layout(_width: number, _height: number): void {
if (this.id === DEFAULT_TAB_IDENTIFIER) {
return {};
}
return {
id: this.id,
};
}
public layout(_width: number, _height: number) {
// noop - retrieval from api // noop - retrieval from api
} }
public updateParentGroup( public updateParentGroup(
_group: GroupPanel, _group: DockviewGroupPanel,
_isPanelVisible: boolean _isPanelVisible: boolean
): void { ): void {
// noop - retrieval from api // noop - retrieval from api
} }
public dispose() { public dispose(): void {
this.part?.dispose(); this.part?.dispose();
} }
} }

View File

@ -3,7 +3,7 @@ import { ReactPart, ReactPortalStore } from '../react';
import { IGroupPanelBaseProps } from './dockview'; import { IGroupPanelBaseProps } from './dockview';
import { import {
PanelUpdateEvent, PanelUpdateEvent,
GroupPanel, DockviewGroupPanel,
GroupPanelPartInitParameters, GroupPanelPartInitParameters,
IWatermarkRenderer, IWatermarkRenderer,
} from 'dockview-core'; } from 'dockview-core';
@ -15,12 +15,12 @@ export interface IWatermarkPanelProps extends IGroupPanelBaseProps {
export class ReactWatermarkPart implements IWatermarkRenderer { export class ReactWatermarkPart implements IWatermarkRenderer {
private _element: HTMLElement; private _element: HTMLElement;
private part?: ReactPart<IWatermarkPanelProps>; private part?: ReactPart<IWatermarkPanelProps>;
private _groupRef: { value: GroupPanel | undefined } = { private _groupRef: { value: DockviewGroupPanel | undefined } = {
value: undefined, value: undefined,
}; };
private parameters: GroupPanelPartInitParameters | undefined; private parameters: GroupPanelPartInitParameters | undefined;
get element() { get element(): HTMLElement {
return this._element; return this._element;
} }
@ -55,11 +55,11 @@ export class ReactWatermarkPart implements IWatermarkRenderer {
); );
} }
focus() { focus(): void {
// noop // noop
} }
update(params: PanelUpdateEvent) { update(params: PanelUpdateEvent): void {
if (this.parameters) { if (this.parameters) {
this.parameters.params = params.params; this.parameters.params = params.params;
} }
@ -67,22 +67,19 @@ export class ReactWatermarkPart implements IWatermarkRenderer {
this.part?.update({ params: this.parameters?.params || {} }); this.part?.update({ params: this.parameters?.params || {} });
} }
toJSON() { layout(_width: number, _height: number): void {
return {
id: this.id,
};
}
layout(_width: number, _height: number) {
// noop - retrieval from api // noop - retrieval from api
} }
updateParentGroup(group: GroupPanel, _isPanelVisible: boolean): void { updateParentGroup(
group: DockviewGroupPanel,
_isPanelVisible: boolean
): void {
// noop - retrieval from api // noop - retrieval from api
this._groupRef.value = group; this._groupRef.value = group;
} }
dispose() { dispose(): void {
this.part?.dispose(); this.part?.dispose();
} }
} }

View File

@ -1,9 +1,10 @@
import { import {
GroupPanelPartInitParameters, GroupPanelPartInitParameters,
IContentRenderer, IContentRenderer,
GroupPanel, DockviewGroupPanel,
HostedContainer, HostedContainer,
PanelUpdateEvent, PanelUpdateEvent,
DockviewEvent,
} from 'dockview-core'; } from 'dockview-core';
import { ReactPart, ReactPortalStore } from '../../react'; import { ReactPart, ReactPortalStore } from '../../react';
import { IDockviewPanelProps } from '../dockview'; import { IDockviewPanelProps } from '../dockview';
@ -13,7 +14,7 @@ export class ReactContentRenderer implements IContentRenderer {
private _element: HTMLElement; private _element: HTMLElement;
private part?: ReactPart<IDockviewPanelProps>; private part?: ReactPart<IDockviewPanelProps>;
private _group: GroupPanel | undefined; private _group: DockviewGroupPanel | undefined;
private parameters: GroupPanelPartInitParameters | undefined; private parameters: GroupPanelPartInitParameters | undefined;
@ -21,11 +22,11 @@ export class ReactContentRenderer implements IContentRenderer {
return this._element; return this._element;
} }
get onDidBlur() { get onDidBlur(): DockviewEvent<void> {
return this._hostedContainer.onDidBlur; return this._hostedContainer.onDidBlur;
} }
get onDidFocus() { get onDidFocus(): DockviewEvent<void> {
return this._hostedContainer.onDidFocus; return this._hostedContainer.onDidFocus;
} }
@ -46,7 +47,7 @@ export class ReactContentRenderer implements IContentRenderer {
this._element.style.width = '100%'; this._element.style.width = '100%';
} }
focus() { focus(): void {
// noop // noop
} }
@ -74,13 +75,7 @@ export class ReactContentRenderer implements IContentRenderer {
); );
} }
public toJSON() { public update(params: PanelUpdateEvent): void {
return {
id: this.id,
};
}
public update(params: PanelUpdateEvent) {
if (this.parameters) { if (this.parameters) {
this.parameters.params = params.params; this.parameters.params = params.params;
} }
@ -89,7 +84,7 @@ export class ReactContentRenderer implements IContentRenderer {
} }
public updateParentGroup( public updateParentGroup(
group: GroupPanel, group: DockviewGroupPanel,
_isPanelVisible: boolean _isPanelVisible: boolean
): void { ): void {
this._group = group; this._group = group;
@ -99,7 +94,7 @@ export class ReactContentRenderer implements IContentRenderer {
this._hostedContainer.layout(this.element); this._hostedContainer.layout(this.element);
} }
public dispose() { public dispose(): void {
this.part?.dispose(); this.part?.dispose();
} }
} }

View File

@ -1,7 +1,7 @@
import { import {
GroupPanelPartInitParameters, GroupPanelPartInitParameters,
IContentRenderer, IContentRenderer,
GroupPanel, DockviewGroupPanel,
HostedContainer, HostedContainer,
PanelUpdateEvent, PanelUpdateEvent,
} from 'dockview-core'; } from 'dockview-core';
@ -24,7 +24,7 @@ export class WebviewContentRenderer implements IContentRenderer {
this._element.style.width = '100%'; this._element.style.width = '100%';
} }
focus() { focus(): void {
// noop // noop
} }
@ -32,18 +32,14 @@ export class WebviewContentRenderer implements IContentRenderer {
this.parameters = parameters; this.parameters = parameters;
} }
public toJSON() { public update(params: PanelUpdateEvent): void {
return {};
}
public update(params: PanelUpdateEvent) {
if (this.parameters) { if (this.parameters) {
this.parameters.params = params.params; this.parameters.params = params.params;
} }
} }
public updateParentGroup( public updateParentGroup(
_group: GroupPanel, _group: DockviewGroupPanel,
_isPanelVisible: boolean _isPanelVisible: boolean
): void { ): void {
// //
@ -53,7 +49,7 @@ export class WebviewContentRenderer implements IContentRenderer {
this._hostedContainer.layout(this._element); this._hostedContainer.layout(this._element);
} }
public dispose() { public dispose(): void {
// //
} }
} }