Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ITabRenderer,
} from '../../dockview/types';
import { PanelUpdateEvent } from '../../panel/types';
import { Orientation } from '../../splitview/splitview';
import { LayoutPriority, Orientation } from '../../splitview/splitview';
import { CompositeDisposable } from '../../lifecycle';
import { Emitter } from '../../events';
import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel';
Expand Down Expand Up @@ -128,6 +128,109 @@ describe('dockviewComponent', () => {
});
});

test('group LayoutPriority is settable via addGroup and round-trips through JSON', () => {
const create = (el: HTMLElement) =>
new DockviewComponent(el, {
createComponent(options) {
switch (options.name) {
case 'default':
return new PanelContentPartTest(
options.id,
options.name
);
default:
throw new Error(`unsupported`);
}
},
});

const containerA = document.createElement('div');
const dv = create(containerA);
dv.layout(1000, 500);

// priority set at group-creation time reaches the group (grid leaf)
dv.addPanel({ id: 'p1', component: 'default' });
const fillGroup = dv.addGroup({
direction: 'right',
priority: LayoutPriority.Fill,
});
dv.addPanel({
id: 'p2',
component: 'default',
position: { referenceGroup: fillGroup },
});

expect(fillGroup.priority).toBe(LayoutPriority.Fill);
expect(fillGroup.api.priority).toBe(LayoutPriority.Fill);

// it is present in the serialized group state
const state = dv.toJSON();
expect(JSON.stringify(state)).toContain('"priority":"fill"');

// and restored when loaded into a fresh component
const containerB = document.createElement('div');
const dv2 = create(containerB);
dv2.layout(1000, 500);
dv2.fromJSON(state);

const restored = dv2.groups.find(
(g) => g.priority === LayoutPriority.Fill
);
expect(restored).toBeDefined();
expect(restored!.panels.map((p) => p.id)).toContain('p2');

dv.dispose();
dv2.dispose();
});

test('group LayoutPriority is settable at runtime via the group api', () => {
dockview.layout(1000, 500);

const panel = dockview.addPanel({ id: 'p1', component: 'default' });
const group = panel.group;

expect(group.api.priority).toBeUndefined();

group.api.priority = LayoutPriority.Fill;
expect(group.api.priority).toBe(LayoutPriority.Fill);
expect(group.priority).toBe(LayoutPriority.Fill);
});

test('a group with LayoutPriority.Fill absorbs resize while siblings stay fixed', () => {
dockview.layout(600, 1000);

const p1 = dockview.addPanel({ id: 'p1', component: 'default' });
const p2 = dockview.addPanel({
id: 'p2',
component: 'default',
position: { direction: 'right' },
});
const p3 = dockview.addPanel({
id: 'p3',
component: 'default',
position: { direction: 'right' },
});

expect(p1.api.width).toBe(200);
expect(p2.api.width).toBe(200);
expect(p3.api.width).toBe(200);

// make the middle group the fill group (runtime — forces a relayout)
p2.api.group.api.priority = LayoutPriority.Fill;

// grow the container: only the fill group grows; siblings stay fixed
dockview.layout(900, 1000);
expect(p1.api.width).toBe(200);
expect(p3.api.width).toBe(200);
expect(p2.api.width).toBe(500);

// shrink the container: only the fill group shrinks
dockview.layout(700, 1000);
expect(p1.api.width).toBe(200);
expect(p3.api.width).toBe(200);
expect(p2.api.width).toBe(300);
});

