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
82 changes: 69 additions & 13 deletions packages/devextreme/js/__internal/ui/splitter/splitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ import {
type RenderQueueItem,
} from './utils/types';

const SPLITTER_CLASS = 'dx-splitter';
const SPLITTER_ITEM_CLASS = 'dx-splitter-item';
const SPLITTER_ITEM_HIDDEN_CONTENT_CLASS = 'dx-splitter-item-hidden-content';
export const SPLITTER_CLASS = 'dx-splitter';
export const SPLITTER_ITEM_CLASS = 'dx-splitter-item';
export const SPLITTER_ITEM_HIDDEN_CONTENT_CLASS = 'dx-splitter-item-hidden-content';
export const INVISIBLE_STATE_CLASS = 'dx-state-invisible';
const SPLITTER_ITEM_DATA_KEY = 'dxSplitterItemData';
const HORIZONTAL_ORIENTATION_CLASS = 'dx-splitter-horizontal';
const VERTICAL_ORIENTATION_CLASS = 'dx-splitter-vertical';
const INVISIBLE_STATE_CLASS = 'dx-state-invisible';

const DEFAULT_RESIZE_HANDLE_SIZE = 8;

Expand All @@ -93,6 +93,10 @@ const ORIENTATION: Record<string, Orientation> = {
vertical: 'vertical',
};

type InternalSplitterItem = Item & {
_initialSizeBeforeCollapse?: Item['size'];
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ItemLike<TKey> = string | Item<TKey> | any;

Expand Down Expand Up @@ -235,6 +239,18 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
return isElementVisible($(this.element())[0]);
}

_captureInitialCollapsedItemSizes(items: InternalSplitterItem[]): void {
items.forEach((item) => {
if (
item._initialSizeBeforeCollapse === undefined
&& item.collapsed === true
&& isDefined(item.size)
) {
item._initialSizeBeforeCollapse = item.size;
}
});
}

