Skip to content

Commit 02e7812

Browse files
authored
DataGrid - Column reordering: Implement autoscroll (DevExpress#29770)
Co-authored-by: Alyar <>
1 parent 9154cb7 commit 02e7812

File tree

15 files changed

+358
-62
lines changed

15 files changed

+358
-62
lines changed

apps/react-storybook/stories/examples/datagrid/DataGrid.stories.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Meta, StoryObj } from '@storybook/react';
22
import React, { useCallback, useState } from "react";
3-
import { countries } from './data';
3+
import { countries, generateData } from './data';
44

55
import DataGrid, {
66
Column,
@@ -253,3 +253,21 @@ export const ColumnReordering: Story = {
253253
},
254254
}
255255
}
256+
257+
const generatedData = generateData(10, 100);
258+
259+
export const ColumnReorderingWithVirtualColumns: Story = {
260+
argTypes: {
261+
columns: {
262+
control: 'object',
263+
mapping: null,
264+
},
265+
},
266+
args: {
267+
allowColumnReordering: true,
268+
rtlEnabled: false,
269+
columnWidth: 100,
270+
dataSource: generatedData,
271+
columns: Object.keys(generatedData[0]),
272+
}
273+
}

apps/react-storybook/stories/examples/datagrid/data.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,16 @@ export const countries = [{
109109
GDP_Services: 0.783,
110110
GDP_Total: 2945146,
111111
}];
112-
112+
113+
export const generateData = (rowCount: number, colCount: number): Record<string, string>[] => {
114+
const items: Record<string, string>[] = [];
115+
for (let i = 0; i < rowCount; i += 1) {
116+
const item: Record<string, string> = {};
117+
for (let j = 0; j < colCount; j += 1) {
118+
item[`field_${j}`] = `val_${i}_${j}`;
119+
}
120+
items.push(item);
121+
}
122+
123+
return items;
124+
};

e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/columnReordering.visual.ts

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import DataGrid from 'devextreme-testcafe-models/dataGrid';
33
import url from '../../../../helpers/getPageUrl';
44
import { createWidget } from '../../../../helpers/createWidget';
55
import { safeSizeTest } from '../../../../helpers/safeSizeTest';
6+
import { getData } from '../../helpers/generateDataSourceData';
67