test('update className', () => {
dockview = new DockviewComponent(container, {
createComponent(options) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { GridviewComponent } from '../../gridview/gridviewComponent';
import { GridviewPanel } from '../../gridview/gridviewPanel';
import { CompositeDisposable } from '../../lifecycle';
import { IFrameworkPart } from '../../panel/types';
import { Orientation } from '../../splitview/splitview';
import { LayoutPriority, Orientation } from '../../splitview/splitview';

class TestGridview extends GridviewPanel {
constructor(id: string, componentName: string) {
Expand Down Expand Up @@ -80,6 +80,52 @@ describe('gridview', () => {
expect(panel?.api.isVisible).toBeTruthy();
});

test('LayoutPriority.Fill round-trips through toJSON/fromJSON', () => {
const create = () =>
new GridviewComponent(container, {
proportionalLayout: false,
orientation: Orientation.VERTICAL,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestGridview(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});

const gridview = create();
gridview.layout(800, 400);

gridview.addPanel({
id: 'content',
component: 'default',
priority: LayoutPriority.Fill,
});

expect(gridview.getPanel('content')!.priority).toBe(
LayoutPriority.Fill
);

const state = JSON.parse(JSON.stringify(gridview.toJSON()));

// the fill priority is present in the serialized output
expect(JSON.stringify(state)).toContain('"priority":"fill"');

// and it is restored when loaded into a fresh component
const restored = create();
restored.layout(800, 400);
restored.fromJSON(state);

expect(restored.getPanel('content')!.priority).toBe(
LayoutPriority.Fill
);

gridview.dispose();
restored.dispose();
});

test('remove panel', () => {
const gridview = new GridviewComponent(container, {
proportionalLayout: false,
Expand Down
185 changes: 185 additions & 0 deletions packages/dockview-core/src/__tests__/splitview/splitview.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,191 @@ describe('splitview', () => {
jest.clearAllMocks();
});

test('LayoutPriority.Fill absorbs surplus/deficit while siblings stay fixed', () => {
const splitview = new Splitview(container, {
orientation: Orientation.HORIZONTAL,
proportionalLayout: true,
});

splitview.layout(1000, 500);

const side1 = new Testview(50, Number.POSITIVE_INFINITY);
const fill = new Testview(
50,
Number.POSITIVE_INFINITY,
LayoutPriority.Fill
);
const side2 = new Testview(50, Number.POSITIVE_INFINITY);

splitview.addView(side1); // index 0
splitview.addView(fill); // index 1
splitview.addView(side2); // index 2

// pin the two side panels to fixed sizes; the fill view compensates
splitview.resizeView(0, 200);
splitview.resizeView(2, 150);

expect(splitview.getViewSize(0)).toBe(200);
expect(splitview.getViewSize(2)).toBe(150);
expect(splitview.getViewSize(1)).toBe(650); // 1000 - 200 - 150

// grow the container: only the fill view grows
splitview.layout(1200, 500);
expect(splitview.getViewSize(0)).toBe(200);
expect(splitview.getViewSize(2)).toBe(150);
expect(splitview.getViewSize(1)).toBe(850);

// shrink the container: only the fill view shrinks
splitview.layout(700, 500);
expect(splitview.getViewSize(0)).toBe(200);
expect(splitview.getViewSize(2)).toBe(150);
expect(splitview.getViewSize(1)).toBe(350);

splitview.dispose();
});

test('LayoutPriority.Fill absorbs add/remove of siblings', () => {
const splitview = new Splitview(container, {
orientation: Orientation.HORIZONTAL,
proportionalLayout: true,
});

splitview.layout(1000, 500);

const side1 = new Testview(50, Number.POSITIVE_INFINITY);
const fill = new Testview(
50,
Number.POSITIVE_INFINITY,
LayoutPriority.Fill
);

splitview.addView(side1); // index 0
splitview.addView(fill); // index 1
splitview.resizeView(0, 200);

expect(splitview.getViewSize(0)).toBe(200);
expect(splitview.getViewSize(1)).toBe(800);

// add another fixed sibling — the fill view yields the space, not the
// existing side panel
const side2 = new Testview(50, Number.POSITIVE_INFINITY);
splitview.addView(side2, 250, 2);

expect(splitview.getViewSize(0)).toBe(200);
expect(splitview.getViewSize(2)).toBe(250);
expect(splitview.getViewSize(1)).toBe(550); // 1000 - 200 - 250

// remove the new sibling — the fill view reclaims the space
splitview.removeView(2);
expect(splitview.getViewSize(0)).toBe(200);
expect(splitview.getViewSize(1)).toBe(800);

splitview.dispose();
});

test('multiple LayoutPriority.Fill views share the surplus equally', () => {
const splitview = new Splitview(container, {
orientation: Orientation.HORIZONTAL,
proportionalLayout: true,
});

splitview.layout(1000, 500);

const fill1 = new Testview(
50,
Number.POSITIVE_INFINITY,
LayoutPriority.Fill
);
const fill2 = new Testview(
50,
Number.POSITIVE_INFINITY,
LayoutPriority.Fill
);

splitview.addView(fill1); // index 0
splitview.addView(fill2); // index 1

// both fill views split the container equally
expect(splitview.getViewSize(0)).toBe(500);
expect(splitview.getViewSize(1)).toBe(500);

// the surplus from growing the container is shared equally
splitview.layout(1200, 500);
expect(splitview.getViewSize(0)).toBe(600);
expect(splitview.getViewSize(1)).toBe(600);

// and the deficit from shrinking it
splitview.layout(800, 500);
expect(splitview.getViewSize(0)).toBe(400);
expect(splitview.getViewSize(1)).toBe(400);

splitview.dispose();
});

test('LayoutPriority.Fill takes precedence over High (High stays fixed)', () => {
const splitview = new Splitview(container, {
orientation: Orientation.HORIZONTAL,
proportionalLayout: true,
});

splitview.layout(1000, 500);

const high = new Testview(
50,
Number.POSITIVE_INFINITY,
LayoutPriority.High
);
const fill = new Testview(
50,
Number.POSITIVE_INFINITY,
LayoutPriority.Fill
);

splitview.addView(high); // index 0
splitview.addView(fill); // index 1

splitview.resizeView(0, 300);
expect(splitview.getViewSize(0)).toBe(300);
expect(splitview.getViewSize(1)).toBe(700);

// grow: the fill view absorbs everything even though `High` would
// normally be offered space first
splitview.layout(1200, 500);
expect(splitview.getViewSize(0)).toBe(300);
expect(splitview.getViewSize(1)).toBe(900);

splitview.dispose();
});

test('LayoutPriority.Fill works in a vertical splitview', () => {
const splitview = new Splitview(container, {
orientation: Orientation.VERTICAL,
proportionalLayout: true,
});

splitview.layout(1000, 500);

const side = new Testview(50, Number.POSITIVE_INFINITY);
const fill = new Testview(
50,
Number.POSITIVE_INFINITY,
LayoutPriority.Fill
);

splitview.addView(side); // index 0
splitview.addView(fill); // index 1

splitview.resizeView(0, 200);
expect(splitview.getViewSize(0)).toBe(200);
expect(splitview.getViewSize(1)).toBe(800);

splitview.layout(600, 500);
expect(splitview.getViewSize(0)).toBe(200);
expect(splitview.getViewSize(1)).toBe(400);

splitview.dispose();
});

test('vertical splitview', () => {
const splitview = new Splitview(container, {
orientation: Orientation.HORIZONTAL,
Expand Down
Loading
Loading