Skip to content

Commit 24b798f

Browse files
authored
CardView - ContextMenu position is wrong after opening from the keyboard (#30169)
1 parent 7ef5699 commit 24b798f

9 files changed

+78
-12
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import CardView from 'devextreme-testcafe-models/cardView';
2+
import { createScreenshotsComparer } from 'devextreme-screenshot-comparer';
3+
import { ClientFunction } from 'testcafe';
4+
import url from '../../../helpers/getPageUrl';
5+
import { createWidget } from '../../../helpers/createWidget';
6+
import { testScreenshot } from '../../../helpers/themeUtils';
7+
8+
fixture.disablePageReloads`CardView - ContextMenu Behavior`
9+
.page(url(__dirname, '../../container.html'));
10+
11+
test('Context menu should be shown at the mouse cursor', async (t) => {
12+
const cardView = new CardView('#container');
13+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
14+
15+
await t
16+
.rightClick(cardView.getHeaders().getHeaderItemNth(0).element, { offsetX: -10, offsetY: -10 });
17+
18+
await testScreenshot(t, takeScreenshot, 'card-view_context-menu_mouse-click_position.png', { element: cardView.element });
19+
20+
await t
21+
.expect(compareResults.isValid())
22+
.ok(compareResults.errorMessages());
23+
}).before(async () => {
24+
await createWidget('dxCardView', {
25+
dataSource: [{ ID: 1 }],
26+
});
27+
});
28+
29+
export const triggerCustomContextMenu = ClientFunction((selector) => {
30+
const element = selector() as Element;
31+
32+
const rect = element.getBoundingClientRect();
33+
const xPosition = rect.left + rect.width / 2;
34+
const yPosition = rect.top + rect.height / 2;
35+
36+
const event = new MouseEvent('contextmenu');
37+
/*
38+
Note: By default, TestCafe sets the pageX and pageY properties of MouseEvent to 0.
39+
There is no supported way to define custom pageX and pageY values for the contextmenu event.
40+
Additionally, TestCafe does not support system keys, so triggering combinations like Shift+F10
41+
or the Context Menu key is not possible.
42+
*/
43+
Object.defineProperty(event, 'pageX', { value: xPosition });
44+
Object.defineProperty(event, 'pageY', { value: yPosition });
45+
46+
element.dispatchEvent(event as any);
47+
});
48+
49+
test('Context menu should be shown at center of the header item if shown with the keyboard', async (t) => {
50+
const cardView = new CardView('#container');
51+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
52+
53+
await triggerCustomContextMenu(cardView.getHeaders().getHeaderItemNth(0).element);
54+
await testScreenshot(t, takeScreenshot, 'card-view_context-menu_keyboard_position.png', { element: cardView.element });
55+
56+
await t
57+
.expect(compareResults.isValid())
58+
.ok(compareResults.errorMessages());
59+
}).before(async () => {
60+
await createWidget('dxCardView', {
61+
dataSource: [{ ID: 1 }],
62+
});
63+
});
12.7 KB
Loading
9.92 KB
Loading
11.6 KB
Loading
12.8 KB
Loading
10 KB
Loading
11.7 KB
Loading

packages/devextreme/js/__internal/grids/new/card_view/header_panel/header_panel.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,6 @@ export class HeaderPanel extends Component<HeaderPanelProps> {
164164
() => ref.current?.focus(),
165165
);
166166
},
167-
'F10+shift': (event, ref) => {
168-
this.props.showContextMenu(
169-
event,
170-
column,
171-
idx,
172-
() => ref.current?.focus(),
173-
);
174-
},
175167
}}
176168
caughtEventPreventDefault={true}
177169
onSortClick={(event): void => {
@@ -180,8 +172,13 @@ export class HeaderPanel extends Component<HeaderPanelProps> {
180172
onFilterClick={(element: Element) => {
181173
this.props.onHeaderFilterOpen?.(element, column);
182174
}}
183-
onContextMenu={(event) => {
184-
this.props.showContextMenu(event, column, idx);
175+
onContextMenu={(event, ref) => {
176+
this.props.showContextMenu(
177+
event,
178+
column,
179+
idx,
180+
() => ref?.focus(),
181+
);
185182
}}
186183
/>
187184
</div>

packages/devextreme/js/__internal/grids/new/card_view/header_panel/item.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export interface ItemProps {
5454
onKeyDown?: (event: KeyboardEvent) => void;
5555
onSortClick?: (event: MouseEvent) => void;
5656
onFilterClick?: (element: Element) => void;
57-
onContextMenu?: (event: MouseEvent) => void;
57+
onContextMenu?: (event: MouseEvent, ref: HTMLDivElement) => void;
5858
}
5959

6060
export class Item extends Component<ItemProps> {
@@ -96,7 +96,7 @@ export class Item extends Component<ItemProps> {
9696
aria-label={ariaLabel}
9797
onClick={this.props.onSortClick}
9898
onKeyDown={this.props.onKeyDown}
99-
onContextMenu={this.props.onContextMenu}
99+
onContextMenu={this.onContextMenuHandler}
100100
>
101101
{icon}
102102
{Template && <Template column={this.props.column}/>}
@@ -130,4 +130,10 @@ export class Item extends Component<ItemProps> {
130130
this.props.onFilterClick?.(this.props.elementRef.current);
131131
}
132132
};
133+
134+
private readonly onContextMenuHandler = (event: MouseEvent): void => {
135+
if (this.props.elementRef?.current) {
136+
this.props.onContextMenu?.(event, this.props.elementRef.current);
137+
}
138+
};
133139
}

0 commit comments

Comments
 (0)