_resizeHandler(): void {
if (this._shouldRecalculateLayout && this._isAttached() && this._isVisible()) {
this._layout = this._getDefaultLayoutBasedOnSize();
Expand All @@ -249,6 +265,8 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
_renderItems(items: Item[]): void {
super._renderItems(items);

this._captureInitialCollapsedItemSizes(items);

this._updateResizeHandlesResizableState();
this._updateResizeHandlesCollapsibleState();

Expand Down Expand Up @@ -662,6 +680,12 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
): void {
switch (property) {
case 'size':

if (item.collapsed) {
// @ts-expect-error
item._initialSizeBeforeCollapse = value;
}

this._layout = this._getDefaultLayoutBasedOnSize(item);

this._applyStylesFromLayout(this.getLayout());
Expand Down Expand Up @@ -900,6 +924,40 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
return 0;
}

_getTargetPaneSize(
paneCache: PaneCache | undefined,
direction: CollapseExpandDirection | undefined,
collapsedSize: number,
item: InternalSplitterItem,
itemIndex: number,
): number {
if (paneCache && paneCache.direction === direction) {
return paneCache.size - collapsedSize;
}

if (!isDefined(item._initialSizeBeforeCollapse)) {
return direction === CollapseExpandDirection.Previous
? this._calculateExpandToLeftSize(itemIndex - 1)
: this._calculateExpandToRightSize(itemIndex + 1);
}

const sizeRatio = convertSizeToRatio(
item._initialSizeBeforeCollapse,
getElementSize($(this.element()), this.option().orientation),
this._getResizeHandlesSize(),
);

item._initialSizeBeforeCollapse = undefined;

if (!isDefined(sizeRatio)) {
return direction === CollapseExpandDirection.Previous
? this._calculateExpandToLeftSize(itemIndex - 1)
: this._calculateExpandToRightSize(itemIndex + 1);
}

return sizeRatio - collapsedSize;
}

_getCollapseDelta(
item: Item,
newCollapsedState: boolean | undefined,
Expand Down Expand Up @@ -934,15 +992,13 @@ class Splitter extends CollectionWidgetLiveUpdate<Properties> {
const paneCache = panesCacheSize[itemIndex];
panesCacheSize[itemIndex] = undefined;

let targetPaneSize = 0;

if (paneCache && paneCache.direction === direction) {
targetPaneSize = paneCache.size - collapsedSize;
} else {
targetPaneSize = direction === CollapseExpandDirection.Previous
? this._calculateExpandToLeftSize(itemIndex - 1)
: this._calculateExpandToRightSize(itemIndex + 1);
}
const targetPaneSize = this._getTargetPaneSize(
paneCache,
direction,
collapsedSize,
item,
itemIndex,
);

let adjustedSize = compareNumbersWithPrecision(targetPaneSize, minSize) < 0
? minSize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,21 @@ import { createEvent } from 'common/core/events/utils/index';
import { name as DOUBLE_CLICK_EVENT } from 'common/core/events/double_click';
import { name as CLICK_EVENT } from 'common/core/events/click';
import resizeObserverSingleton from 'core/resize_observer';
import {
SPLITTER_CLASS,
SPLITTER_ITEM_CLASS,
SPLITTER_ITEM_HIDDEN_CONTENT_CLASS,
INVISIBLE_STATE_CLASS as STATE_INVISIBLE_CLASS
} from '__internal/ui/splitter/splitter';

import 'fluent_blue_light.css!';

const SPLITTER_ITEM_CLASS = 'dx-splitter-item';
const SPLITTER_ITEM_HIDDEN_CONTENT_CLASS = 'dx-splitter-item-hidden-content';
const RESIZE_HANDLE_CLASS = 'dx-resize-handle';
const RESIZE_HANDLE_ICON_CLASS = 'dx-resize-handle-icon';
const RESIZE_HANDLE_COLLAPSE_PREV_PANE_CLASS = 'dx-resize-handle-collapse-prev-pane';
const RESIZE_HANDLE_COLLAPSE_NEXT_PANE_CLASS = 'dx-resize-handle-collapse-next-pane';
const STATE_INVISIBLE_CLASS = 'dx-state-invisible';
const STATE_ACTIVE_CLASS = 'dx-state-active';
const STATE_FOCUSED_CLASS = 'dx-state-focused';
const SPLITTER_CLASS = 'dx-splitter';

QUnit.testStart(() => {
const markup =
Expand Down Expand Up @@ -1008,14 +1010,14 @@ QUnit.module('Pane sizing', moduleConfig, () => {
]
},
{
items: [{ collapsed: true, size: '150px', collapsible: true }, { collapsible: true }, { collapsed: true, collapsible: true }, { }],
items: [{ collapsed: true, collapsible: true }, { collapsible: true }, { collapsed: true, collapsible: true }, { }],
scenarios: [
{ newCollapsedValue: false, paneIndex: 0, expectedLayout: ['25', '25', '0', '50'] },
{ newCollapsedValue: false, paneIndex: 2, expectedLayout: ['25', '25', '25', '25'] },
]
},
{
items: [{ collapsed: false, collapsible: true }, { collapsed: true, collapsible: true }, { collapsible: true }, { collapsed: true, size: '150px', collapsible: true }],
items: [{ collapsed: false, collapsible: true }, { collapsed: true, collapsible: true }, { collapsible: true }, { collapsed: true, collapsible: true }],
scenarios: [
{ newCollapsedValue: false, paneIndex: 3, expectedLayout: ['50', '0', '25', '25'] },
{ newCollapsedValue: false, paneIndex: 1, expectedLayout: ['50', '12.5', '12.5', '25'] },
Expand Down Expand Up @@ -1361,6 +1363,98 @@ QUnit.module('Pane sizing', moduleConfig, () => {

resizeObserverSingleton.unobserve.restore();
});

[150, 200, 250].forEach(expectedSize => {
QUnit.test(`initial collapsed pane should restore size from configuration (left pane) size ${expectedSize}`, function(assert) {

this.reinit({
width: 600,
height: 600,
items: [
{ size: `${expectedSize}px`, collapsed: true, collapsible: true, },
{ }
]
});

this.instance.option('items[0].collapsed', false);

assert.strictEqual(this.instance.option('items[0].size'), expectedSize, 'items[0].size');

});

QUnit.test(`initial collapsed pane should restore size from configuration (right pane) size ${expectedSize}`, function(assert) {

this.reinit({
width: 600,
height: 600,
items: [
{ },
{ size: `${expectedSize}px`, collapsed: true, collapsible: true, }
]
});

this.instance.option('items[1].collapsed', false);

assert.strictEqual(this.instance.option('items[1].size'), expectedSize, 'items[1].size');

});

QUnit.test(`initial collapsed pane should restore size from configuration (right and left pane) size ${expectedSize}`, function(assert) {

this.reinit({
width: 600,
height: 600,
items: [
{ size: `${expectedSize}px`, collapsed: true, collapsible: true, },
{ },
{ size: `${expectedSize}px`, collapsed: true, collapsible: true, }
]
});

this.instance.option('items[0].collapsed', false);
this.instance.option('items[2].collapsed', false);

assert.strictEqual(this.instance.option('items[0].size'), expectedSize, 'items[0].size');
assert.strictEqual(this.instance.option('items[2].size'), expectedSize, 'items[2].size');

});

QUnit.test(`_initialSizeBeforeCollapse should create when item has collapsed:true and size = ${expectedSize}`, function(assert) {
this.reinit({
width: 600,
height: 600,
items: [
{ size: `${expectedSize}px`, collapsed: true, collapsible: true, },
{ },
]
});

const items = this.instance.option('items');

assert.strictEqual(items[0]._initialSizeBeforeCollapse, `${expectedSize}px`, 'items[0]._initialSizeBeforeCollapse');
assert.strictEqual(items[1]._initialSizeBeforeCollapse, undefined, 'items[1]._initialSizeBeforeCollapse');

});
});

QUnit.test('_initialSizeBeforeCollapse should be undefined after first expand', function(assert) {
this.reinit({
width: 600,
height: 600,
items: [
{ size: '150px', collapsed: true, collapsible: true, },
{ },
]
});

this.instance.option('items[0].collapsed', false);

const item0 = this.instance.option('items[0]');

assert.strictEqual(item0._initialSizeBeforeCollapse, undefined, 'items[0]._initialSizeBeforeCollapse');

});

});

QUnit.module('Pane visibility', moduleConfig, () => {
Expand Down
Loading