feat: migrate to generic construction

This commit is contained in:
mathuo 2024-12-23 16:38:56 +00:00
parent f6e7e4e390
commit fade057412
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
23 changed files with 922 additions and 644 deletions

View File

@ -36,7 +36,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
className: 'test-a test-b',
});
@ -51,7 +58,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -70,7 +84,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -100,7 +121,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -160,7 +188,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -287,7 +322,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(1000, 1000);
@ -323,7 +365,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -446,7 +495,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -475,7 +531,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -533,7 +596,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -591,7 +661,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -667,7 +744,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -761,7 +845,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -855,7 +946,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -949,7 +1047,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -1073,7 +1178,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -1197,7 +1309,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -1323,7 +1442,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -1447,7 +1573,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(800, 400);
@ -1571,7 +1704,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.fromJSON({
@ -1698,7 +1838,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(1000, 1000);
@ -1728,7 +1875,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(1000, 1000);
@ -1757,7 +1911,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(1000, 1000);
@ -1795,7 +1956,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
let addGroup: GridviewPanel[] = [];
@ -1917,7 +2085,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(1600, 800);
@ -2043,7 +2218,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(6000, 5000);
@ -2318,7 +2500,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.VERTICAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
gridview.layout(5000, 6000);
@ -2591,7 +2780,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error(`unsupported panel '${options.name}'`);
}
},
});
let el = gridview.element.querySelector('.dv-view-container');
@ -2655,9 +2851,7 @@ describe('gridview', () => {
},
activePanel: 'panel_1',
});
}).toThrow(
"Cannot create 'panel_1', no component 'somethingBad' provided"
);
}).toThrow("unsupported panel 'somethingBad'");
expect(gridview.groups.length).toBe(0);
@ -2670,7 +2864,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
expect(gridview.disableResizing).toBeFalsy();
@ -2680,7 +2881,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
disableAutoResizing: true,
});
@ -2691,7 +2899,14 @@ describe('gridview', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
components: { default: TestGridview },
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
disableAutoResizing: true,
});
gridview.layout(1000, 1000);

View File

@ -1,102 +0,0 @@
import { createComponent } from '../../panel/componentFactory';
describe('componentFactory', () => {
describe('createComponent', () => {
test('valid component and framework component', () => {
const mock = jest.fn();
const mock2 = jest.fn();
expect(() =>
createComponent(
'id-1',
'component-1',
{ 'component-1': mock },
{ 'component-1': mock2 }
)
).toThrow(
"Cannot create 'id-1'. component 'component-1' registered as both a component and frameworkComponent"
);
});
test('valid framework component but no factory', () => {
const mock = jest.fn();
expect(() =>
createComponent(
'id-1',
'component-1',
{},
{ 'component-1': mock }
)
).toThrow(
"Cannot create 'id-1' for framework component 'component-1'. you must register a frameworkPanelWrapper to use framework components"
);
});
test('valid framework component', () => {
const component = jest.fn();
const createComponentFn = jest
.fn()
.mockImplementation(() => component);
const frameworkComponent = jest.fn();
expect(
createComponent(
'id-1',
'component-1',
{},
{ 'component-1': frameworkComponent },
{
createComponent: createComponentFn,
}
)
).toBe(component);
expect(createComponentFn).toHaveBeenCalledWith(
'id-1',
'component-1',
frameworkComponent
);
});
test('no valid component with fallback', () => {
const mock = jest.fn();
expect(
createComponent(
'id-1',
'component-1',
{},
{},
{
createComponent: () => null,
},
() => mock
)
).toBe(mock);
});
test('no valid component', () => {
expect(() =>
createComponent('id-1', 'component-1', {}, {})
).toThrow(
"Cannot create 'id-1', no component 'component-1' provided"
);
});
test('valid component', () => {
const component = jest.fn();
const componentResult = createComponent(
'id-1',
'component-1',
{ 'component-1': component },
{}
);
expect(component).toHaveBeenCalled();
expect(componentResult instanceof component).toBeTruthy();
});
});
});

View File

