Skip to content
Merged
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## [Unreleased]

### Added

- **SplitLayout**: Added `handlePosition` property to adjust the handle position programmatically.
- **SplitLayout**: Added `fixedPane` property. When the parent element is resized, the panes adjust proportionally.
This parameter allows you to set one of the panes to a fixed size so its dimensions won’t change during resizing.
- **SplitLayout**: Added `resetHandlePosition()` method to reset the handle position to the default value.
- **SplitLayout**: Dispatch `vsc-split-layout-change` event when a panel is resized.

### Fixed

- **SingleSelect**, **MultiSelect**: Fix the widget height when it is empty.
Expand Down
23 changes: 18 additions & 5 deletions src/vscode-split-layout/vscode-split-layout.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ const styles: CSSResultGroup = [

.start {
box-sizing: border-box;
flex-shrink: 0;
width: 100%;
flex: 1;
min-height: 0;
min-width: 0;
}

:host([split='vertical']) .start {
Expand All @@ -47,7 +48,18 @@ const styles: CSSResultGroup = [
}

.end {
flex-shrink: 0;
flex: 1;
min-height: 0;
min-width: 0;
}

:host([split='vertical']) .start,
:host([split='vertical']) .end {
height: 100%;
}

:host([split='horizontal']) .start,
:host([split='horizontal']) .end {
width: 100%;
}

Expand All @@ -74,18 +86,19 @@ const styles: CSSResultGroup = [
}

.handle {
background-color: transparent;
position: absolute;
z-index: 2;
}

.handle.hover {
transition: background-color 0.1s ease-out 0.3s;
background-color: var(--vscode-sash-hoverBorder);
transition: background-color 100ms linear 300ms;
}

.handle.hide {
background-color: transparent;
transition: background-color 100ms linear;
transition: background-color 0.1s ease-out;
}

.handle.split-vertical {
Expand Down
193 changes: 158 additions & 35 deletions src/vscode-split-layout/vscode-split-layout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ describe('vscode-split-layout', () => {
expect(el).to.instanceOf(VscodeSplitLayout);
});

it('default values', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout></vscode-split-layout>`
);

expect(el.split).to.eq('vertical');
expect(el.resetOnDblClick).to.be.false;
expect(el.handleSize).to.eq(4);
expect(el.initialHandlePosition).to.eq('50%');
expect(el.fixedPane).to.eq('none');
});

describe('helper functions', () => {
it('should parse percentage value correctly', () => {
expect(parseValue('50%')).to.deep.equal({unit: 'percent', value: 50});
Expand Down Expand Up @@ -75,46 +87,152 @@ describe('vscode-split-layout', () => {
});

describe('when provided parameters', () => {
it('should adjust the handle vertical', async () => {
it('should handle position set correctly when the divider orientation is vertical, and the position is specified in pixels', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout
style="width: 500px; height: 500px;"
initial-handle-position="50%"
handle-position="50%"
handle-size="4"
split="vertical"
handle-position="100px"
></vscode-split-layout>`
);

const handle = el.shadowRoot!.querySelector('.handle') as HTMLDivElement;

expect(handle.offsetLeft).to.eq(98);
expect(handle.offsetTop).to.eq(0);
});

it('should handle position set correctly when the divider orientation is vertical, and the position is specified in percent', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout
style="width: 500px; height: 500px;"
handle-position="20%"
></vscode-split-layout>`
);

const handle = el.shadowRoot!.querySelector('.handle') as HTMLDivElement;

expect(handle.style.left).to.eq('50%');
expect(handle.style.top).to.eq('0px');
expect(handle.offsetLeft).to.eq(98);
expect(handle.offsetTop).to.eq(0);
});

it('should adjust the handle horizontal', async () => {
it('should handle position set correctly when the divider orientation is horizontal, and the position is specified in pixels', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout
style="width: 500px; height: 500px;"
initial-handle-position="50%"
handle-position="50%"
handle-size="4"
handle-position="100px"
split="horizontal"
></vscode-split-layout>`
);

const handle = el.shadowRoot!.querySelector('.handle') as HTMLDivElement;

expect(handle.style.left).to.eq('0px');
expect(handle.style.top).to.eq('50%');
expect(handle.offsetLeft).to.eq(0);
expect(handle.offsetTop).to.eq(98);
});

it('should handle position set correctly when the divider orientation is horizontal, and the position is specified in percent', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout
style="width: 500px; height: 500px;"
handle-position="20%"
split="horizontal"
></vscode-split-layout>`
);

const handle = el.shadowRoot!.querySelector('.handle') as HTMLDivElement;

expect(handle.offsetLeft).to.eq(0);
expect(handle.offsetTop).to.eq(98);
});

it('should set handle size in vertical split mode', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout
style="width: 500px; height: 500px;"
handle-size="20"
></vscode-split-layout>`
);
const handle = el.shadowRoot?.querySelector('.handle') as HTMLDivElement;

expect(handle.offsetWidth).to.eq(20);
expect(handle.offsetLeft).to.eq(240);
});