78
fixture
89
.disablePageReloads`Keyboard Navigation - Column Reordering`
@@ -1439,3 +1440,164 @@ test('reorder column to left when adaptability is enabled and there are hidden c
14391440
});
14401441
});
14411442
});
1443+
1444+
// Autoscroll
1445+
test('Auto scroll to the right when column reordering via keyboard', async (t) => {
1446+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
1447+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
1448+
const firstHeaderCell = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(0);
1449+
1450+
await t
1451+
.click(firstHeaderCell.element)
1452+
.pressKey('ctrl+right')
1453+
.pressKey('ctrl+right')
1454+
.pressKey('ctrl+right')
1455+
.pressKey('ctrl+right');
1456+
1457+
await takeScreenshot(
1458+
'auto_scroll_to_right_when_column_reordering',
1459+
dataGrid.element,
1460+
);
1461+
1462+
await t.expect(compareResults.isValid())
1463+
.ok(compareResults.errorMessages());
1464+
}).before(async () => {
1465+
await createWidget('dxDataGrid', {
1466+
allowColumnReordering: true,
1467+
columnWidth: 200,
1468+
width: 800,
1469+
dataSource: [{
1470+
field1: 'test1',
1471+
field2: 'test2',
1472+
field3: 'test3',
1473+
field4: 'test4',
1474+
field5: 'test5',
1475+
field6: 'test6',
1476+
field7: 'test7',
1477+
field8: 'test8',
1478+
field9: 'test9',
1479+
field10: 'test10',
1480+
}],
1481+
scrolling: {
1482+
useNative: false,
1483+
},
1484+
});
1485+
});
1486+
1487+
test('Auto scroll to the left when column reordering via keyboard', async (t) => {
1488+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
1489+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
1490+
const lastHeaderCell = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(9);
1491+
1492+
await dataGrid.scrollTo(t, { x: 1200 });
1493+
1494+
await t
1495+
.expect(dataGrid.getScrollLeft())
1496+
.eql(1200);
1497+
1498+
await t
1499+
.click(lastHeaderCell.element)
1500+
.pressKey('ctrl+left')
1501+
.pressKey('ctrl+left')
1502+
.pressKey('ctrl+left')
1503+
.pressKey('ctrl+left');
1504+
1505+
await takeScreenshot(
1506+
'auto_scroll_to_left_when_column_reordering',
1507+
dataGrid.element,
1508+
);
1509+
1510+
await t.expect(compareResults.isValid())
1511+
.ok(compareResults.errorMessages());
1512+
}).before(async () => {
1513+
await createWidget('dxDataGrid', {
1514+
allowColumnReordering: true,
1515+
columnWidth: 200,
1516+
width: 800,
1517+
dataSource: [{
1518+
field1: 'test1',
1519+
field2: 'test2',
1520+
field3: 'test3',
1521+
field4: 'test4',
1522+
field5: 'test5',
1523+
field6: 'test6',
1524+
field7: 'test7',
1525+
field8: 'test8',
1526+
field9: 'test9',
1527+
field10: 'test10',
1528+
}],
1529+
scrolling: {
1530+
useNative: false,
1531+
},
1532+
});
1533+
});
1534+
1535+
test('Auto scroll to the right when column reordering via keyboard when virtual columns are enabled', async (t) => {
1536+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
1537+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
1538+
const firstHeaderCell = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(0);
1539+
1540+
await t
1541+
.click(firstHeaderCell.element);
1542+
1543+
for (let i = 0; i < 30; i += 1) {
1544+
await t.pressKey('ctrl+right');
1545+
}
1546+
1547+
await takeScreenshot(
1548+
'auto_scroll_to_right_when_column_reordering_when_virtual_columns_are_enabled',
1549+
dataGrid.element,
1550+
);
1551+
1552+
await t.expect(compareResults.isValid())
1553+
.ok(compareResults.errorMessages());
1554+
}).before(async () => {
1555+
await createWidget('dxDataGrid', {
1556+
allowColumnReordering: true,
1557+
columnWidth: 100,
1558+
width: 800,
1559+
dataSource: getData(1, 30),
1560+
scrolling: {
1561+
useNative: false,
1562+
columnRenderingMode: 'virtual',
1563+
},
1564+
});
1565+
});
1566+
1567+
test('Auto scroll to the left when column reordering via keyboard when virtual columns are enabled', async (t) => {
1568+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
1569+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
1570+
const lastHeaderCell = dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(29);
1571+
1572+
await dataGrid.scrollTo(t, { x: 2200 });
1573+
1574+
await t
1575+
.expect(dataGrid.getScrollLeft())
1576+
.eql(2200);
1577+
1578+
await t
1579+
.click(lastHeaderCell.element);
1580+
1581+
for (let i = 0; i < 30; i += 1) {
1582+
await t.pressKey('ctrl+left');
1583+
}
1584+
1585+
await takeScreenshot(
1586+
'auto_scroll_to_left_when_column_reordering_when_virtual_columns_are_enabled',
1587+
dataGrid.element,
1588+
);
1589+
1590+
await t.expect(compareResults.isValid())
1591+
.ok(compareResults.errorMessages());
1592+
}).before(async () => {
1593+
await createWidget('dxDataGrid', {
1594+
allowColumnReordering: true,
1595+
columnWidth: 100,
1596+
width: 800,
1597+
dataSource: getData(1, 30),
1598+
scrolling: {
1599+
useNative: false,
1600+
columnRenderingMode: 'virtual',
1601+
},
1602+
});
1603+
});
6.77 KB
Loading
Loading
6.34 KB
Loading
Loading

packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1892,6 +1892,14 @@ export class ColumnsController extends modules.Controller {
18921892
public isVirtualMode(): boolean {
18931893
return false;
18941894
}
1895+
1896+
/**
1897+
* @extended: virtual_column
1898+
*/
1899+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1900+
public isNeedToRenderVirtualColumns(scrollPosition: number): boolean {
1901+
return false;
1902+
}
18951903
}
18961904

