Skip to content

Commit eb2e152

Browse files
committed
fix(splitter): percentage min max constraints scenario
1 parent ddad5eb commit eb2e152

File tree

3 files changed

+130
-12
lines changed

3 files changed

+130
-12
lines changed

src/components/splitter/splitter.spec.ts

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -880,8 +880,7 @@ describe('Splitter', () => {
880880
expect(sizes.startSize + sizes.endSize).to.be.at.most(totalAvailable);
881881
});
882882

883-
// TODO: very broken scenario (same in Angular)
884-
xit('should honor minSize and maxSize constraints when resizing, constraints in %', async () => {
883+
it('should honor minSize and maxSize constraints when resizing, constraints in %', async () => {
885884
const constraintSplitter = await fixture<IgcSplitterComponent>(
886885
createTwoPanesWithSizesAndConstraints({
887886
startSize: '30%',
@@ -930,7 +929,7 @@ describe('Splitter', () => {
930929
});
931930

932931
describe('Vertical orientation', () => {
933-
it('should honor minSize and maxSize constraints when resizing - constraints in px', async () => {
932+
it('should honor minSize and maxSize constraints when resizing - constraints in px - vertical', async () => {
934933
const mixedConstraintSplitter = await fixture<IgcSplitterComponent>(
935934
createTwoPanesWithSizesAndConstraints({
936935
orientation: 'vertical',
@@ -967,6 +966,54 @@ describe('Splitter', () => {
967966
sizes = getPanesSizes(mixedConstraintSplitter, 'height');
968967
expect(sizes.endSize).to.equal(300);
969968
});
969+
970+
it('should honor minSize and maxSize constraints when resizing, constraints in % - vertical', async () => {
971+
const constraintSplitter = await fixture<IgcSplitterComponent>(
972+
createTwoPanesWithSizesAndConstraints({
973+
orientation: 'vertical',
974+
startSize: '30%',
975+
startMinSize: '10%',
976+
startMaxSize: '80%',
977+
endSize: '70%',
978+
endMinSize: '20%',
979+
endMaxSize: '90%',
980+
})
981+
);
982+
await elementUpdated(constraintSplitter);
983+
984+
const bar = getSplitterPart(constraintSplitter, 'bar');
985+
const barSize = bar.getBoundingClientRect().height;
986+
const totalAvailable = 500 - barSize;
987+
expect(totalAvailable).to.equal(495);
988+
989+
let deltaY = 1000;
990+
await resize(constraintSplitter, 0, deltaY);
991+
992+
let sizes = getPanesSizes(constraintSplitter, 'height');
993+
const expectedStartMax = Math.round((totalAvailable * 80) / 100);
994+
expect(sizes.startSize).to.be.closeTo(expectedStartMax, 2);
995+
996+
deltaY = -1000;
997+
await resize(constraintSplitter, 0, deltaY);
998+
999+
sizes = getPanesSizes(constraintSplitter, 'height');
1000+
const expectedStartMin = Math.round((totalAvailable * 10) / 100);
1001+
expect(sizes.startSize).to.be.closeTo(expectedStartMin, 2);
1002+
1003+
deltaY = 1000;
1004+
await resize(constraintSplitter, 0, deltaY);
1005+
1006+
sizes = getPanesSizes(constraintSplitter, 'height');
1007+
const expectedEndMin = Math.round((totalAvailable * 20) / 100);
1008+
expect(sizes.endSize).to.be.closeTo(expectedEndMin, 2);
1009+
1010+
deltaY = -1000;
1011+
await resize(constraintSplitter, 0, deltaY);
1012+
1013+
sizes = getPanesSizes(constraintSplitter, 'height');
1014+
const expectedEndMax = Math.round((totalAvailable * 90) / 100);
1015+
expect(sizes.endSize).to.be.closeTo(expectedEndMax, 2);
1016+
});
9701017
});
9711018

9721019
it('should result in % sizes after resize when the panes size is auto', () => {

src/components/splitter/splitter.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export interface IgcSplitterComponentEventMap {
3535
interface PaneResizeState {
3636
initialSize: number;
3737
isPercentageBased: boolean;
38+
minSizePx?: number;
39+
maxSizePx?: number;
3840
}
3941

4042
interface SplitterResizeState {
@@ -438,9 +440,35 @@ export default class IgcSplitterComponent extends EventEmitterMixin<
438440
return {
439441
initialSize: size,
440442
isPercentageBased: this._isPercentageSize(pane) || this._isAutoSize(pane),
443+
minSizePx: this._setMinMaxInPx(pane, 'min'),
444+
maxSizePx: this._setMinMaxInPx(pane, 'max'),
441445
};
442446
}
443447

448+
private _setMinMaxInPx(
449+
pane: 'start' | 'end',
450+
type: 'min' | 'max'
451+
): number | undefined {
452+
let value: string | undefined;
453+
if (type === 'max') {
454+
value = pane === 'start' ? this.startMaxSize : this.endMaxSize;
455+
} else {
456+
value = pane === 'start' ? this.startMinSize : this.endMinSize;
457+
}
458+
if (!value) {
459+
return undefined;
460+
}
461+
const totalSize = this.getTotalSize();
462+
let result: number;
463+
if (value.indexOf('%') !== -1) {
464+
const percentageValue = Number.parseInt(value ?? '0', 10) || 0;
465+
result = (percentageValue / 100) * totalSize;
466+
} else {
467+
result = Number.parseInt(value ?? '0', 10) || 0;
468+
}
469+
return result;
470+
}
471+
444472
private _resizing(delta: number) {
445473
let [paneSize, siblingSize] = this._calcNewSizes(delta);
446474
const totalSize = this.getTotalSize();
@@ -523,15 +551,15 @@ export default class IgcSplitterComponent extends EventEmitterMixin<
523551
if (!this._resizeState) return [0, 0];
524552

525553
let finalDelta: number;
526-
const min = Number.parseInt(this.startMinSize ?? '0', 10) || 0;
527-
const minSibling = Number.parseInt(this.endMinSize ?? '0', 10) || 0;
554+
const min = this._resizeState.startPane.minSizePx || 0;
555+
const minSibling = this._resizeState.endPane.minSizePx || 0;
528556
const max =
529-
Number.parseInt(this.startMaxSize ?? '0', 10) ||
557+
this._resizeState.startPane.maxSizePx ||
530558
this._resizeState.startPane.initialSize +
531559
this._resizeState.endPane.initialSize -
532560
minSibling;
533561
const maxSibling =
534-
Number.parseInt(this.endMaxSize ?? '0', 10) ||
562+
this._resizeState.endPane.maxSizePx ||
535563
this._resizeState.startPane.initialSize +
536564
this._resizeState.endPane.initialSize -
537565
min;

stories/splitter.stories.ts

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ interface IgcSplitterArgs {
103103

104104
type Story = StoryObj<IgcSplitterArgs>;
105105

106-
function changePaneMinMaxSizes() {
106+
function changePaneMinMaxSizesPx() {
107107
const splitter = document.querySelector('igc-splitter');
108108
if (!splitter) {
109109
return;
@@ -114,6 +114,19 @@ function changePaneMinMaxSizes() {
114114
splitter.endMaxSize = '300px';
115115
}
116116

117+
function changePaneMinMaxSizesPercent() {
118+
const splitter = document.querySelector('igc-splitter');
119+
if (!splitter) {
120+
return;
121+
}
122+
splitter.startMinSize = '10%';
123+
splitter.startMaxSize = '80%';
124+
splitter.endMinSize = '20%';
125+
splitter.endMaxSize = '90%';
126+
splitter.startSize = '30%';
127+
splitter.endSize = '70%';
128+
}
129+
117130
export const Default: Story = {
118131
render: ({
119132
orientation,
@@ -135,6 +148,7 @@ export const Default: Story = {
135148
136149
.splitters {
137150
height: 400px;
151+
/*width: 1000px;*/ /* useful for testing % values */
138152
}
139153
</style>
140154
@@ -152,15 +166,44 @@ export const Default: Story = {
152166
.endMinSize=${endMinSize}
153167
.endMaxSize=${endMaxSize}
154168
>
155-
<div slot="start" class="pane-content">Pane 1</div>
156-
<div slot="end" class="pane-content">Pane 2</div>
169+
<div slot="start" class="pane-content">
170+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque
171+
scelerisque elementum ante, et tincidunt eros ultrices sit amet.
172+
Mauris non consectetur nunc. In hac habitasse platea dictumst.
173+
Pellentesque ornare et tellus sit amet varius. Nulla in augue rhoncus,
174+
finibus mauris semper, tincidunt sem. Cras vitae semper neque, eget
175+
tempus massa. Maecenas gravida turpis quis interdum bibendum. Nam quis
176+
ultricies est. Fusce ante erat, iaculis quis iaculis ut, iaculis sed
177+
nunc. Cras iaculis condimentum lacus nec tempus. Nam ex massa, mattis
178+
vitae iaculis in, suscipit ut nibh.
179+
</div>
180+
<div slot="end" class="pane-content">
181+
Maecenas sit amet ipsum non ipsum scelerisque varius. Maecenas
182+
scelerisque nisl scelerisque nulla ultricies eleifend. Aliquam sit
183+
amet velit mauris. Duis at nulla vitae risus condimentum semper. Nam
184+
ornare arcu vitae euismod pharetra. Morbi facilisis tincidunt lorem at
185+
consequat. Aliquam varius quam non eros suscipit, ac tincidunt sapien
186+
porttitor. Sed sed lorem quam. Praesent blandit aliquam arcu a
187+
vestibulum. Mauris porta faucibus ex in vehicula. Pellentesque ut
188+
risus quis felis molestie facilisis eget et est. Proin interdum urna
189+
vitae porttitor suscipit. Curabitur lobortis aliquet dolor sit amet
190+
varius. Proin a semper velit, non molestie libero. Suspendisse
191+
potenti. Aliquam vestibulum dui id lacus suscipit, eget posuere justo
192+
venenatis. Vestibulum id velit ac dui posuere pretium.
193+
</div>
157194
</igc-splitter>
158195
</div>
159196
<igc-button
160197
style="margin-top: 16px;"
161198
variant="outlined"
162-
@click=${changePaneMinMaxSizes}
163-
>Change All Panes Min/Max Sizes</igc-button
199+
@click=${changePaneMinMaxSizesPx}
200+
>Change All Panes Min/Max Sizes (px)</igc-button
201+
>
202+
<igc-button
203+
style="margin-top: 16px;"
204+
variant="outlined"
205+
@click=${changePaneMinMaxSizesPercent}
206+
>Change All Panes Min/Max Sizes (%)</igc-button
164207
>
165208
`,
166209
};

0 commit comments

Comments
 (0)