Skip to content

Commit 44b19ec

Browse files
committed
feat: add bodyEventsToCapture prop
1 parent 39e58e2 commit 44b19ec

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

__tests__/index.tsx

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import React, { act } from 'react';
22
import ReactDOM from 'react-dom';
3-
import { render, fireEvent, renderHook } from '@testing-library/react';
3+
import {
4+
render,
5+
fireEvent,
6+
renderHook,
7+
getByTestId
8+
} from '@testing-library/react';
49
import ClickAwayListener from '../src';
510

611
/**
@@ -34,7 +39,7 @@ describe('ClickAway Listener', () => {
3439
`(
3540
'should return the "$expectedEventType" event object, when the "$fireEventFn" event is fired on the outside element',
3641
({ fireEventFn, expectedEventType }) => {
37-
const handleClick = (event: FocusEvent | MouseEvent | TouchEvent) => {
42+
const handleClick = (event) => {
3843
expect(event.type).toBe(expectedEventType);
3944
};
4045

@@ -237,6 +242,33 @@ describe('ClickAway Listener', () => {
237242
expect(handleClick).toHaveBeenCalledTimes(1);
238243
});
239244

245+
it('should work with other body events', () => {
246+
const handleClick = jest.fn();
247+
const handleClickAway = jest.fn();
248+
249+
const { getByTestId } = render(
250+
<React.Fragment>
251+
<ClickAwayListener
252+
onClickAway={(event) => {
253+
if ((event as KeyboardEvent).key === 'Escape') {
254+
handleClickAway(event);
255+
}
256+
}}
257+
bodyEventsToCapture={['keydown']}
258+
>
259+
<button onClick={handleClick}>Hello World</button>
260+
</ClickAwayListener>
261+
<input type="text" data-testid="input" />
262+
</React.Fragment>
263+
);
264+
jest.runOnlyPendingTimers();
265+
266+
fireEvent.keyDown(getByTestId('input'), { key: 'Enter' });
267+
expect(handleClickAway).toHaveBeenCalledTimes(0);
268+
fireEvent.keyDown(getByTestId('input'), { key: 'Escape' });
269+
expect(handleClickAway).toHaveBeenCalledTimes(1);
270+
});
271+
240272
it('should work with function refs', () => {
241273
const handleClickAway = jest.fn();
242274
let buttonRef;

src/index.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ type TouchEvents = 'touchstart' | 'touchend';
1616
type Events = FocusEvent | MouseEvent | TouchEvent;
1717

1818
interface Props extends HTMLAttributes<HTMLElement> {
19-
onClickAway: (event: Events) => void;
19+
onClickAway: (event: Event) => void;
2020
focusEvent?: FocusEvents;
2121
mouseEvent?: MouseEvents;
2222
touchEvent?: TouchEvents;
2323
children: ReactElement<any>;
24+
bodyEventsToCapture?: Array<keyof DocumentEventMap>;
2425
}
2526

2627
const eventTypeMapping = {
@@ -55,6 +56,7 @@ const ClickAwayListener: FunctionComponent<Props> = ({
5556
focusEvent = 'focusin',
5657
mouseEvent = 'click',
5758
touchEvent = 'touchend',
59+
bodyEventsToCapture,
5860
...rest
5961
}) => {
6062
const node = useRef<HTMLElement | null>(null);
@@ -102,7 +104,7 @@ const ClickAwayListener: FunctionComponent<Props> = ({
102104
useEffect(() => {
103105
const nodeDocument = node.current?.ownerDocument ?? document;
104106

105-
const handleEvents = (event: Events): void => {
107+
const handleEvents: EventListener = (event) => {
106108
if (!mountedRef.current) return;
107109

108110
if (
@@ -119,13 +121,21 @@ const ClickAwayListener: FunctionComponent<Props> = ({
119121
nodeDocument.addEventListener(mouseEvent, handleEvents);
120122
nodeDocument.addEventListener(touchEvent, handleEvents);
121123
nodeDocument.addEventListener(focusEvent, handleEvents);
124+
const customListeners = bodyEventsToCapture || [];
125+
customListeners.forEach((eventType) => {
126+
nodeDocument.addEventListener(eventType, handleEvents);
127+
});
122128

123129
return () => {
124130
nodeDocument.removeEventListener(mouseEvent, handleEvents);
125131
nodeDocument.removeEventListener(touchEvent, handleEvents);
126132
nodeDocument.removeEventListener(focusEvent, handleEvents);
133+
134+
customListeners.forEach((eventType) => {
135+
nodeDocument.removeEventListener(eventType, handleEvents);
136+
});
127137
};
128-
}, [focusEvent, mouseEvent, onClickAway, touchEvent]);
138+
}, [focusEvent, mouseEvent, onClickAway, touchEvent, bodyEventsToCapture]);
129139

130140
const mappedMouseEvent = eventTypeMapping[mouseEvent];
131141
const mappedTouchEvent = eventTypeMapping[touchEvent];

0 commit comments

Comments
 (0)