18971905
export const columnsControllerModule: Module = {

packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller_utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ export const updateColumnVisibleIndexes = function (that: ColumnsController, cur
390390
export const getColumnIndexByVisibleIndex = function (that: ColumnsController, visibleIndex, location) {
391391
// @ts-expect-error
392392
const rowIndex = isObject(visibleIndex) ? visibleIndex.rowIndex : null;
393-
const columns = location === GROUP_LOCATION ? that.getGroupColumns() : location === COLUMN_CHOOSER_LOCATION ? that.getChooserColumns() : that.getVisibleColumns(rowIndex);
393+
const columns = location === GROUP_LOCATION ? that.getGroupColumns() : location === COLUMN_CHOOSER_LOCATION ? that.getChooserColumns() : that.getVisibleColumns(rowIndex, true);
394394
let column;
395395

396396
// @ts-expect-error

packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_column_keyboard_navigation_core.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import eventsEngine from '@js/common/core/events/core/events_engine';
21
import { isDefined, isEmptyObject } from '@js/core/utils/type';
32

43
import { Direction, ViewName } from './const';
54
import type { ColumnFocusDispatcher } from './m_column_focus_dispatcher';
65
import { KeyboardNavigationController as KeyboardNavigationControllerCore } from './m_keyboard_navigation_core';
76

87
export class ColumnKeyboardNavigationController extends KeyboardNavigationControllerCore {
8+
private resizeCompletedWithContext!: (e: any) => void;
9+
910
protected needToRestoreFocus = false;
1011

1112
public columnFocusDispatcher!: ColumnFocusDispatcher;
@@ -19,7 +20,10 @@ export class ColumnKeyboardNavigationController extends KeyboardNavigationContro
1920
return column.groupIndex as number;
2021
}
2122

22-
return this._columnsController.getVisibleIndex(column.index, rowIndex);
23+
const visibleIndex = this._columnsController.getVisibleIndex(column.index, rowIndex);
24+
const columnIndexOffset = this.getColumnIndexOffset(visibleIndex);
25+
26+
return visibleIndex >= 0 ? visibleIndex + columnIndexOffset : -1;
2327
}
2428

2529
protected getNewVisibleIndex(
@@ -62,9 +66,7 @@ export class ColumnKeyboardNavigationController extends KeyboardNavigationContro
6266
return direction === Direction.Next ? newVisibleIndex - 1 : newVisibleIndex;
6367
}
6468

65-
protected renderCompleted(e: any): void {
66-
super.renderCompleted(e);
67-
69+
protected resizeCompleted(): void {
6870
if (this.needToRestoreFocus) {
6971
this.restoreFocus();
7072
this.needToRestoreFocus = false;
@@ -83,8 +85,16 @@ export class ColumnKeyboardNavigationController extends KeyboardNavigationContro
8385
public init() {
8486
super.init();
8587

88+
const focusedView = this.getFocusedView();
89+
8690
this.columnFocusDispatcher = this.getController('columnFocusDispatcher');
8791
this.columnFocusDispatcher?.registerKeyboardNavigationController(this);
92+
93+
this.resizeCompletedWithContext = this.resizeCompletedWithContext
94+
?? this.resizeCompleted.bind(this);
95+
96+
focusedView?.resizeCompleted?.remove(this.resizeCompletedWithContext);
97+
focusedView?.resizeCompleted?.add(this.resizeCompletedWithContext);
8898
}
8999

90100
public moveColumn({
@@ -150,9 +160,7 @@ export class ColumnKeyboardNavigationController extends KeyboardNavigationContro
150160
}
151161

152162
const $focusedCell = this._getFocusedCell();
153-
154-
// @ts-expect-error
155-
eventsEngine.trigger($focusedCell, 'focus');
163+
$focusedCell?.[0]?.focus({ preventScroll: true });
156164
}
157165

158166
public ungroupAllColumns(): void {

0 commit comments

Comments
 (0)