From 1cd0ba2c9e4859a2e78bb892515bcbecfb47de50 Mon Sep 17 00:00:00 2001 From: pharret31 Date: Wed, 11 Mar 2026 11:06:23 +0100 Subject: [PATCH 1/3] fix --- .../js/__internal/ui/splitter/splitter.ts | 5 +- .../DevExpress.ui.widgets/splitter.tests.js | 73 ++++++++++++++++++- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/packages/devextreme/js/__internal/ui/splitter/splitter.ts b/packages/devextreme/js/__internal/ui/splitter/splitter.ts index 2ca1c018760d..108e440ef6d2 100644 --- a/packages/devextreme/js/__internal/ui/splitter/splitter.ts +++ b/packages/devextreme/js/__internal/ui/splitter/splitter.ts @@ -1100,9 +1100,10 @@ class Splitter extends CollectionWidgetLiveUpdate { } _dimensionChanged(): void { - this._updateItemSizes(); - this._layout = this._getDefaultLayoutBasedOnSize(); + this._applyStylesFromLayout(this._layout); + + this._updateItemSizes(); } _optionChanged(args: OptionChanged): void { diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/splitter.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/splitter.tests.js index 752166f71b94..1dda0867b6b2 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/splitter.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/splitter.tests.js @@ -1973,8 +1973,8 @@ QUnit.module('Resizing', moduleConfig, () => { this.instance.option(orientation === 'horizontal' ? 'width' : 'height', 700); - this.checkItemSizes([159.133, 159.133, 159.133, 204.602]); - this.assertLayout([23.3333, 23.3333, 23.3333, 30]); + this.checkItemSizes([0, 166.664, 215.336, 300]); + this.assertLayout([0, 24.4375, 31.5742, 43.9883]); }); }); @@ -2822,6 +2822,75 @@ QUnit.module('Resizing', moduleConfig, () => { this.assertLayout(['15', '10', '25', '50']); }); + + [{ + initialWidth: 408, + newWidth: 808, + dataSource: [{ size: '200px', maxSize: '200px' }, { }], + expectedLayout: ['25', '75'], + expectedItemSizes: [200, 600], + }, { + initialWidth: 408, + newWidth: 808, + dataSource: [{ }, { size: '200px', maxSize: '200px' }], + expectedLayout: ['75', '25'], + expectedItemSizes: [600, 200], + }, { + initialWidth: 808, + newWidth: 408, + dataSource: [{ size: '200px', minSize: '200px' }, { }], + expectedLayout: ['50', '50'], + expectedItemSizes: [200, 200], + }, { + initialWidth: 808, + newWidth: 408, + dataSource: [{ }, { size: '200px', minSize: '200px' }], + expectedLayout: ['50', '50'], + expectedItemSizes: [200, 200], + }, { + initialWidth: 416, + newWidth: 816, + dataSource: [{ size: '200px', maxSize: '200px' }, { }, { }], + expectedLayout: ['25', '12.5', '62.5'], + expectedItemSizes: [200, 100, 500], + }, { + initialWidth: 816, + newWidth: 416, + dataSource: [{ size: '200px', minSize: '200px' }, { }, { }], + expectedLayout: ['50', '50', '0'], + expectedItemSizes: [200, 200, 0], + }, { + initialWidth: 416, + newWidth: 816, + dataSource: [{ }, { size: '200px', maxSize: '200px' }, { }], + expectedLayout: ['12.5', '25', '62.5'], + expectedItemSizes: [100, 200, 500], + }, { + initialWidth: 416, + newWidth: 816, + dataSource: [{ size: '200px', minSize: '100px', maxSize: '300px' }, { }], + expectedLayout: ['24.7525', '75.2475'], + expectedItemSizes: [200, 608], + }, { + initialWidth: 208, + newWidth: 808, + dataSource: [{ size: '100px', maxSize: '200px' }, { }], + expectedLayout: ['12.5', '87.5'], + expectedItemSizes: [100, 700], + }].forEach(({ initialWidth, newWidth, dataSource, expectedLayout, expectedItemSizes }) => { + QUnit.test(`pane constraints should be respected after dimension change from ${initialWidth} to ${newWidth}, dataSource: ${JSON.stringify(dataSource)}`, function(assert) { + this.reinit({ + width: initialWidth, + height: 408, + dataSource, + }); + + this.instance.option('width', newWidth); + + this.checkItemSizes(expectedItemSizes); + this.assertLayout(expectedLayout); + }); + }); }); QUnit.module('Initialization', moduleConfig, () => { From 981b2ca8706cb405dbc48255153be309d7c85fff Mon Sep 17 00:00:00 2001 From: pharret31 Date: Wed, 11 Mar 2026 12:15:11 +0100 Subject: [PATCH 2/3] fix e2e --- ...ane_1.size=`100px` (fluent.blue.light).png | Bin 6339 -> 6323 bytes .../tests/navigation/splitter/resize.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/testcafe-devextreme/tests/navigation/splitter/etalons/Splitter in tab content after window resize, pane_1.size=`100px` (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/navigation/splitter/etalons/Splitter in tab content after window resize, pane_1.size=`100px` (fluent.blue.light).png index 2501aa486c75cae8fbc14075fbac117079d6b120..c9bd3743a9238b9f65b8fa8aef4bf22c3f49f707 100644 GIT binary patch literal 6323 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 Fe*-R;r9c1x literal 6339 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 Wg)tU>N&PE91JcyLU#aov+1~&ermZXh diff --git a/e2e/testcafe-devextreme/tests/navigation/splitter/resize.ts b/e2e/testcafe-devextreme/tests/navigation/splitter/resize.ts index 7a43afce5754..815ad3d42da2 100644 --- a/e2e/testcafe-devextreme/tests/navigation/splitter/resize.ts +++ b/e2e/testcafe-devextreme/tests/navigation/splitter/resize.ts @@ -16,7 +16,7 @@ test.meta({ browserSize: [800, 800] })('non resizable pane should not change its await t .expect(splitter.getItem(2).element.clientWidth) - .eql(145); + .eql(300); }).before(async () => createWidget('dxSplitter', { width: '100%', height: 300, From cac954de0a1b6263fcf5f7d6574866c5128b51c3 Mon Sep 17 00:00:00 2001 From: pharret31 Date: Wed, 18 Mar 2026 12:13:11 +0100 Subject: [PATCH 3/3] test --- .../js/__internal/ui/splitter/splitter.ts | 186 +++++++++++++++++- .../DevExpress.ui.widgets/splitter.tests.js | 77 ++++++-- 2 files changed, 244 insertions(+), 19 deletions(-) diff --git a/packages/devextreme/js/__internal/ui/splitter/splitter.ts b/packages/devextreme/js/__internal/ui/splitter/splitter.ts index 108e440ef6d2..6d994b9e65b6 100644 --- a/packages/devextreme/js/__internal/ui/splitter/splitter.ts +++ b/packages/devextreme/js/__internal/ui/splitter/splitter.ts @@ -53,10 +53,12 @@ import { findIndexOfNextVisibleItem, findLastIndexOfNonCollapsedItem, findLastIndexOfVisibleItem, + findLastVisibleExpandedItemIndex, getElementSize, getNextLayout, isElementVisible, setFlexProp, + tryConvertToNumber, } from './utils/layout'; import { getDefaultLayout } from './utils/layout_default'; import { compareNumbersWithPrecision } from './utils/number_comparison'; @@ -128,12 +130,16 @@ class Splitter extends CollectionWidgetLiveUpdate { private _layout?: number[]; + private _idealLayout?: number[]; + private _currentLayout?: number[]; private _activeResizeHandleIndex?: number; private _collapseDirection?: CollapseExpandDirection; + private _initialPaneSizes: (string | number | undefined)[] = []; + private _itemRestrictions: PaneRestrictions[] = []; private _currentOnePxRatio?: number; @@ -236,13 +242,20 @@ class Splitter extends CollectionWidgetLiveUpdate { } _resizeHandler(): void { - if (this._shouldRecalculateLayout && this._isAttached() && this._isVisible()) { + if (!this._isAttached() || !this._isVisible()) { + return; + } + + if (this._shouldRecalculateLayout) { this._layout = this._getDefaultLayoutBasedOnSize(); + this._idealLayout = this._layout; this._applyStylesFromLayout(this._layout); this._updateItemSizes(); this._shouldRecalculateLayout = false; + } else { + this._dimensionChanged(); } } @@ -252,8 +265,11 @@ class Splitter extends CollectionWidgetLiveUpdate { this._updateResizeHandlesResizableState(); this._updateResizeHandlesCollapsibleState(); + this._initialPaneSizes = items.map((item: Item): string | number | undefined => item.size); + if (this._isVisible()) { this._layout = this._getDefaultLayoutBasedOnSize(); + this._idealLayout = this._layout; this._applyStylesFromLayout(this._layout); this._updateItemSizes(); @@ -537,6 +553,7 @@ class Splitter extends CollectionWidgetLiveUpdate { this._applyStylesFromLayout(newLayout); this._layout = newLayout; + this._idealLayout = newLayout; }, onResizeEnd: (e: ResizeEndEvent): void => { const { element, event } = e; @@ -663,6 +680,7 @@ class Splitter extends CollectionWidgetLiveUpdate { switch (property) { case 'size': this._layout = this._getDefaultLayoutBasedOnSize(item); + this._idealLayout = this._layout; this._applyStylesFromLayout(this.getLayout()); this._updateItemSizes(); @@ -671,6 +689,7 @@ class Splitter extends CollectionWidgetLiveUpdate { case 'minSize': case 'collapsedSize': this._layout = this._getDefaultLayoutBasedOnSize(); + this._idealLayout = this._layout; this._applyStylesFromLayout(this.getLayout()); this._updateItemSizes(); @@ -737,6 +756,7 @@ class Splitter extends CollectionWidgetLiveUpdate { paneIndex, this._itemRestrictions, ); + this._idealLayout = this._layout; this._applyStylesFromLayout(this.getLayout()); this._updateItemSizes(); @@ -859,6 +879,7 @@ class Splitter extends CollectionWidgetLiveUpdate { this._activeResizeHandleIndex, this._itemRestrictions, ); + this._idealLayout = this._layout; this._applyStylesFromLayout(this.getLayout()); this._updateItemSizes(); @@ -1100,12 +1121,171 @@ class Splitter extends CollectionWidgetLiveUpdate { } _dimensionChanged(): void { - this._layout = this._getDefaultLayoutBasedOnSize(); - this._applyStylesFromLayout(this._layout); + const idealLayout = this._idealLayout; + + if (!idealLayout || idealLayout.length === 0) { + return; + } + + const { orientation, items = [] } = this.option(); + const elementSize = getElementSize(this.$element(), orientation); + const handlesSize = this._getResizeHandlesSize(); + const availableSize = Math.max(0, elementSize - handlesSize); + + if (availableSize <= 0) { + this._layout = idealLayout.map((): number => 0); + this._applyStylesFromLayout(this._layout); + this._updateItemSizes(); + return; + } + + const idealPixels = idealLayout.map((ratio: number): number => (ratio / 100) * availableSize); + let remaining = 0; + const newPixels = idealPixels.map((px: number, index: number): number => { + const item = items[index]; + + if (!item || item.visible === false) { + remaining += px; + return 0; + } + + if (item.collapsed === true) { + const collapsedPx = tryConvertToNumber(item.collapsedSize, elementSize) ?? 0; + remaining += px - collapsedPx; + return collapsedPx; + } + + if (item.resizable === false) { + const originalSize = this._initialPaneSizes[index]; + + if (isDefined(originalSize)) { + const fixedPx = tryConvertToNumber(originalSize, elementSize) ?? px; + remaining += px - fixedPx; + return fixedPx; + } + } + + const minPx = tryConvertToNumber(item.minSize, elementSize) ?? 0; + const maxPx = tryConvertToNumber(item.maxSize, elementSize); + const clampedPx = this._getClampedPixelSize(px, minPx, maxPx); + + remaining += px - clampedPx; + return clampedPx; + }); + + this._distributeRemainingPixels(newPixels, remaining); + + this._layout = newPixels.map((px: number): number => (px / availableSize) * 100); + this._applyStylesFromLayout(this._layout); this._updateItemSizes(); } + _getEligiblePaneIndices( + pixels: number[], + remaining: number, + ): number[] { + const { items = [], orientation } = this.option(); + const elementSize = getElementSize(this.$element(), orientation); + const indices: number[] = []; + const direction = remaining > 0 ? 1 : -1; + + for (let index = 0; index < pixels.length; index += 1) { + const item = items[index]; + + if (!item || item.visible === false || item.collapsed === true + || (item.resizable === false && isDefined(this._initialPaneSizes[index]))) { + // skip + } else { + const minPx = tryConvertToNumber(item.minSize, elementSize) ?? 0; + const maxPx = tryConvertToNumber(item.maxSize, elementSize); + const clampedPx = this._getClampedPixelSize(pixels[index] + direction, minPx, maxPx); + + if (compareNumbersWithPrecision(clampedPx, pixels[index]) !== 0) { + indices.push(index); + } + } + } + + return indices; + } + + _distributeRemainingPixels( + pixels: number[], + initialRemaining: number, + ): void { + const { items = [] } = this.option(); + + let remaining = initialRemaining; + + while (compareNumbersWithPrecision(remaining, 0) !== 0) { + const eligiblePaneIndices = this._getEligiblePaneIndices(pixels, remaining); + + if (eligiblePaneIndices.length === 0) { + const fallback = findLastVisibleExpandedItemIndex(items); + + if (fallback !== -1) { + pixels[fallback] += remaining; + } + break; + } + + const share = remaining / eligiblePaneIndices.length; + const result = this._applyPixelShare(pixels, eligiblePaneIndices, share); + + remaining -= result.applied; + + if (!result.distributed) { + break; + } + } + } + + _applyPixelShare( + pixels: number[], + eligiblePaneIndices: number[], + share: number, + ): { applied: number; distributed: boolean } { + const { items = [], orientation } = this.option(); + const elementSize = getElementSize(this.$element(), orientation); + let applied = 0; + let distributed = false; + + eligiblePaneIndices.forEach((index: number): void => { + const item = items[index]; + const prev = pixels[index]; + const next = prev + share; + + const minPx = tryConvertToNumber(item?.minSize, elementSize) ?? 0; + const maxPx = tryConvertToNumber(item?.maxSize, elementSize); + const clampedPx = this._getClampedPixelSize(next, minPx, maxPx); + + const delta = clampedPx - prev; + + if (compareNumbersWithPrecision(delta, 0) !== 0) { + pixels[index] = clampedPx; + applied += delta; + distributed = true; + } + }); + + return { applied, distributed }; + } + + _getClampedPixelSize( + size: number, + minPx: number, + maxPx: number | undefined, + ): number { + let result = Math.max(size, minPx); + + if (isDefined(maxPx)) { + result = Math.min(result, maxPx); + } + + return result; + } + _optionChanged(args: OptionChanged): void { const { name, value } = args; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/splitter.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/splitter.tests.js index 1dda0867b6b2..f804e165d25c 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/splitter.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/splitter.tests.js @@ -1963,18 +1963,18 @@ QUnit.module('Resizing', moduleConfig, () => { }); }); - QUnit.test(`non resizable panes shouldn't change their sizes after update splitter dimension, ${orientation} orientation`, function(assert) { + QUnit.test(`non resizable panes with restrictions shouldn't change their sizes after update splitter dimension, ${orientation} orientation`, function(assert) { this.reinit({ width: 1018, height: 1018, - dataSource: [{ }, { }, { }, { resizable: false, size: '300px' }], + dataSource: [{ }, { }, { }, { resizable: false, minSize: '300px', maxSize: '300px' }], orientation, }); this.instance.option(orientation === 'horizontal' ? 'width' : 'height', 700); - this.checkItemSizes([0, 166.664, 215.336, 300]); - this.assertLayout([0, 24.4375, 31.5742, 43.9883]); + this.checkItemSizes([104.602, 138.695, 138.703, 300]); + this.assertLayout(['15.3372', '20.3372', '20.3372', '43.9883']); }); }); @@ -2851,32 +2851,32 @@ QUnit.module('Resizing', moduleConfig, () => { initialWidth: 416, newWidth: 816, dataSource: [{ size: '200px', maxSize: '200px' }, { }, { }], - expectedLayout: ['25', '12.5', '62.5'], - expectedItemSizes: [200, 100, 500], + expectedLayout: ['25', '37.5', '37.5'], + expectedItemSizes: [200, 300, 300], }, { initialWidth: 816, newWidth: 416, dataSource: [{ size: '200px', minSize: '200px' }, { }, { }], - expectedLayout: ['50', '50', '0'], - expectedItemSizes: [200, 200, 0], + expectedLayout: ['50', '25', '25'], + expectedItemSizes: [200, 100, 100], }, { initialWidth: 416, newWidth: 816, dataSource: [{ }, { size: '200px', maxSize: '200px' }, { }], - expectedLayout: ['12.5', '25', '62.5'], - expectedItemSizes: [100, 200, 500], + expectedLayout: ['37.5', '25', '37.5'], + expectedItemSizes: [300, 200, 300], }, { - initialWidth: 416, - newWidth: 816, + initialWidth: 408, + newWidth: 808, dataSource: [{ size: '200px', minSize: '100px', maxSize: '300px' }, { }], - expectedLayout: ['24.7525', '75.2475'], - expectedItemSizes: [200, 608], + expectedLayout: ['37.5', '62.5'], + expectedItemSizes: [300, 500], }, { initialWidth: 208, newWidth: 808, dataSource: [{ size: '100px', maxSize: '200px' }, { }], - expectedLayout: ['12.5', '87.5'], - expectedItemSizes: [100, 700], + expectedLayout: ['25', '75'], + expectedItemSizes: [200, 600], }].forEach(({ initialWidth, newWidth, dataSource, expectedLayout, expectedItemSizes }) => { QUnit.test(`pane constraints should be respected after dimension change from ${initialWidth} to ${newWidth}, dataSource: ${JSON.stringify(dataSource)}`, function(assert) { this.reinit({ @@ -2891,6 +2891,51 @@ QUnit.module('Resizing', moduleConfig, () => { this.assertLayout(expectedLayout); }); }); + + QUnit.test('layout should be restored after shrinking and expanding back', function(assert) { + this.reinit({ + width: 416, + height: 408, + dataSource: [{ }, { }, { }], + }); + + this.assertLayout(['33.3333', '33.3333', '33.3333']); + + this.instance.option('width', 40); + this.instance.option('width', 416); + + this.assertLayout(['33.3333', '33.3333', '33.3333']); + }); + + QUnit.test('layout should be restored after shrinking and expanding with minSize', function(assert) { + this.reinit({ + width: 416, + height: 408, + dataSource: [{ minSize: '100px' }, { }, { }], + }); + + this.assertLayout(['33.3333', '33.3333', '33.3333']); + + this.instance.option('width', 40); + this.instance.option('width', 416); + + this.assertLayout(['33.3333', '33.3333', '33.3333']); + }); + + QUnit.test('layout should be restored after shrinking and expanding with maxSize', function(assert) { + this.reinit({ + width: 816, + height: 408, + dataSource: [{ size: '200px', maxSize: '200px' }, { }, { }], + }); + + this.assertLayout(['25', '37.5', '37.5']); + + this.instance.option('width', 40); + this.instance.option('width', 816); + + this.assertLayout(['25', '37.5', '37.5']); + }); }); QUnit.module('Initialization', moduleConfig, () => {