Skip to content

Commit 5318610

Browse files
Merge branch '25_1' of https://github.com/DevExpress/DevExtreme into 25_1_demos_csb_tgz
2 parents 3eef76a + a6ed77e commit 5318610

25 files changed

Lines changed: 865 additions & 356 deletions

File tree

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,13 @@
1-
If your data contains an error or measurement uncertainty, you can indicate a confidential interval on the Chart using error bars. To configure them, use the fields of the series’ **valueErrorBar** object. In this example, error bars indicate a range of average temperatures (on the upper pane) and humidity (on the lower pane) for a specific month.
2-
<!--split-->
1+
DevExtreme Chart supports value error bars. Implement these bars to indicate data measurement tolerances and [confidence intervals](https://en.wikipedia.org/wiki/Confidence_interval). Configure error bar settings and appearance in the **series**.[valueErrorBar](/Documentation/ApiReference/UI_Components/dxChart/Configuration/series/valueErrorBar/) object.
2+
3+
<!--split-->
4+
5+
To enable error bars, specify one of the following pairs of **valueErrorBar** properties:
6+
7+
- [lowValueField](Documentation/ApiReference/UI_Components/dxChart/Configuration/series/valueErrorBar/#lowValueField) and [highValueField](/Documentation/ApiReference/UI_Components/dxChart/Configuration/series/valueErrorBar/#highValueField)
8+
Specify predefined error bars for each series point.
9+
10+
- [value](Documentation/ApiReference/UI_Components/dxChart/Configuration/series/valueErrorBar/#value) and [type](/Documentation/ApiReference/UI_Components/dxChart/Configuration/series/valueErrorBar/#type)
11+
Configure dynamically calculated error bars.
12+
13+
This demo implements predefined error bars specified in the Chart data source.
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1-
The Chart component allows you to&nbsp;create charts with multiple panes stacked vertically. Each pane can plot one or&nbsp;more series and can share the argument axis with other plots.
2-
<!--split-->
1+
The DevExtreme Chart component allows you to display data in multiple panes. To configure a multi-pane chart, specify the [panes[]](/Documentation/ApiReference/UI_Components/dxChart/Configuration/panes/) array. The component stacks panes vertically (or horizontally when [rotated](/Documentation/ApiReference/UI_Components/dxChart/Configuration/#rotated) is `true`).
2+
3+
<!--split-->
4+
5+
Chart assigns unique [value axes](/Documentation/ApiReference/UI_Components/dxChart/Configuration/valueAxis/) and a shared [argument axis](/Documentation/ApiReference/UI_Components/dxChart/Configuration/argumentAxis/) to all panes. To configure the value axis of a specific pane, define **valueAxis** properties and assign the **pane**.[name](/Documentation/ApiReference/UI_Components/dxChart/Configuration/panes/#name) value to **valueAxis**.[pane](/Documentation/ApiReference/UI_Components/dxChart/Configuration/valueAxis/#pane).
6+
7+
DevExtreme Chart can display multiple [series](/Documentation/ApiReference/UI_Components/dxChart/Configuration/series/) in a single pane. Specify the **series**.[pane](/Documentation/ApiReference/UI_Components/dxChart/Configuration/series/#pane) property to display a series in a specific pane.
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
In&nbsp;this demo, the DevExtreme Chart component is&nbsp;used to&nbsp;create&nbsp;a [Pareto chart][0]. This example of&nbsp;a&nbsp;Pareto chart summarizes complaints about the service provided by&nbsp;a&nbsp;pizza shop. From this chart, the pizza shop owner may infer that to&nbsp;satisfy most of&nbsp;the customers, he&nbsp;or&nbsp;she needs to&nbsp;eliminate two most frequently encountered issues: delayed delivery and cold pizza.
1+
You can utilize the DevExtreme Chart component to display data in a [Pareto chart](https://en.wikipedia.org/wiki/Pareto_chart). A Pareto chart displays individual values along with their cumulative totals. In this demo, individual values are numbers of complaints and cumulative totals are represented as percentages.
22

3-
[0]: https://en.wikipedia.org/wiki/Pareto_chart
3+
<!--split-->
4+
5+
To create a Pareto chart, configure two [series](/Documentation/ApiReference/UI_Components/dxChart/Configuration/series/) objects. Assign the [Bar](/Documentation/ApiReference/UI_Components/dxChart/Series_Types/BarSeries/) and [Line](/Documentation/ApiReference/UI_Components/dxChart/Series_Types/LineSeries/)/[Spline](/Documentation/ApiReference/UI_Components/dxChart/Series_Types/SplineSeries/) series types to **series**.[type](/Documentation/ApiReference/UI_Components/dxChart/Configuration/series/#type). To represent the numbers of the [Pareto principle](https://en.wikipedia.org/wiki/Pareto_principle) (80/20), you can specify constant lines. This demo configures a **valueAxis**.[constantLines](/Documentation/ApiReference/UI_Components/dxChart/Configuration/valueAxis/constantLines/) object to display a constant line at 80% of the cumulative total axis.

e2e/testcafe-devextreme/tests/dataGrid/common/keyboardNavigation/startEditing.functional.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import DataGrid from 'devextreme-testcafe-models/dataGrid';
2+
import { ClientFunction } from 'testcafe';
23
import url from '../../../../helpers/getPageUrl';
34
import { createWidget } from '../../../../helpers/createWidget';
45

@@ -36,6 +37,86 @@ test('Editing should start by pressing enter after scrolling content with scroll
3637
});
3738
});
3839

40+
test('editing.allowUpdating callback should receive correct row on tab key on first cell with virtual scrolling (T1290811)', async (t) => {
41+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
42+
43+
await dataGrid.scrollBy({ y: 10000 });
44+
45+
await t
46+
.click(dataGrid.getDataCell(49, 0).element)
47+
.expect(dataGrid.getDataCell(49, 0).getEditor().element.focused).ok();
48+
49+
await t
50+
.pressKey('tab')
51+
.expect(dataGrid.getDataCell(49, 1).getEditor().element.focused).ok();
52+
53+
const eventRowKeys = await ClientFunction(() => (window as any).eventRowKeys)();
54+
const uniqueRowKeys = [...new Set(eventRowKeys)];
55+
56+
await t.expect(uniqueRowKeys).eql([49]);
57+
}).before(async () => {
58+
await createWidget('dxDataGrid', {
59+
dataSource: [...new Array(50)].map((_, i) => ({
60+
id: i,
61+
data: `Row ${i}`,
62+
})),
63+
keyExpr: 'id',
64+
columns: ['id', 'data'],
65+
editing: {
66+
mode: 'cell',
67+
allowUpdating: (e) => {
68+
(window as any).eventRowKeys ??= [];
69+
(window as any).eventRowKeys.push(e.row?.key);
70+
return true;
71+
},
72+
},
73+
scrolling: {
74+
mode: 'virtual',
75+
},
76+
height: 300,
77+
});
78+
});
79+
80+
test('editing.allowUpdating callback should receive correct row on tab key on last cell with virtual scrolling (T1290811)', async (t) => {
81+
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
82+
83+
await dataGrid.scrollBy({ y: 10000 });
84+
85+
await t
86+
.click(dataGrid.getDataCell(48, 1).element)
87+
.expect(dataGrid.getDataCell(48, 1).getEditor().element.focused).ok();
88+
89+
await t
90+
.pressKey('tab')
91+
.expect(dataGrid.getDataCell(49, 0).getEditor().element.focused).ok();
92+
93+
const eventRowKeys = await ClientFunction(() => (window as any).eventRowKeys)();
94+
const uniqueRowKeys = [...new Set(eventRowKeys)];
95+
96+
await t.expect(uniqueRowKeys).eql([48, 49]);
97+
}).before(async () => {
98+
await createWidget('dxDataGrid', {
99+
dataSource: [...new Array(50)].map((_, i) => ({
100+
id: i,
101+
data: `Row ${i}`,
102+
})),
103+
keyExpr: 'id',
104+
columns: ['id', 'data'],
105+
editing: {
106+
mode: 'cell',
107+
allowUpdating: (e) => {
108+
(window as any).eventRowKeys ??= [];
109+
(window as any).eventRowKeys.push(e.row?.key);
110+
return true;
111+
},
112+
},
113+
scrolling: {
114+
mode: 'virtual',
115+
},
116+
height: 300,
117+
});
118+
});
119+
39120
test('DataGrid should not remove the minus symbol when editing started (T1201166)', async (t) => {
40121
const dataGrid = new DataGrid(DATA_GRID_SELECTOR);
41122

-2 Bytes
Loading
-1 Bytes
Loading
-1 Bytes
Loading

packages/devextreme-scss/scss/widgets/fluent/menuBase/_index.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@
3434
&.dx-state-active {
3535
background-color: $menu-item-bg-active;
3636
}
37+
38+
.dx-item-url {
39+
display: inherit;
40+
gap: inherit;
41+
}
42+
43+
.dx-icon-with-url {
44+
&::before {
45+
display: inline-block;
46+
}
47+
}
3748
}
3849

3950
.dx-menu-item-selected {

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

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -885,49 +885,52 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo
885885

886886
private _editingCellTabHandler(eventArgs, direction) {
887887
const eventTarget = eventArgs.originalEvent.target;
888-
let $cell = this._getCellElementFromTarget(eventTarget);
889-
let isEditingAllowed;
890-
const $event = eventArgs.originalEvent;
891-
const elementType = this._getElementType(eventTarget);
888+
const $targetCell = this._getCellElementFromTarget(eventTarget);
889+
const isCommandCell = $targetCell.is(COMMAND_CELL_SELECTOR);
892890

893-
if ($cell.is(COMMAND_CELL_SELECTOR)) {
891+
if (isCommandCell) {
894892
return !this._targetCellTabHandler(eventArgs, direction);
895893
}
896894

897-
this._updateFocusedCellPosition($cell);
895+
this._updateFocusedCellPosition($targetCell);
896+
897+
const elementType = this._getElementType(eventTarget);
898898
const nextCellInfo = this._getNextCellByTabKey(
899-
$event,
899+
eventArgs.originalEvent,
900900
direction,
901901
elementType,
902902
);
903-
$cell = nextCellInfo.$cell;
903+
const $nextCell = nextCellInfo.$cell;
904904

905-
if (!$cell || this._handleTabKeyOnMasterDetailCell($cell, direction)) {
905+
if (!$nextCell || this._handleTabKeyOnMasterDetailCell($nextCell, direction)) {
906906
return false;
907907
}
908908

909-
const column = this._getColumnByCellElement($cell);
910-
const $row = $cell.parent();
911-
const rowIndex = this._getRowIndex($row);
912-
const row = this._dataController.items()[rowIndex] as any;
913-
const editingController = this._editingController;
909+
let isEditingAllowed = false;
910+
const column = this._getColumnByCellElement($nextCell);
914911

915-
if (column && column.allowEditing) {
912+
if (column?.allowEditing) {
913+
const $row = $nextCell.parent();
914+
const rowIndex = this._getLocalRowIndex($row);
915+
const row = this._dataController.items()[rowIndex] as any;
916916
const isDataRow = !row || row.rowType === 'data';
917-
isEditingAllowed = editingController.allowUpdating({ row })
918-
? isDataRow
919-
: row && row.isNewRow;
917+
918+
isEditingAllowed = this._editingController.allowUpdating({ row })
919+
? isDataRow : row?.isNewRow;
920920
}
921921

922922
if (!isEditingAllowed) {
923923
this._closeEditCell();
924924
}
925925

926-
if (this._focusCell($cell, !nextCellInfo.isHighlighted)) {
927-
if (!this._isRowEditMode() && isEditingAllowed) {
926+
const nextCellFocused = this._focusCell($nextCell, !nextCellInfo.isHighlighted);
927+
928+
if (nextCellFocused) {
929+
const isRowMode = this._isRowEditMode();
930+
if (!isRowMode && isEditingAllowed) {
928931
this._editFocusedCell();
929932
} else {
930-
this._focusInteractiveElement($cell, eventArgs.shift);
933+
this._focusInteractiveElement($nextCell, eventArgs.shift);
931934
}
932935
}
933936

@@ -2302,11 +2305,14 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo
23022305
columnIndex: number,
23032306
): void {
23042307
const $cell = this._getFocusedCell();
2305-
const rowIndex = this._getRowIndex($cell?.parent());
2308+
const $row = $cell?.parent();
2309+
2310+
const rowIndex = this.getRowIndex();
23062311
const localRowIndex = Math.min(
2307-
rowIndex - this._dataController.getRowIndexOffset(),
2312+
this._getLocalRowIndex($row),
23082313
this._dataController.items().length - 1,
23092314
);
2315+
23102316
const isEditingCell = this._editingController.isEditCell(
23112317
localRowIndex,
23122318
columnIndex,
@@ -2448,8 +2454,8 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo
24482454
}
24492455
}
24502456

2451-
protected _getRowIndex($row) {
2452-
let rowIndex = this._rowsView.getRowIndex($row);
2457+
protected _getRowIndex($row): number {
2458+
let rowIndex = this._getLocalRowIndex($row);
24532459

24542460
if (rowIndex >= 0) {
24552461
rowIndex += this._dataController.getRowIndexOffset();
@@ -2458,6 +2464,12 @@ export class KeyboardNavigationController extends KeyboardNavigationControllerCo
24582464
return rowIndex;
24592465
}
24602466

2467+
protected _getLocalRowIndex($row): number {
2468+
const rowIndex = this._rowsView.getRowIndex($row);
2469+
2470+
return rowIndex;
2471+
}
2472+
24612473
protected getCellIndex($cell, rowIndex): number {
24622474
return this._rowsView.getCellIndex($cell, rowIndex);
24632475
}

0 commit comments

Comments
 (0)