Skip to content

Commit 4031bf3

Browse files
author
annaha
committed
fix: add keyBinding for context menu
1 parent 80d78d3 commit 4031bf3

4 files changed

Lines changed: 114 additions & 83 deletions

File tree

packages/core/src/data-editor/data-editor-keybindings.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ export interface ConfigurableKeybinds {
6767
readonly selectAll: Keybind;
6868
readonly selectRow: Keybind;
6969
readonly selectColumn: Keybind;
70+
71+
readonly contextMenu: Keybind;
7072
}
7173

7274
export type Keybinds = ConfigurableKeybinds & ForcedKeybinds & Partial<BackCompatKeybinds>;
@@ -118,6 +120,7 @@ export const keybindingDefaults: Keybinds = {
118120
selectGrowRight: true,
119121
selectGrowDown: true,
120122
selectGrowLeft: true,
123+
contextMenu: true,
121124
};
122125

123126
function realizeKeybind(keybind: Keybind, defaultVal: string): string {
@@ -174,6 +177,7 @@ export function realizeKeybinds(keybinds: Keybinds): RealizedKeybinds {
174177
selectToLastCell: realizeKeybind(keybinds.selectToLastCell, "primary+shift+End"),
175178
selectToLastColumn: realizeKeybind(keybinds.selectToLastColumn, "primary+shift+ArrowRight"),
176179
selectToLastRow: realizeKeybind(keybinds.selectToLastRow, "primary+shift+ArrowDown"),
180+
contextMenu: realizeKeybind(keybinds.contextMenu, "shift+F10"),
177181
};
178182
}
179183

packages/core/src/data-editor/data-editor.tsx

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3263,6 +3263,7 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
32633263
}
32643264
}
32653265
}
3266+
console.log({event, details}, "keys.contextMenu:", keys.contextMenu, overlayOpen )
32663267

32673268
if (details.didMatch) {
32683269
cancel();
@@ -3363,23 +3364,44 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
33633364
} else if (isHotkey(keys.goToFirstColumn, event, details)) {
33643365
col = Number.MIN_SAFE_INTEGER;
33653366
} else if (rangeSelect === "rect" || rangeSelect === "multi-rect") {
3366-
if (isHotkey(keys.selectGrowDown, event, details)) {
3367-
adjustSelection([0, 1]);
3368-
} else if (isHotkey(keys.selectGrowUp, event, details)) {
3369-
adjustSelection([0, -1]);
3370-
} else if (isHotkey(keys.selectGrowRight, event, details)) {
3371-
adjustSelection([1, 0]);
3372-
} else if (isHotkey(keys.selectGrowLeft, event, details)) {
3373-
adjustSelection([-1, 0]);
3374-
} else if (isHotkey(keys.selectToLastRow, event, details)) {
3375-
adjustSelection([0, 2]);
3376-
} else if (isHotkey(keys.selectToFirstRow, event, details)) {
3377-
adjustSelection([0, -2]);
3378-
} else if (isHotkey(keys.selectToLastColumn, event, details)) {
3379-
adjustSelection([2, 0]);
3380-
} else if (isHotkey(keys.selectToFirstColumn, event, details)) {
3381-
adjustSelection([-2, 0]);
3382-
}
3367+
if (isHotkey(keys.selectGrowDown, event, details)) {
3368+
adjustSelection([0, 1]);
3369+
} else if (isHotkey(keys.selectGrowUp, event, details)) {
3370+
adjustSelection([0, -1]);
3371+
} else if (isHotkey(keys.selectGrowRight, event, details)) {
3372+
adjustSelection([1, 0]);
3373+
} else if (isHotkey(keys.selectGrowLeft, event, details)) {
3374+
adjustSelection([-1, 0]);
3375+
} else if (isHotkey(keys.selectToLastRow, event, details)) {
3376+
adjustSelection([0, 2]);
3377+
} else if (isHotkey(keys.selectToFirstRow, event, details)) {
3378+
adjustSelection([0, -2]);
3379+
} else if (isHotkey(keys.selectToLastColumn, event, details)) {
3380+
adjustSelection([2, 0]);
3381+
} else if (isHotkey(keys.selectToFirstColumn, event, details)) {
3382+
adjustSelection([-2, 0]);
3383+
} else if (isHotkey(keys.contextMenu, event, details) &&
3384+
event.bounds !== undefined &&
3385+
event.location !== undefined
3386+
) {
3387+
onContextMenu(
3388+
{
3389+
kind: "cell",
3390+
isFillHandle: false,
3391+
isTouch: false,
3392+
isEdge: false,
3393+
button: 0,
3394+
scrollEdge: [0, 0],
3395+
localEventX: event.bounds.width / 2,
3396+
localEventY: event.bounds.height / 2,
3397+
location: [col, row],
3398+
bounds: event.bounds,
3399+
ctrlKey: false,
3400+
metaKey: false,
3401+
shiftKey: true,
3402+
buttons: 0
3403+
}, cancel)
3404+
}
33833405
}
33843406
cancelOnlyOnMove = details.didMatch;
33853407
} else {

packages/core/src/internal/data-grid/data-grid.tsx

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,25 +1263,6 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
12631263
);
12641264
useEventListener("contextmenu", onContextMenuImpl, eventTargetRef?.current ?? null, false);
12651265