it('should set handle size in horizontal split mode', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout
style="width: 500px; height: 500px;"
handle-size="20"
split="horizontal"
></vscode-split-layout>`
);
const handle = el.shadowRoot?.querySelector('.handle') as HTMLDivElement;

expect(handle.offsetHeight).to.eq(20);
expect(handle.offsetTop).to.eq(240);
});

it('should change divider orientation from vertical to horizontal correctly', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout
style="width: 500px; height: 500px;"
initial-handle-position="20%"
></vscode-split-layout>`
);

const startWidthBefore =
el.shadowRoot?.querySelector<HTMLDivElement>('.start')!.offsetWidth;
const endWidthBefore =
el.shadowRoot?.querySelector<HTMLDivElement>('.end')!.offsetWidth;

el.split = 'horizontal';
await el.updateComplete;

const startHeightAfter =
el.shadowRoot?.querySelector<HTMLDivElement>('.start')!.offsetHeight;
const endHeightAfter =
el.shadowRoot?.querySelector<HTMLDivElement>('.end')!.offsetHeight;

expect(startWidthBefore).to.eq(100);
expect(endWidthBefore).to.eq(400);
expect(startHeightAfter).to.eq(100);
expect(endHeightAfter).to.eq(400);
});

it('should change divider orientation from horizontal to vertical correctly', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout
style="width: 500px; height: 500px;"
initial-handle-position="20%"
split="horizontal"
></vscode-split-layout>`
);

const startHeightBefore =
el.shadowRoot?.querySelector<HTMLDivElement>('.start')!.offsetHeight;
const endHeightBefore =
el.shadowRoot?.querySelector<HTMLDivElement>('.end')!.offsetHeight;

el.split = 'vertical';
await el.updateComplete;

const startWidthAfter =
el.shadowRoot?.querySelector<HTMLDivElement>('.start')!.offsetWidth;
const endWidthAfter =
el.shadowRoot?.querySelector<HTMLDivElement>('.end')!.offsetWidth;

expect(startHeightBefore).to.eq(100);
expect(endHeightBefore).to.eq(400);
expect(startWidthAfter).to.eq(100);
expect(endWidthAfter).to.eq(400);
});
});

describe('user interactions', () => {
it('should panes resize in vertical mode', async () => {
const el = await fixture<VscodeSplitLayout>(
html`<vscode-split-layout
style="width: 500px; height: 500px;"
style="width: 500px; height: 500px;border: 0;"
initial-handle-position="100px"
></vscode-split-layout>`
);
Expand All @@ -125,18 +243,17 @@ describe('vscode-split-layout', () => {
) as HTMLDivElement;
const paneEnd = el.shadowRoot?.querySelector('.end') as HTMLDivElement;

expect(handle).not.to.be.null;
expect(handle.style.left).to.eq('20%');
expect(handle.style.top).to.eq('0px');
expect(paneStart.style.width).to.eq('20%');
expect(paneEnd.style.width).to.eq('80%');
expect(paneStart.offsetWidth, 'start pane width before resizing').to.eq(
100
);
expect(paneEnd.offsetWidth, 'end pane width before resizing').to.eq(400);

await dragElement(handle, 100);

expect(paneStart.style.width).to.eq('40%');
expect(paneEnd.style.width).to.eq('60%');
expect(handle.style.left).to.eq('40%');
expect(handle.style.top).to.eq('0px');
expect(paneStart.offsetWidth, 'start pane width after resizing').to.eq(
200
);
expect(paneEnd.offsetWidth, 'end pane width after resizing').to.eq(300);
});

it('should panes resize in horizontal mode', async () => {
Expand All @@ -149,15 +266,24 @@ describe('vscode-split-layout', () => {
);

const handle = el.shadowRoot?.querySelector('.handle') as HTMLDivElement;
const paneStart = el.shadowRoot?.querySelector(
'.start'
) as HTMLDivElement;
const paneEnd = el.shadowRoot?.querySelector('.end') as HTMLDivElement;

expect(handle).not.to.be.null;
expect(handle.style.left).to.eq('0px');
expect(handle.style.top).to.eq('20%');
expect(paneStart.offsetHeight, 'start pane height before resizing').to.eq(
100
);
expect(paneEnd.offsetHeight, 'end pane height before resizing').to.eq(
400
);

await dragElement(handle, 0, 100);

expect(handle.style.left).to.eq('0px');
expect(handle.style.top).to.eq('40%');
expect(paneStart.offsetHeight, 'start pane height after resizing').to.eq(
200
);
expect(paneEnd.offsetHeight, 'end pane height after resizing').to.eq(300);
});

it('should dispatch "vsc-split-layout-change" event when handle position is changed', async () => {
Expand Down Expand Up @@ -207,17 +333,14 @@ describe('vscode-split-layout', () => {
expect(revertedHandlePos).to.eq('20%');
});

it('should not reset handle position on double click when "reset-on-dbl-click" is unset');
it(
'should not reset handle position on double click when "reset-on-dbl-click" is unset'
);
});

// TODO
it('should set vertical handle size');
it('should set horizontal handle size');
it('should change divider orientation from vertical to horizontal');
it('should change divider orientation from horizontal to vertical');
it('should set fixed start panel');
it('should set fixed end panel');
it('should set handle position programmatically when divider orientation is vertical');
it('should set handle position programmatically when divider orientation is horizontal');
it('should reset to the default position programmatically');
it('should nested instances reset when slotted content is changed');
});
Loading