Skip to content

Commit 31eb528

Browse files
authored
Merge pull request #22 from frontend-opensource-project/URH-22/useOutsideInteraction
[URH-22] useOutsideInteraction 신규
2 parents 4904f5c + f44222e commit 31eb528

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

src/hooks/useOutsideInteraction.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { useCallback, useEffect, useRef, RefObject } from 'react';
2+
3+
type EventType =
4+
| 'mousedown'
5+
| 'mouseup'
6+
| 'touchstart'
7+
| 'touchend'
8+
| 'keydown';
9+
10+
interface UseOutsideInteractionProps {
11+
handleOutsideInteraction: () => void;
12+
events?: EventType[];
13+
}
14+
15+
const defaultEvents: EventType[] = ['mousedown', 'touchstart', 'keydown'];
16+
17+
/**
18+
* 지정된 element 외부의 interaction을 감지하는 hook
19+
* 마우스 클릭, 터치, 키보드 이벤트(Escape 키)를 처리할 수 있습니다.
20+
*
21+
* @param {Object} props - hook props
22+
* @param {() => void} props.handleOutsideInteraction - 외부 interaction 발생 시 실행될 콜백 함수
23+
* @param {EventType[]} [props.events] - 감지할 이벤트 (default :['mousedown', 'touchstart', 'keydown'])
24+
*
25+
* @returns {React.RefObject<HTMLElement>} element에 연결할 ref 객체
26+
*/
27+
28+
const useOutsideInteraction = ({
29+
handleOutsideInteraction,
30+
events = defaultEvents,
31+
}: UseOutsideInteractionProps): RefObject<HTMLElement> => {
32+
const ref = useRef<HTMLElement>(null);
33+
34+
const handleEvent = useCallback(
35+
(event: Event) => {
36+
if (event instanceof KeyboardEvent) {
37+
if (event.key === 'Escape') {
38+
handleOutsideInteraction();
39+
return;
40+
}
41+
}
42+
43+
const target = event.target as Node | null;
44+
if (!target) return;
45+
46+
if (ref.current && !ref.current.contains(target)) {
47+
handleOutsideInteraction();
48+
}
49+
},
50+
[handleOutsideInteraction]
51+
);
52+
53+
useEffect(() => {
54+
if (events.length === 0) return;
55+
56+
events.forEach((event) => document.addEventListener(event, handleEvent));
57+
58+
return () => {
59+
events.forEach((event) =>
60+
document.removeEventListener(event, handleEvent)
61+
);
62+
};
63+
}, [handleEvent, events]);
64+
65+
return ref;
66+
};
67+
68+
export default useOutsideInteraction;

0 commit comments

Comments
 (0)