Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance use key event #432

Merged
merged 2 commits into from
Jan 5, 2022
Merged
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
130 changes: 129 additions & 1 deletion src/hooks/__tests__/useKeyEvent.jest.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from "react";
import { renderHook, cleanup, act, waitFor } from "@testing-library/react-hooks";
import { fireEvent } from "@testing-library/react";
import useKeyEvent from "../useKeyEvent";
Expand Down Expand Up @@ -56,6 +55,135 @@ describe("useKeyEvent", () => {
});
});

describe("single key with ALT modifier", () => {
const keys = ["Enter"];
beforeEach(() => {
callbackStub = jest.fn();
element = document.createElement("div");
document.body.appendChild(element);
renderHook(() =>
useKeyEvent({
keys,
keyEventName: "keyup",
ref: { current: element },
callback: callbackStub,
modifier: useKeyEvent.modifiers.ALT
})
);
});

afterEach(() => {
element.remove();
cleanup();
});

it(`should call the callback with the ${keys[0]} key and ALT key`, () => {
act(() => {
fireEvent.keyUp(element, {
key: keys[0],
altKey: true
});
});
expect(callbackStub.mock.calls.length).toEqual(1);
});

it(`should not call the callback with the key but without modifiers`, () => {
act(() => {
fireEvent.keyUp(element, {
key: keys[0]
});
});

expect(callbackStub.mock.calls.length).toEqual(0);
});

it(`should not call the callback with the key but with other modifier`, () => {
act(() => {
fireEvent.keyUp(element, {
key: keys[0],
shiftKey: true
});
});

expect(callbackStub.mock.calls.length).toEqual(0);
});
});

describe("single key with CTRL_OR_META modifier", () => {
const keys = ["Enter"];
beforeEach(() => {
callbackStub = jest.fn();
element = document.createElement("div");
document.body.appendChild(element);
renderHook(() =>
useKeyEvent({
keys,
keyEventName: "keyup",
ref: { current: element },
callback: callbackStub,
modifier: useKeyEvent.modifiers.CTRL_OR_META
})
);
});

afterEach(() => {
element.remove();
cleanup();
});

it(`should call the callback with the ${keys[0]} key and CTRL key`, () => {
act(() => {
fireEvent.keyUp(element, {
key: keys[0],
ctrlKey: true
});
});
expect(callbackStub.mock.calls.length).toEqual(1);
});

it(`should call the callback with the ${keys[0]} key and META key`, () => {
act(() => {
fireEvent.keyUp(element, {
key: keys[0],
metaKey: true
});
});
expect(callbackStub.mock.calls.length).toEqual(1);
});

it(`should not call the callback with the key but without modifiers`, () => {
act(() => {
fireEvent.keyUp(element, {
key: keys[0]
});
});

expect(callbackStub.mock.calls.length).toEqual(0);
});

it(`should not call the callback with the key but with other modifier`, () => {
act(() => {
fireEvent.keyUp(element, {
key: keys[0],
shiftKey: true
});
});

expect(callbackStub.mock.calls.length).toEqual(0);
});

it(`should not call the callback with other key but with modifiers`, () => {
act(() => {
fireEvent.keyUp(element, {
key: "Esc",
metaKey: true
});
});

expect(callbackStub.mock.calls.length).toEqual(0);
});
});

describe("multiple keys", () => {
const keys = ["Enter", "Esc", "Escape"];
beforeEach(() => {
Expand Down
23 changes: 22 additions & 1 deletion src/hooks/useKeyEvent/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { useCallback, useRef } from "react";
import useEventListener from "../useEventListener";

const CTRL_OR_META = "ctrlOrMetaKey";

const checkModifierInEvent = (event, modifier) => {
if (event[modifier]) return true;
if (modifier === CTRL_OR_META) {
return event.ctrlKey || event.metaKey;
}
return false;
};
export default function useKeyEvent({
keys = [],
modifier,
ref,
callback,
ignoreDocumentFallback = false,
Expand All @@ -18,6 +28,9 @@ export default function useKeyEvent({
if (!keys.includes(key)) {
return;
}
if (modifier && !checkModifierInEvent(event, modifier)) {
return;
}

if (preventDefault) {
event.preventDefault();
Expand All @@ -29,7 +42,7 @@ export default function useKeyEvent({

callback(event);
},
[callback, keys, preventDefault, stopPropagation]
[callback, keys, preventDefault, stopPropagation, modifier]
);

let listenerRef;
Expand All @@ -49,3 +62,11 @@ export default function useKeyEvent({
capture
});
}

useKeyEvent.modifiers = {
ALT: "altKey",
META: "metaKey", // i.e. CMD key
CTRL: "ctrlKey",
SHIFT: "shiftKey",
CTRL_OR_META
};