Skip to content

Commit 8243f02

Browse files
committed
Add useOutsideClick hook and documentation
1 parent b072706 commit 8243f02

File tree

5 files changed

+128
-0
lines changed

5 files changed

+128
-0
lines changed

src/hooks/useOutsideClick/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useEffect } from 'react';
2+
3+
export const useOutsideClick = (callback: (T?: any) => void, ref: React.RefObject<HTMLDivElement>) => {
4+
const handleClick = (e: Event) => {
5+
if (ref.current && !ref.current.contains(<HTMLElement>e.target)) {
6+
callback();
7+
}
8+
};
9+
10+
useEffect(() => {
11+
document.addEventListener('click', handleClick);
12+
13+
return () => {
14+
document.removeEventListener('click', handleClick);
15+
};
16+
});
17+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.dropdown-wrapper {
2+
align-items: center;
3+
border: 1px solid var(--structure-color-600);
4+
border-radius: 4px;
5+
display: flex;
6+
flex-direction: column;
7+
height: 500px;
8+
justify-content: center;
9+
width: 500px;
10+
11+
--dropdown-width: 250px;
12+
}
13+
14+
.example-toast {
15+
--toast-top: 82px;
16+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# useOutsideClick
2+
3+
Accepts a `callback` as the first argument that is executed when the user clicks outside of an element that is passed as a `ref`
4+
as a second argument.
5+
6+
```javascript
7+
import { useRef } from 'react';
8+
import { useOutsideClick } from '/hooks/useOutsideClick';
9+
10+
const someComponent = () => {
11+
[...]
12+
const ref = useRef(null);
13+
14+
useOutsideClick(() => alert('You clicked outside the dropdown'), ref);
15+
16+
[...]
17+
}
18+
```
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React, { useState, useRef, useEffect } from 'react';
2+
import Dropdown from '@/components/Dropdown';
3+
import Toast from '@/components/Toast';
4+
import { useOutsideClick } from '@/hooks/useOutsideClick';
5+
import { Meta } from '@storybook/react';
6+
import styles from './useOutsideClick.stories.css';
7+
import mdx from './useOutsideClick.stories.mdx';
8+
9+
const Demo = () => {
10+
const [selectedItem, setSelectedItem] = useState({});
11+
const [wasClicked, setWasClicked] = useState(false);
12+
const ref = useRef(null);
13+
14+
useOutsideClick(() => setWasClicked(true), ref);
15+
16+
const options = [
17+
{
18+
label: 'Option 1',
19+
value: '1'
20+
},
21+
{
22+
label: 'Option 2',
23+
value: '2'
24+
}
25+
];
26+
27+
useEffect(() => {
28+
if (wasClicked) {
29+
setTimeout(() => {
30+
setWasClicked(false);
31+
}, 1000);
32+
}
33+
}, [wasClicked]);
34+
35+
return (
36+
<div className={styles['dropdown-wrapper']}>
37+
{wasClicked && (
38+
<Toast
39+
autoCloseInMilliseconds={1000}
40+
category='success'
41+
message='You clicked outside the Dropdown!'
42+
title='Success'
43+
variablesClassName={styles['example-toast']}
44+
/>
45+
)}
46+
47+
<h4>Click outside of the Dropdown</h4>
48+
<div ref={ref}>
49+
<Dropdown
50+
onChange={setSelectedItem}
51+
options={options}
52+
getItemLabel={item => item.label}
53+
getItemKey={item => item.value}
54+
getItemValue={item => item.value}
55+
getListTitle={item => item.label}
56+
selected={selectedItem}
57+
selectorText='Select'
58+
/>
59+
</div>
60+
</div>
61+
);
62+
};
63+
64+
export default {
65+
title: 'Hooks/useOutsideClick',
66+
component: Demo,
67+
parameters: {
68+
docs: {
69+
page: mdx
70+
}
71+
}
72+
} as Meta;
73+
74+
const Template = () => <Demo />;
75+
export const Default = Template.bind({});

src/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@ export { default as Toggle } from '@/components/Toggle';
2929
export { default as Tooltip } from '@/components/Tooltip';
3030
export { default as UploadAvatar } from '@/components/UploadAvatar';
3131
export * from '@/components/Grid';
32+
33+
export { useOutsideClick } from '@/hooks/useOutsideClick';

0 commit comments

Comments
 (0)