@ -1,14 +1,10 @@
import { CompositeDisposable } from '../../lifecycle';
import { Paneview } from '../../paneview/paneview';
import {
IPaneBodyPart,
IPaneHeaderPart,
PaneviewPanel,
} from '../../paneview/paneviewPanel';
import { IPanePart, PaneviewPanel } from '../../paneview/paneviewPanel';
import { Orientation } from '../../splitview/splitview';
class TestPanel extends PaneviewPanel {
protected getBodyComponent(): IPaneBodyPart {
protected getBodyComponent(): IPanePart {
return {
element: document.createElement('div'),
update: () => {
@ -23,7 +19,7 @@ class TestPanel extends PaneviewPanel {
};
}
protected getHeaderComponent(): IPaneHeaderPart {
protected getHeaderComponent(): IPanePart {
return {
element: document.createElement('div'),
update: () => {

View File

@ -4,8 +4,7 @@ import { PanelUpdateEvent } from '../../panel/types';
import { PaneviewComponent } from '../../paneview/paneviewComponent';
import {
PaneviewPanel,
IPaneBodyPart,
IPaneHeaderPart,
IPanePart,
PanePanelComponentInitParameter,
} from '../../paneview/paneviewPanel';
import { Orientation } from '../../splitview/splitview';
@ -16,7 +15,7 @@ class TestPanel extends PaneviewPanel {
}
getHeaderComponent() {
return new (class Header implements IPaneHeaderPart {
return new (class Header implements IPanePart {
private _element: HTMLElement = document.createElement('div');
get element() {
@ -38,7 +37,7 @@ class TestPanel extends PaneviewPanel {
}
getBodyComponent() {
return new (class Header implements IPaneBodyPart {
return new (class Header implements IPanePart {
private _element: HTMLElement = document.createElement('div');
get element() {
@ -72,8 +71,13 @@ describe('componentPaneview', () => {
const disposables = new CompositeDisposable();
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -81,12 +85,12 @@ describe('componentPaneview', () => {
paneview.addPanel({
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
});
paneview.addPanel({
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel2',
});
@ -144,8 +148,13 @@ describe('componentPaneview', () => {
test('serialization', () => {
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -156,7 +165,7 @@ describe('componentPaneview', () => {
size: 1,
data: {
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
},
expanded: true,
@ -165,7 +174,7 @@ describe('componentPaneview', () => {
size: 2,
data: {
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel 2',
},
expanded: false,
@ -174,7 +183,7 @@ describe('componentPaneview', () => {
size: 3,
data: {
id: 'panel3',
component: 'testPanel',
component: 'default',
title: 'Panel 3',
},
},
@ -220,7 +229,7 @@ describe('componentPaneview', () => {
size: 756,
data: {
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
},
expanded: true,
@ -230,7 +239,7 @@ describe('componentPaneview', () => {
size: 22,
data: {
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel 2',
},
expanded: false,
@ -240,7 +249,7 @@ describe('componentPaneview', () => {
size: 22,
data: {
id: 'panel3',
component: 'testPanel',
component: 'default',
title: 'Panel 3',
},
expanded: false,
@ -252,20 +261,25 @@ describe('componentPaneview', () => {
test('toJSON shouldnt fire any layout events', () => {
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
paneview.layout(1000, 1000);
paneview.addPanel({
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
});
paneview.addPanel({
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel 2',
});
@ -283,8 +297,13 @@ describe('componentPaneview', () => {
expect(container.childNodes.length).toBe(0);
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -292,12 +311,12 @@ describe('componentPaneview', () => {
paneview.addPanel({
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
});
paneview.addPanel({
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel 2',
});
@ -310,8 +329,13 @@ describe('componentPaneview', () => {
test('panel is disposed of when component is disposed', () => {
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -319,12 +343,12 @@ describe('componentPaneview', () => {
paneview.addPanel({
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
});
paneview.addPanel({
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel 2',
});
@ -342,8 +366,13 @@ describe('componentPaneview', () => {
test('panel is disposed of when removed', () => {
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -351,12 +380,12 @@ describe('componentPaneview', () => {
paneview.addPanel({
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
});
paneview.addPanel({
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel 2',
});
@ -374,8 +403,13 @@ describe('componentPaneview', () => {
test('panel is disposed of when fromJSON is called', () => {
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -383,12 +417,12 @@ describe('componentPaneview', () => {
paneview.addPanel({
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
});
paneview.addPanel({
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel 2',
});
@ -406,8 +440,13 @@ describe('componentPaneview', () => {
test('that fromJSON layouts are resized to the current dimensions', async () => {
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -420,7 +459,7 @@ describe('componentPaneview', () => {
size: 1,
data: {
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
},
expanded: true,
@ -429,7 +468,7 @@ describe('componentPaneview', () => {
size: 2,
data: {
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel 2',
},
expanded: true,
@ -438,7 +477,7 @@ describe('componentPaneview', () => {
size: 3,
data: {
id: 'panel3',
component: 'testPanel',
component: 'default',
title: 'Panel 3',
},
expanded: true,
@ -454,7 +493,7 @@ describe('componentPaneview', () => {
size: 122,
data: {
id: 'panel1',
component: 'testPanel',
component: 'default',
title: 'Panel 1',
},
expanded: true,
@ -464,7 +503,7 @@ describe('componentPaneview', () => {
size: 122,
data: {
id: 'panel2',
component: 'testPanel',
component: 'default',
title: 'Panel 2',
},
expanded: true,
@ -474,7 +513,7 @@ describe('componentPaneview', () => {
size: 356,
data: {
id: 'panel3',
component: 'testPanel',
component: 'default',
title: 'Panel 3',
},
expanded: true,
@ -486,8 +525,13 @@ describe('componentPaneview', () => {
test('that disableAutoResizing is false by default', () => {
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -496,8 +540,13 @@ describe('componentPaneview', () => {
test('that disableAutoResizing can be enabled', () => {
const paneview = new PaneviewComponent(container, {
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
disableAutoResizing: true,
});
@ -507,8 +556,13 @@ describe('componentPaneview', () => {
test('that setVisible toggles visiblity', () => {
const paneview = new PaneviewComponent(container, {
components: {
default: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
disableAutoResizing: true,
});
@ -540,8 +594,13 @@ describe('componentPaneview', () => {
test('update className', () => {
const paneview = new PaneviewComponent(container, {
components: {
default: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
disableAutoResizing: true,
className: 'test-a test-b',

View File

@ -31,19 +31,24 @@ describe('componentSplitview', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(600, 400);
const panel1 = splitview.addPanel({
id: 'panel1',
component: 'testPanel',
component: 'default',
});
const panel2 = splitview.addPanel({
id: 'panel2',
component: 'testPanel',
component: 'default',
});
splitview.movePanel(0, 1);
@ -67,15 +72,20 @@ describe('componentSplitview', () => {
test('remove panel', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(600, 400);
splitview.addPanel({ id: 'panel1', component: 'testPanel' });
splitview.addPanel({ id: 'panel2', component: 'testPanel' });
splitview.addPanel({ id: 'panel3', component: 'testPanel' });
splitview.addPanel({ id: 'panel1', component: 'default' });
splitview.addPanel({ id: 'panel2', component: 'default' });
splitview.addPanel({ id: 'panel3', component: 'default' });
const panel1 = splitview.getPanel('panel1')!;
const panel2 = splitview.getPanel('panel2')!;
@ -102,8 +112,13 @@ describe('componentSplitview', () => {
test('horizontal dimensions', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(600, 400);
@ -115,8 +130,13 @@ describe('componentSplitview', () => {
test('vertical dimensions', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(600, 400);
@ -128,15 +148,20 @@ describe('componentSplitview', () => {
test('api resize', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(400, 600);
splitview.addPanel({ id: 'panel1', component: 'testPanel' });
splitview.addPanel({ id: 'panel2', component: 'testPanel' });
splitview.addPanel({ id: 'panel3', component: 'testPanel' });
splitview.addPanel({ id: 'panel1', component: 'default' });
splitview.addPanel({ id: 'panel2', component: 'default' });
splitview.addPanel({ id: 'panel3', component: 'default' });
const panel1 = splitview.getPanel('panel1')!;
const panel2 = splitview.getPanel('panel2')!;
@ -180,13 +205,18 @@ describe('componentSplitview', () => {
test('api', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(600, 400);
splitview.addPanel({ id: 'panel1', component: 'testPanel' });
splitview.addPanel({ id: 'panel1', component: 'default' });
const panel1 = splitview.getPanel('panel1');
@ -197,7 +227,7 @@ describe('componentSplitview', () => {
// expect(panel1?.api.isFocused).toBeFalsy();
expect(panel1!.api.isVisible).toBeTruthy();
splitview.addPanel({ id: 'panel2', component: 'testPanel' });
splitview.addPanel({ id: 'panel2', component: 'default' });
const panel2 = splitview.getPanel('panel2');
@ -221,15 +251,20 @@ describe('componentSplitview', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(300, 200);
splitview.addPanel({ id: 'panel1', component: 'testPanel' });
splitview.addPanel({ id: 'panel2', component: 'testPanel' });
splitview.addPanel({ id: 'panel1', component: 'default' });
splitview.addPanel({ id: 'panel2', component: 'default' });
const panel1 = splitview.getPanel('panel1') as SplitviewPanel;
const panel2 = splitview.getPanel('panel2') as SplitviewPanel;
@ -272,15 +307,20 @@ describe('componentSplitview', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(300, 200);
splitview.addPanel({ id: 'panel1', component: 'testPanel' });
splitview.addPanel({ id: 'panel2', component: 'testPanel' });
splitview.addPanel({ id: 'panel1', component: 'default' });
splitview.addPanel({ id: 'panel2', component: 'default' });
const panel1 = splitview.getPanel('panel1') as SplitviewPanel;
const panel2 = splitview.getPanel('panel2') as SplitviewPanel;
@ -321,8 +361,13 @@ describe('componentSplitview', () => {
test('serialization', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(400, 6);
@ -331,15 +376,15 @@ describe('componentSplitview', () => {
views: [
{
size: 1,
data: { id: 'panel1', component: 'testPanel' },
data: { id: 'panel1', component: 'default' },
snap: false,
},
{
size: 2,
data: { id: 'panel2', component: 'testPanel' },
data: { id: 'panel2', component: 'default' },
snap: true,
},
{ size: 3, data: { id: 'panel3', component: 'testPanel' } },
{ size: 3, data: { id: 'panel3', component: 'default' } },
],
size: 6,
orientation: Orientation.VERTICAL,
@ -352,17 +397,17 @@ describe('componentSplitview', () => {
views: [
{
size: 1,
data: { id: 'panel1', component: 'testPanel' },
data: { id: 'panel1', component: 'default' },
snap: false,
},
{
size: 2,
data: { id: 'panel2', component: 'testPanel' },
data: { id: 'panel2', component: 'default' },
snap: true,
},
{
size: 3,
data: { id: 'panel3', component: 'testPanel' },
data: { id: 'panel3', component: 'default' },
snap: false,
},
],
@ -375,8 +420,13 @@ describe('componentSplitview', () => {
test('toJSON shouldnt fire any layout events', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -384,11 +434,11 @@ describe('componentSplitview', () => {
splitview.addPanel({
id: 'panel1',
component: 'testPanel',
component: 'default',
});
splitview.addPanel({
id: 'panel2',
component: 'testPanel',
component: 'default',
});
const disposable = splitview.onDidLayoutChange(() => {
@ -406,8 +456,13 @@ describe('componentSplitview', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -415,11 +470,11 @@ describe('componentSplitview', () => {
splitview.addPanel({
id: 'panel1',
component: 'testPanel',
component: 'default',
});
splitview.addPanel({
id: 'panel2',
component: 'testPanel',
component: 'default',
});
expect(container.childNodes.length).toBeGreaterThan(0);
@ -432,8 +487,13 @@ describe('componentSplitview', () => {
test('panel is disposed of when component is disposed', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
default: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -463,8 +523,13 @@ describe('componentSplitview', () => {
test('panel is disposed of when removed', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
default: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -494,8 +559,13 @@ describe('componentSplitview', () => {
test('panel is disposed of when fromJSON is called', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
default: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -529,8 +599,13 @@ describe('componentSplitview', () => {
test('that fromJSON layouts are resized to the current dimensions', async () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(400, 600);
@ -539,15 +614,15 @@ describe('componentSplitview', () => {
views: [
{
size: 1,
data: { id: 'panel1', component: 'testPanel' },
data: { id: 'panel1', component: 'default' },
snap: false,
},
{
size: 2,
data: { id: 'panel2', component: 'testPanel' },
data: { id: 'panel2', component: 'default' },
snap: true,
},
{ size: 3, data: { id: 'panel3', component: 'testPanel' } },
{ size: 3, data: { id: 'panel3', component: 'default' } },
],
size: 6,
orientation: Orientation.VERTICAL,
@ -558,17 +633,17 @@ describe('componentSplitview', () => {
views: [
{
size: 100,
data: { id: 'panel1', component: 'testPanel' },
data: { id: 'panel1', component: 'default' },
snap: false,
},
{
size: 200,
data: { id: 'panel2', component: 'testPanel' },
data: { id: 'panel2', component: 'default' },
snap: true,
},
{
size: 300,
data: { id: 'panel3', component: 'testPanel' },
data: { id: 'panel3', component: 'default' },
snap: false,
},
],
@ -581,8 +656,13 @@ describe('componentSplitview', () => {
test('that disableAutoResizing is false by default', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -592,8 +672,13 @@ describe('componentSplitview', () => {
test('that disableAutoResizing can be enabled', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
components: {
testPanel: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
disableAutoResizing: true,
});
@ -604,8 +689,13 @@ describe('componentSplitview', () => {
test('that setVisible toggles visiblity', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
default: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
@ -635,8 +725,13 @@ describe('componentSplitview', () => {
test('update className', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
components: {
default: TestPanel,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
className: 'test-a test-b',
});

View File

@ -96,7 +96,7 @@ export class DockviewUnhandledDragOverEvent implements DockviewDndOverlayEvent {
}
}
export const PROPERTY_KEYS: (keyof DockviewOptions)[] = (() => {
export const PROPERTY_KEYS_DOCKVIEW: (keyof DockviewOptions)[] = (() => {
/**
* by readong the keys from an empty value object TypeScript will error
* when we add or remove new properties to `DockviewOptions`

View File

@ -23,7 +23,6 @@ import {
} from './gridviewPanel';
import { BaseComponentOptions, Parameters } from '../panel/types';
import { Orientation, Sizing } from '../splitview/splitview';
import { createComponent } from '../panel/componentFactory';
import { Emitter, Event } from '../events';
import { Position } from '../dnd/droptarget';
@ -116,9 +115,11 @@ export class GridviewComponent
constructor(parentElement: HTMLElement, options: GridviewComponentOptions) {
super(parentElement, {
proportionalLayout: options.proportionalLayout,
proportionalLayout: options.proportionalLayout ?? true,
orientation: options.orientation,
styles: options.styles,
styles: options.hideBorders
? { separatorBorder: 'transparent' }
: undefined,
disableAutoResizing: options.disableAutoResizing,
className: options.className,
});
@ -139,13 +140,6 @@ export class GridviewComponent
this._onDidActiveGroupChange.fire(event);
})
);
if (!this.options.components) {
this.options.components = {};
}
if (!this.options.frameworkComponents) {
this.options.frameworkComponents = {};
}
}
override updateOptions(options: Partial<GridviewComponentOptions>): void {
@ -216,19 +210,11 @@ export class GridviewComponent
this.gridview.deserialize(grid, {
fromJSON: (node) => {
const { data } = node;
const view = createComponent(
data.id,
data.component,
this.options.components ?? {},
this.options.frameworkComponents ?? {},
this.options.frameworkComponentFactory
? {
createComponent:
this.options.frameworkComponentFactory
.createComponent,
}
: undefined
);
const view = this.options.createComponent({
id: data.id,
name: data.component,
});
queue.push(() =>
view.init({
@ -363,19 +349,10 @@ export class GridviewComponent
}
}
const view = createComponent(
options.id,
options.component,
this.options.components ?? {},
this.options.frameworkComponents ?? {},
this.options.frameworkComponentFactory
? {
createComponent:
this.options.frameworkComponentFactory
.createComponent,
}
: undefined
);
const view = this.options.createComponent({
id: options.id,
name: options.component,
});
view.init({
params: options.params ?? {},

View File

@ -1,21 +1,34 @@
import { GridviewPanel } from './gridviewPanel';
import { ISplitviewStyles, Orientation } from '../splitview/splitview';
import {
ComponentConstructor,
FrameworkFactory,
} from '../panel/componentFactory';
import { Orientation } from '../splitview/splitview';
import { CreateComponentOptions } from '../dockview/options';
export interface GridviewComponentOptions {
export interface GridviewOptions {
disableAutoResizing?: boolean;
proportionalLayout: boolean;
proportionalLayout?: boolean;
orientation: Orientation;
components?: {
[componentName: string]: ComponentConstructor<GridviewPanel>;
};
frameworkComponents?: {
[componentName: string]: any;
};
frameworkComponentFactory?: FrameworkFactory<GridviewPanel>;
styles?: ISplitviewStyles;
className?: string;
hideBorders?: boolean;
}
export interface GridviewFrameworkOptions {
createComponent: (options: CreateComponentOptions) => GridviewPanel;
}
export type GridviewComponentOptions = GridviewOptions &
GridviewFrameworkOptions;
export const PROPERTY_KEYS_GRIDVIEW: (keyof GridviewOptions)[] = (() => {
/**
* by readong the keys from an empty value object TypeScript will error
* when we add or remove new properties to `DockviewOptions`
*/
const properties: Record<keyof GridviewOptions, undefined> = {
disableAutoResizing: undefined,
proportionalLayout: undefined,
orientation: undefined,
hideBorders: undefined,
className: undefined,
};
return Object.keys(properties) as (keyof GridviewOptions)[];
})();

View File

@ -24,11 +24,19 @@ export * from './splitview/splitview';
export {
SplitviewComponentOptions,
PanelViewInitParameters,
SplitviewOptions,
SplitviewFrameworkOptions,
PROPERTY_KEYS_SPLITVIEW,
} from './splitview/options';
export * from './paneview/paneview';
export * from './gridview/gridview';
export { GridviewComponentOptions } from './gridview/options';
export {
GridviewComponentOptions,
GridviewOptions,
GridviewFrameworkOptions,
PROPERTY_KEYS_GRIDVIEW,
} from './gridview/options';
export * from './gridview/baseComponentGridview';
export {
@ -67,7 +75,12 @@ export * from './dockview/dockviewComponent';
export * from './gridview/gridviewComponent';
export * from './splitview/splitviewComponent';
export * from './paneview/paneviewComponent';
export { PaneviewComponentOptions } from './paneview/options';
export {
PaneviewComponentOptions,
PaneviewOptions,
PaneviewFrameworkOptions,
PROPERTY_KEYS_PANEVIEW,
} from './paneview/options';
export * from './gridview/gridviewPanel';
export { SplitviewPanel, ISplitviewPanel } from './splitview/splitviewPanel';

View File

@ -1,58 +0,0 @@
export interface FrameworkFactory<T> {
createComponent: (id: string, componentId: string, component: any) => T;
}
export type ComponentConstructor<T> = {
new (id: string, component: string): T;
};
export function createComponent<T>(
id: string,
componentName?: string,
components: {
[componentName: string]: ComponentConstructor<T>;
} = {},
frameworkComponents: {
[componentName: string]: any;
} = {},
createFrameworkComponent?: FrameworkFactory<T>,
fallback?: () => T
): T {
const Component =
typeof componentName === 'string'
? components[componentName]
: undefined;
const FrameworkComponent =
typeof componentName === 'string'
? frameworkComponents[componentName]
: undefined;
if (Component && FrameworkComponent) {
throw new Error(
`Cannot create '${id}'. component '${componentName}' registered as both a component and frameworkComponent`
);
}
if (FrameworkComponent) {
if (!createFrameworkComponent) {
throw new Error(
`Cannot create '${id}' for framework component '${componentName}'. you must register a frameworkPanelWrapper to use framework components`
);
}
return createFrameworkComponent.createComponent(
id,
componentName!,
FrameworkComponent
);
}
if (!Component) {
if (fallback) {
return fallback();
}
throw new Error(
`Cannot create '${id}', no component '${componentName}' provided`
);
}
return new Component(id, componentName!);
}

View File

@ -2,14 +2,11 @@ import { addDisposableListener } from '../events';
import { PaneviewPanelApiImpl } from '../api/paneviewPanelApi';
import { CompositeDisposable, MutableDisposable } from '../lifecycle';
import { PanelUpdateEvent } from '../panel/types';
import { IPaneHeaderPart, PanePanelInitParameter } from './paneviewPanel';
import { IPanePart, PanePanelInitParameter } from './paneviewPanel';
import { toggleClass } from '../dom';
import { createChevronRightButton, createExpandMoreButton } from '../svg';
export class DefaultHeader
extends CompositeDisposable
implements IPaneHeaderPart
{
export class DefaultHeader extends CompositeDisposable implements IPanePart {
private readonly _expandedIcon = createExpandMoreButton();
private readonly _collapsedIcon = createChevronRightButton();
private readonly disposable = new MutableDisposable();

View File

@ -1,29 +1,35 @@
import {
ComponentConstructor,
FrameworkFactory,
} from '../panel/componentFactory';
import { CreateComponentOptions } from '../dockview/options';
import { PaneviewDndOverlayEvent } from './paneviewComponent';
import { IPaneBodyPart, IPaneHeaderPart, PaneviewPanel } from './paneviewPanel';
import { IPanePart } from './paneviewPanel';
export interface PaneviewComponentOptions {
export interface PaneviewOptions {
disableAutoResizing?: boolean;
components?: {
[componentName: string]: ComponentConstructor<PaneviewPanel>;
};
frameworkComponents?: {
[componentName: string]: any;
};
headerComponents?: {
[componentName: string]: ComponentConstructor<PaneviewPanel>;
};
headerframeworkComponents?: {
[componentName: string]: any;
};
frameworkWrapper?: {
header: FrameworkFactory<IPaneHeaderPart>;
body: FrameworkFactory<IPaneBodyPart>;
};
disableDnd?: boolean;
showDndOverlay?: (event: PaneviewDndOverlayEvent) => boolean;
className?: string;
}
export interface PaneviewFrameworkOptions {
createComponent: (options: CreateComponentOptions) => IPanePart;
createHeaderComponent?: (
options: CreateComponentOptions
) => IPanePart | undefined;
}
export type PaneviewComponentOptions = PaneviewOptions &
PaneviewFrameworkOptions;
export const PROPERTY_KEYS_PANEVIEW: (keyof PaneviewOptions)[] = (() => {
/**
* by readong the keys from an empty value object TypeScript will error
* when we add or remove new properties to `DockviewOptions`
*/
const properties: Record<keyof PaneviewOptions, undefined> = {
disableAutoResizing: undefined,
disableDnd: undefined,
showDndOverlay: undefined,
className: undefined,
};
return Object.keys(properties) as (keyof PaneviewOptions)[];
})();

View File

@ -1,5 +1,4 @@
import { PaneviewApi } from '../api/component.api';
import { createComponent } from '../panel/componentFactory';
import { Emitter, Event } from '../events';
import {
CompositeDisposable,
@ -9,12 +8,7 @@ import {
import { LayoutPriority, Orientation, Sizing } from '../splitview/splitview';
import { PaneviewComponentOptions } from './options';
import { Paneview } from './paneview';
import {
IPaneBodyPart,
IPaneHeaderPart,
PaneviewPanel,
IPaneviewPanel,
} from './paneviewPanel';
import { IPanePart, PaneviewPanel, IPaneviewPanel } from './paneviewPanel';
import {
DraggablePaneviewPanel,
PaneviewDropEvent,
@ -61,8 +55,8 @@ export class PaneFramework extends DraggablePaneviewPanel {
id: string;
component: string;
headerComponent: string | undefined;
body: IPaneBodyPart;
header: IPaneHeaderPart;
body: IPanePart;
header: IPanePart;
orientation: Orientation;
isExpanded: boolean;
disableDnd: boolean;
@ -218,13 +212,6 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
this._options = options;
if (!options.components) {
options.components = {};
}
if (!options.frameworkComponents) {
options.frameworkComponents = {};
}
this.paneview = new Paneview(this.element, {
// only allow paneview in the vertical orientation for now
orientation: Orientation.VERTICAL,
@ -257,36 +244,21 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
addPanel<T extends object = Parameters>(
options: AddPaneviewComponentOptions<T>
): IPaneviewPanel {
const body = createComponent(
options.id,
options.component,
this.options.components ?? {},
this.options.frameworkComponents ?? {},
this.options.frameworkWrapper
? {
createComponent:
this.options.frameworkWrapper.body.createComponent,
}
: undefined
);
const body = this.options.createComponent({
id: options.id,
name: options.component,
});
let header: IPaneHeaderPart;
let header: IPanePart | undefined;
if (options.headerComponent) {
header = createComponent(
options.id,
options.headerComponent,
this.options.headerComponents ?? {},
this.options.headerframeworkComponents,
this.options.frameworkWrapper
? {
createComponent:
this.options.frameworkWrapper.header
.createComponent,
if (options.headerComponent && this.options.createHeaderComponent) {
header = this.options.createHeaderComponent({
id: options.id,
name: options.headerComponent,
});
}
: undefined
);
} else {
if (!header) {
header = new DefaultHeader();
}
@ -395,37 +367,24 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
views: views.map((view) => {
const data = view.data;
const body = createComponent(
data.id,
data.component,
this.options.components ?? {},
this.options.frameworkComponents ?? {},
this.options.frameworkWrapper
? {
createComponent:
this.options.frameworkWrapper.body
.createComponent,
}
: undefined
);
const body = this.options.createComponent({
id: data.id,
name: data.component,
});
let header: IPaneHeaderPart;
let header: IPanePart | undefined;
if (data.headerComponent) {
header = createComponent(
data.id,
data.headerComponent,
this.options.headerComponents ?? {},
this.options.headerframeworkComponents ?? {},
this.options.frameworkWrapper
? {
createComponent:
this.options.frameworkWrapper.header
.createComponent,
if (
data.headerComponent &&
this.options.createHeaderComponent
) {
header = this.options.createHeaderComponent({
id: data.id,
name: data.headerComponent,
});
}
: undefined
);
} else {
if (!header) {
header = new DefaultHeader();
}

View File

@ -36,13 +36,7 @@ export interface PanePanelComponentInitParameter
api: PaneviewPanelApiImpl;
}
export interface IPaneBodyPart extends IDisposable {
readonly element: HTMLElement;
update(params: PanelUpdateEvent): void;
init(parameters: PanePanelComponentInitParameter): void;
}
export interface IPaneHeaderPart extends IDisposable {
export interface IPanePart extends IDisposable {
readonly element: HTMLElement;
update(params: PanelUpdateEvent): void;
init(parameters: PanePanelComponentInitParameter): void;
@ -85,8 +79,8 @@ export abstract class PaneviewPanel
private _isExpanded = false;
protected header?: HTMLElement;
protected body?: HTMLElement;
private bodyPart?: IPaneHeaderPart;
private headerPart?: IPaneBodyPart;
private bodyPart?: IPanePart;
private headerPart?: IPanePart;
private expandedSize = 0;
private animationTimer: any;
private _orientation: Orientation;
@ -338,6 +332,6 @@ export abstract class PaneviewPanel
};
}
protected abstract getBodyComponent(): IPaneBodyPart;
protected abstract getHeaderComponent(): IPaneHeaderPart;
protected abstract getBodyComponent(): IPanePart;
protected abstract getHeaderComponent(): IPanePart;
}

View File

@ -2,10 +2,7 @@ import { PanelInitParameters } from '../panel/types';
import { SplitViewOptions, LayoutPriority } from './splitview';
import { SplitviewPanel } from './splitviewPanel';
import { SplitviewComponent } from './splitviewComponent';
import {
ComponentConstructor,
FrameworkFactory,
} from '../panel/componentFactory';
import { CreateComponentOptions } from '../dockview/options';
export interface PanelViewInitParameters extends PanelInitParameters {
minimumSize?: number;
@ -15,14 +12,32 @@ export interface PanelViewInitParameters extends PanelInitParameters {
accessor: SplitviewComponent;
}
export interface SplitviewComponentOptions extends SplitViewOptions {
export interface SplitviewOptions extends SplitViewOptions {
disableAutoResizing?: boolean;
components?: {
[componentName: string]: ComponentConstructor<SplitviewPanel>;
};
frameworkComponents?: {
[componentName: string]: any;
};
frameworkWrapper?: FrameworkFactory<SplitviewPanel>;
className?: string;
}
export interface SplitviewFrameworkOptions {
createComponent: (options: CreateComponentOptions) => SplitviewPanel;
}
export type SplitviewComponentOptions = SplitviewOptions &
SplitviewFrameworkOptions;
export const PROPERTY_KEYS_SPLITVIEW: (keyof SplitviewOptions)[] = (() => {
/**
* by readong the keys from an empty value object TypeScript will error
* when we add or remove new properties to `DockviewOptions`
*/
const properties: Record<keyof SplitviewOptions, undefined> = {
orientation: undefined,
descriptor: undefined,
proportionalLayout: undefined,
styles: undefined,
margin: undefined,
disableAutoResizing: undefined,
className: undefined,
};
return Object.keys(properties) as (keyof SplitviewOptions)[];
})();

View File

@ -32,11 +32,11 @@ export interface ISplitviewStyles {
}
export interface SplitViewOptions {
readonly orientation: Orientation;
readonly descriptor?: ISplitViewDescriptor;
readonly proportionalLayout?: boolean;
readonly styles?: ISplitviewStyles;
readonly margin?: number;
orientation: Orientation;
descriptor?: ISplitViewDescriptor;
proportionalLayout?: boolean;
styles?: ISplitviewStyles;
margin?: number;
}
export enum LayoutPriority {

View File

@ -15,7 +15,6 @@ import { SplitviewComponentOptions } from './options';
import { BaseComponentOptions, Parameters } from '../panel/types';
import { Emitter, Event } from '../events';
import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel';
import { createComponent } from '../panel/componentFactory';
import { Resizable } from '../resizable';
import { Classnames } from '../dom';
@ -167,13 +166,6 @@ export class SplitviewComponent
this._options = options;
if (!options.components) {
options.components = {};
}
if (!options.frameworkComponents) {
options.frameworkComponents = {};
}
this.splitview = new Splitview(this.element, options);
this.addDisposables(
@ -267,18 +259,10 @@ export class SplitviewComponent
throw new Error(`panel ${options.id} already exists`);
}
const view = createComponent(
options.id,
options.component,
this.options.components ?? {},
this.options.frameworkComponents ?? {},
this.options.frameworkWrapper
? {
createComponent:
this.options.frameworkWrapper.createComponent,
}
: undefined
);
const view = this.options.createComponent({
id: options.id,
name: options.component,
});
view.orientation = this.splitview.orientation;
@ -367,19 +351,10 @@ export class SplitviewComponent
throw new Error(`panel ${data.id} already exists`);
}
const panel = createComponent(
data.id,
data.component,
this.options.components ?? {},
this.options.frameworkComponents ?? {},
this.options.frameworkWrapper
? {
createComponent:
this.options.frameworkWrapper
.createComponent,
}
: undefined
);
const panel = this.options.createComponent({
id: data.id,
name: data.component,
});
queue.push(() => {
panel.init({

View File

@ -2,7 +2,7 @@
import {
DockviewApi,
type DockviewOptions,
PROPERTY_KEYS,
PROPERTY_KEYS_DOCKVIEW,
type DockviewFrameworkOptions,
createDockview,
} from 'dockview-core';
@ -25,7 +25,7 @@ import {
import type { IDockviewVueProps, VueEvents } from './types';
function extractCoreOptions(props: IDockviewVueProps): DockviewOptions {
const coreOptions = (PROPERTY_KEYS as (keyof DockviewOptions)[]).reduce(
const coreOptions = (PROPERTY_KEYS_DOCKVIEW as (keyof DockviewOptions)[]).reduce(
(obj, key) => {
(obj as any)[key] = props[key];
return obj;
@ -43,7 +43,7 @@ const props = defineProps<IDockviewVueProps>();
const el = ref<HTMLElement | null>(null);
const instance = ref<DockviewApi | null>(null);
PROPERTY_KEYS.forEach((coreOptionKey) => {
PROPERTY_KEYS_DOCKVIEW.forEach((coreOptionKey) => {
watch(
() => props[coreOptionKey],
(newValue, oldValue) => {

View File

@ -10,7 +10,7 @@ import {
IDockviewPanelHeaderProps,
IDockviewPanelProps,
DockviewOptions,
PROPERTY_KEYS,
PROPERTY_KEYS_DOCKVIEW,
DockviewComponentOptions,
DockviewFrameworkOptions,
DockviewReadyEvent,
@ -40,7 +40,6 @@ function createGroupControlElement(
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
export interface IDockviewReactProps extends DockviewOptions {
className?: string;
tabComponents?: Record<
string,
React.FunctionComponent<IDockviewPanelHeaderProps>
@ -58,7 +57,7 @@ export interface IDockviewReactProps extends DockviewOptions {
}
function extractCoreOptions(props: IDockviewReactProps): DockviewOptions {
const coreOptions = PROPERTY_KEYS.reduce((obj, key) => {
const coreOptions = PROPERTY_KEYS_DOCKVIEW.reduce((obj, key) => {
if (key in props) {
obj[key] = props[key] as any;
}
@ -82,7 +81,7 @@ export const DockviewReact = React.forwardRef(
() => {
const changes: Partial<DockviewOptions> = {};
PROPERTY_KEYS.forEach((propKey) => {
PROPERTY_KEYS_DOCKVIEW.forEach((propKey) => {
const key = propKey;
const propValue = props[key];
@ -99,7 +98,7 @@ export const DockviewReact = React.forwardRef(
prevProps.current = props;
},
PROPERTY_KEYS.map((key) => props[key])
PROPERTY_KEYS_DOCKVIEW.map((key) => props[key])
);
React.useEffect(() => {

View File

@ -1,13 +1,17 @@
import React from 'react';
import {
GridviewPanelApi,
Orientation,
GridviewApi,
createGridview,
GridviewOptions,
PROPERTY_KEYS_GRIDVIEW,
GridviewComponentOptions,
GridviewFrameworkOptions,
} from 'dockview-core';
import { ReactGridPanelView } from './view';
import { usePortalsLifecycle } from '../react';
import { PanelParameters } from '../types';
export interface GridviewReadyEvent {
api: GridviewApi;
}
@ -18,14 +22,20 @@ export interface IGridviewPanelProps<T extends { [index: string]: any } = any>
containerApi: GridviewApi;
}
export interface IGridviewReactProps {
orientation?: Orientation;
export interface IGridviewReactProps extends GridviewOptions {
onReady: (event: GridviewReadyEvent) => void;
components: Record<string, React.FunctionComponent<IGridviewPanelProps>>;
hideBorders?: boolean;
className?: string;
proportionalLayout?: boolean;
disableAutoResizing?: boolean;
}
function extractCoreOptions(props: IGridviewReactProps): GridviewOptions {
const coreOptions = PROPERTY_KEYS_GRIDVIEW.reduce((obj, key) => {
if (key in props) {
obj[key] = props[key] as any;
}
return obj;
}, {} as Partial<GridviewComponentOptions>);
return coreOptions as GridviewOptions;
}
export const GridviewReact = React.forwardRef(
@ -36,6 +46,32 @@ export const GridviewReact = React.forwardRef(
React.useImperativeHandle(ref, () => domRef.current!, []);
const prevProps = React.useRef<Partial<IGridviewReactProps>>({});
React.useEffect(
() => {
const changes: Partial<GridviewOptions> = {};
PROPERTY_KEYS_GRIDVIEW.forEach((propKey) => {
const key = propKey;
const propValue = props[key];
if (key in props && propValue !== prevProps.current[key]) {
changes[key] = propValue as any;
}
});
if (gridviewRef.current) {
gridviewRef.current.updateOptions(changes);
} else {
// not yet fully initialized
}
prevProps.current = props;
},
PROPERTY_KEYS_GRIDVIEW.map((key) => props[key])
);
React.useEffect(() => {
if (!domRef.current) {
return () => {
@ -43,29 +79,20 @@ export const GridviewReact = React.forwardRef(
};
}
const api = createGridview(domRef.current, {
disableAutoResizing: props.disableAutoResizing,
proportionalLayout:
typeof props.proportionalLayout === 'boolean'
? props.proportionalLayout
: true,
orientation: props.orientation ?? Orientation.HORIZONTAL,
frameworkComponents: props.components,
frameworkComponentFactory: {
createComponent: (id: string, componentId, component) => {
const frameworkOptions: GridviewFrameworkOptions = {
createComponent: (options) => {
return new ReactGridPanelView(
id,
componentId,
component,
{
addPortal,
}
options.id,
options.name,
props.components[options.name],
{ addPortal }
);
},
},
styles: props.hideBorders
? { separatorBorder: 'transparent' }
: undefined,
};
const api = createGridview(domRef.current, {
...extractCoreOptions(props),
...frameworkOptions,
});
const { clientWidth, clientHeight } = domRef.current;
@ -87,7 +114,14 @@ export const GridviewReact = React.forwardRef(
return;
}
gridviewRef.current.updateOptions({
frameworkComponents: props.components,
createComponent: (options) => {
return new ReactGridPanelView(
options.id,
options.name,
props.components[options.name],
{ addPortal }
);
},
});
}, [props.components]);

View File

@ -5,6 +5,10 @@ import {
PaneviewApi,
PaneviewDropEvent,
createPaneview,
PaneviewOptions,
PROPERTY_KEYS_PANEVIEW,
PaneviewComponentOptions,
PaneviewFrameworkOptions,
} from 'dockview-core';
import { usePortalsLifecycle } from '../react';
import { PanePanelSection } from './view';
@ -21,20 +25,28 @@ export interface IPaneviewPanelProps<T extends { [index: string]: any } = any>
title: string;
}
export interface IPaneviewReactProps {
export interface IPaneviewReactProps extends PaneviewOptions {
onReady: (event: PaneviewReadyEvent) => void;
components: Record<string, React.FunctionComponent<IPaneviewPanelProps>>;
headerComponents?: Record<
string,
React.FunctionComponent<IPaneviewPanelProps>
>;
className?: string;
disableAutoResizing?: boolean;
disableDnd?: boolean;
showDndOverlay?: (event: PaneviewDndOverlayEvent) => boolean;
onDidDrop?(event: PaneviewDropEvent): void;
}
function extractCoreOptions(props: IPaneviewReactProps): PaneviewOptions {
const coreOptions = PROPERTY_KEYS_PANEVIEW.reduce((obj, key) => {
if (key in props) {
obj[key] = props[key] as any;
}
return obj;
}, {} as Partial<PaneviewComponentOptions>);
return coreOptions as PaneviewOptions;
}
export const PaneviewReact = React.forwardRef(
(props: IPaneviewReactProps, ref: React.ForwardedRef<HTMLDivElement>) => {
const domRef = React.useRef<HTMLDivElement>(null);
@ -43,35 +55,64 @@ export const PaneviewReact = React.forwardRef(
React.useImperativeHandle(ref, () => domRef.current!, []);
const prevProps = React.useRef<Partial<IPaneviewReactProps>>({});
React.useEffect(
() => {
const changes: Partial<PaneviewOptions> = {};
PROPERTY_KEYS_PANEVIEW.forEach((propKey) => {
const key = propKey;
const propValue = props[key];
if (key in props && propValue !== prevProps.current[key]) {
changes[key] = propValue as any;
}
});
if (paneviewRef.current) {
paneviewRef.current.updateOptions(changes);
} else {
// not yet fully initialized
}
prevProps.current = props;
},
PROPERTY_KEYS_PANEVIEW.map((key) => props[key])
);
React.useEffect(() => {
const createComponent = (
id: string,
_componentId: string,
component: any
) =>
new PanePanelSection(id, component, {
addPortal,
if (!domRef.current) {
return () => {
// noop
};
}
const headerComponents = props.headerComponents ?? {};
const frameworkOptions: PaneviewFrameworkOptions = {
createComponent: (options) => {
return new PanePanelSection(
options.id,
props.components[options.name],
{ addPortal }
);
},
createHeaderComponent: (options) => {
return new PanePanelSection(
options.id,
headerComponents[options.name],
{ addPortal }
);
},
};
const api = createPaneview(domRef.current, {
...extractCoreOptions(props),
...frameworkOptions,
});
const api = createPaneview(domRef.current!, {
disableAutoResizing: props.disableAutoResizing,
frameworkComponents: props.components,
components: {},
headerComponents: {},
disableDnd: props.disableDnd,
headerframeworkComponents: props.headerComponents,
frameworkWrapper: {
header: {
createComponent,
},
body: {
createComponent,
},
},
showDndOverlay: props.showDndOverlay,
});
const { clientWidth, clientHeight } = domRef.current!;
const { clientWidth, clientHeight } = domRef.current;
api.layout(clientWidth, clientHeight);
if (props.onReady) {
@ -90,7 +131,13 @@ export const PaneviewReact = React.forwardRef(
return;
}
paneviewRef.current.updateOptions({
frameworkComponents: props.components,
createComponent: (options) => {
return new PanePanelSection(
options.id,
props.components[options.name],
{ addPortal }
);
},
});
}, [props.components]);
@ -98,26 +145,30 @@ export const PaneviewReact = React.forwardRef(
if (!paneviewRef.current) {
return;
}
const headerComponents = props.headerComponents ?? {};
paneviewRef.current.updateOptions({
headerframeworkComponents: props.headerComponents,
createHeaderComponent: (options) => {
return new PanePanelSection(
options.id,
headerComponents[options.name],
{ addPortal }
);
},
});
}, [props.headerComponents]);
React.useEffect(() => {
if (!paneviewRef.current) {
return () => {
//
// noop
};
}
const api = paneviewRef.current;
const disposable = api.onDidDrop((event) => {
const disposable = paneviewRef.current.onDidDrop((event) => {
if (props.onDidDrop) {
props.onDidDrop({
...event,
api,
});
props.onDidDrop(event);
}
});

View File

@ -1,13 +1,13 @@
import React from 'react';
import {
PanelUpdateEvent,
IPaneBodyPart,
IPanePart,
PanePanelComponentInitParameter,
} from 'dockview-core';
import { ReactPart, ReactPortalStore } from '../react';
import { IPaneviewPanelProps } from './paneview';
export class PanePanelSection implements IPaneBodyPart {
export class PanePanelSection implements IPanePart {
private readonly _element: HTMLElement;
private part?: ReactPart<IPaneviewPanelProps>;

View File

@ -2,8 +2,11 @@ import React from 'react';
import {
SplitviewApi,
SplitviewPanelApi,
Orientation,
createSplitview,
SplitviewOptions,
PROPERTY_KEYS_SPLITVIEW,
SplitviewFrameworkOptions,
SplitviewComponentOptions,
} from 'dockview-core';
import { usePortalsLifecycle } from '../react';
import { PanelParameters } from '../types';
@ -19,14 +22,20 @@ export interface ISplitviewPanelProps<T extends { [index: string]: any } = any>
containerApi: SplitviewApi;
}
export interface ISplitviewReactProps {
orientation?: Orientation;
export interface ISplitviewReactProps extends SplitviewOptions {
onReady: (event: SplitviewReadyEvent) => void;
components: Record<string, React.FunctionComponent<ISplitviewPanelProps>>;
proportionalLayout?: boolean;
hideBorders?: boolean;
className?: string;
disableAutoResizing?: boolean;
}
function extractCoreOptions(props: ISplitviewReactProps): SplitviewOptions {
const coreOptions = PROPERTY_KEYS_SPLITVIEW.reduce((obj, key) => {
if (key in props) {
obj[key] = props[key] as any;
}
return obj;
}, {} as Partial<SplitviewComponentOptions>);
return coreOptions as SplitviewOptions;
}
export const SplitviewReact = React.forwardRef(
@ -37,32 +46,56 @@ export const SplitviewReact = React.forwardRef(
React.useImperativeHandle(ref, () => domRef.current!, []);
React.useEffect(() => {
const api = createSplitview(domRef.current!, {
disableAutoResizing: props.disableAutoResizing,
orientation: props.orientation ?? Orientation.HORIZONTAL,
frameworkComponents: props.components,
frameworkWrapper: {
createComponent: (
id: string,
componentId,
component: any
) => {
return new ReactPanelView(id, componentId, component, {
addPortal,
});
},
},
proportionalLayout:
typeof props.proportionalLayout === 'boolean'
? props.proportionalLayout
: true,
styles: props.hideBorders
? { separatorBorder: 'transparent' }
: undefined,
const prevProps = React.useRef<Partial<ISplitviewReactProps>>({});
React.useEffect(
() => {
const changes: Partial<SplitviewOptions> = {};
PROPERTY_KEYS_SPLITVIEW.forEach((propKey) => {
const key = propKey;
const propValue = props[key];
if (key in props && propValue !== prevProps.current[key]) {
changes[key] = propValue as any;
}
});
const { clientWidth, clientHeight } = domRef.current!;
if (splitviewRef.current) {
splitviewRef.current.updateOptions(changes);
} else {
// not yet fully initialized
}
prevProps.current = props;
},
PROPERTY_KEYS_SPLITVIEW.map((key) => props[key])
);
React.useEffect(() => {
if (!domRef.current) {
return () => {
// noop
};
}
const frameworkOptions: SplitviewFrameworkOptions = {
createComponent: (options) => {
return new ReactPanelView(
options.id,
options.name,
props.components[options.name],
{ addPortal }
);
},
};
const api = createSplitview(domRef.current, {
...extractCoreOptions(props),
...frameworkOptions,
});
const { clientWidth, clientHeight } = domRef.current;
api.layout(clientWidth, clientHeight);
if (props.onReady) {
@ -81,7 +114,14 @@ export const SplitviewReact = React.forwardRef(
return;
}
splitviewRef.current.updateOptions({
frameworkComponents: props.components,
createComponent: (options) => {
return new ReactPanelView(
options.id,
options.name,
props.components[options.name],
{ addPortal }
);
},
});
}, [props.components]);