1266-
const onContextMenuWithKeyboardImpl = React.useCallback(
1267-
(ev: MouseEvent) => {
1268-
const canvas = ref.current;
1269-
const currentSelectedCell = selectionRef.current.current?.cell
1270-
if (canvas === null || onContextMenu === undefined || currentSelectedCell === undefined)
1271-
return;
1272-
const bounds = getBoundsForItem(canvas, ...currentSelectedCell);
1273-
if (bounds) {
1274-
const args = getMouseArgsForPosition(canvas, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, ev);
1275-
onContextMenu(args, () => {
1276-
if (ev.cancelable) ev.preventDefault();
1277-
});
1278-
}
1279-
},
1280-
[getMouseArgsForPosition, onContextMenu, getBoundsForItem]
1281-
);
1282-
1283-
useEventListener("contextmenu", onContextMenuWithKeyboardImpl, ref?.current ?? null, false);
1284-
12851266
const onAnimationFrame = React.useCallback<StepCallback>(values => {
12861267
damageRegion.current = new CellSet(values.map(x => x.item));
12871268
hoverValues.current = values;

packages/core/test/data-editor.test.tsx

Lines changed: 71 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -196,53 +196,6 @@ describe("data-editor", () => {
196196
expect(spySelection).not.toHaveBeenCalled();
197197
});
198198

199-
test("opens contextmenu at selected cell position when fired on canvas", async () => {
200-
const spy = vi.fn();
201-
202-
vi.useFakeTimers();
203-
render(<DataEditor
204-
{...basicProps}
205-
gridSelection={{
206-
columns: CompactSelection.empty(),
207-
rows: CompactSelection.empty(),
208-
current: {
209-
cell: [1, 1],
210-
range: { x: 1, y: 1, width: 1, height: 1 },
211-
rangeStack: [],
212-
},
213-
}}
214-
onCellContextMenu={spy}
215-
/>, { wrapper: Context });
216-
217-
prep();
218-
219-
const canvas = screen.getByTestId("data-grid-canvas");
220-
221-
fireEvent.contextMenu(canvas);
222-
223-
expect(spy).toHaveBeenCalledWith([1, 1], expect.anything());
224-
});
225-
226-
test("does not open contextmenu when no cell selected", async () => {
227-
const spy = vi.fn();
228-
229-
vi.useFakeTimers();
230-
render(<DataEditor
231-
{...basicProps}
232-
gridSelection={{
233-
columns: CompactSelection.empty(),
234-
rows: CompactSelection.empty(),
235-
}}
236-
onCellContextMenu={spy}
237-
/>, { wrapper: Context });
238-
239-
prep();
240-
const canvas = screen.getByTestId("data-grid-canvas");
241-
fireEvent.contextMenu(canvas);
242-
243-
expect(spy).not.toHaveBeenCalled();
244-
});
245-
246199
test("middle click does not change selection", async () => {
247200
const spySelection = vi.fn();
248201

@@ -1196,6 +1149,77 @@ describe("data-editor", () => {
11961149
expect(spy).toHaveBeenCalledWith(expect.objectContaining({ location: [1, 1] }));
11971150
});
11981151

1152+
test("opens context menu with Shift+F10 when cell is selected", async () => {
1153+
const spy = vi.fn();
1154+
1155+
vi.useFakeTimers();
1156+
render(<DataEditor {...basicProps} onCellContextMenu={spy} />, {
1157+
wrapper: Context,
1158+
});
1159+
prep(false);
1160+
1161+
const canvas = screen.getByTestId("data-grid-canvas");
1162+
sendClick(canvas, {
1163+
clientX: 300,
1164+
clientY: 84,
1165+
});
1166+
1167+
fireEvent.keyDown(canvas, {
1168+
key: "F10",
1169+
keyCode: 121,
1170+
shiftKey: true,
1171+
});
1172+
1173+
expect(spy).toHaveBeenCalledWith([1, 1], expect.anything());
1174+
1175+
const eventArgs = spy.mock.calls[0][1];
1176+
expect(eventArgs).toMatchObject({
1177+
kind: "cell",
1178+
shiftKey: true,
1179+
location: [1, 1],
1180+
bounds: expect.objectContaining({
1181+
x: expect.any(Number),
1182+
y: expect.any(Number),
1183+
width: expect.any(Number),
1184+
height: expect.any(Number),
1185+
}),
1186+
});
1187+
1188+
expect(eventArgs.localEventX).toBe(eventArgs.bounds.width / 2);
1189+
expect(eventArgs.localEventY).toBe(eventArgs.bounds.height / 2);
1190+
});
1191+
1192+
test("does not open context menu with Shift+F10 when no cells are selected", async () => {
1193+
const spy = vi.fn();
1194+
1195+
vi.useFakeTimers();
1196+
render(
1197+
<DataEditor
1198+
{...basicProps}
1199+
onCellContextMenu={spy}
1200+
gridSelection={{
1201+
columns: CompactSelection.empty(),
1202+
rows: CompactSelection.empty(),
1203+
current: undefined,
1204+
}}
1205+
/>,
1206+
{
1207+
wrapper: Context,
1208+
}
1209+
);
1210+
prep(false);
1211+
1212+
const canvas = screen.getByTestId("data-grid-canvas");
1213+
1214+
fireEvent.keyDown(canvas, {
1215+
key: "F10",
1216+
keyCode: 121,
1217+
shiftKey: true,
1218+
});
1219+
1220+
expect(spy).not.toHaveBeenCalled();
1221+
});
1222+
11991223
test("Delete cell", async () => {
12001224
const spy = vi.fn();
12011225

0 commit comments

Comments
 (0)