Skip to content

Commit

Permalink
feat(react): useOutsidePointerDown 훅 excludeRefs 신규 props 추가 (#635)
Browse files Browse the repository at this point in the history
* feat(react): useOutsidePointerDown 훅 excludeRefs 신규 props 추가

* test: useBlockMultipleAsyncCalls isError 테스트 코드 추가 개선

* docs: useEventListener 주석 수정

* docs: useFileReader 한글화 및 테스트 코드 개선
  • Loading branch information
ssi02014 authored Dec 10, 2024
1 parent 508d334 commit c1120fc
Show file tree
Hide file tree
Showing 22 changed files with 398 additions and 161 deletions.
5 changes: 5 additions & 0 deletions .changeset/stale-seals-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/react': minor
---

feat(react): useOutsidePointerDown 훅 excludeRefs 신규 props 추가 - @ssi02014
54 changes: 37 additions & 17 deletions docs/docs/react/components/OutsidePointerDownHandler.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, useRef } from 'react';
import { OutsidePointerDownHandler } from '@modern-kit/react';
import BrowserOnly from '@docusaurus/BrowserOnly';

Expand Down Expand Up @@ -33,9 +33,10 @@ import BrowserOnly from '@docusaurus/BrowserOnly';
## Interface
```ts title="typescript"
interface OutsidePointerDownHandlerProps {
asChild?: boolean;
onPointerDown: () => void;
children: ReactNode;
onPointerDown: (targetElement: HTMLElement) => void;
excludeRefs?: React.RefObject<HTMLElement>[];
asChild?: boolean;
}
```
```ts title="typescript"
Expand All @@ -52,33 +53,52 @@ const OutsidePointerDown: PolyForwardComponent<
import { OutsidePointerDownHandler } from '@modern-kit/react';

const DefaultExample = () => {
const excludeRef = useRef<HTMLDivElement>(null);
const style = {
width: '500px',
height: '100px',
backgroundColor: 'skyBlue',
// ...
};
const excludeStyle = {
// ...
};
return (
<OutsidePointerDownHandler
style={style}
onPointerDown={() => console.log('DefaultExample Outside Clicked!')}>
<div>외부 영역 클릭 후 콘솔을 확인해주세요.</div>
</OutsidePointerDownHandler>
<div style={{ background: 'gray'}}>
<OutsidePointerDownHandler
style={style}
onPointerDown={() => console.log('DefaultExample Outside Clicked!')}
excludeRefs={[excludeRef]}
>
<div>외부 영역 클릭 후 콘솔을 확인해주세요.</div>
</OutsidePointerDownHandler>
<div ref={excludeRef} style={excludeStyle}>외부 클릭 및 터치 감지를 제외할 요소의 ref 배열입니다.</div>
</div>
);
};
```

export const DefaultExample = () => {
const excludeRef = useRef(null);
const style = {
width: '500px',
height: '100px',
backgroundColor: 'skyBlue',
padding: '20px',
};
const excludeStyle = {
width: '300px',
backgroundColor: '#439966',
color: 'white',
padding: '20px',
};
return (
<OutsidePointerDownHandler
style={style}
onPointerDown={() => console.log('DefaultExample Outside Clicked!')}>
외부 영역 클릭 후 콘솔을 확인해주세요.
</OutsidePointerDownHandler>
<div style={{ background: 'gray'}}>
<OutsidePointerDownHandler
style={style}
onPointerDown={() => console.log('DefaultExample Outside Clicked!')}
excludeRefs={[excludeRef]}
>
<div>외부 영역 클릭 후 콘솔을 확인해주세요.</div>
</OutsidePointerDownHandler>
<div ref={excludeRef} style={excludeStyle}>외부 클릭 및 터치 감지를 제외할 요소의 ref 배열입니다.</div>
</div>
);
};

Expand Down
15 changes: 11 additions & 4 deletions docs/docs/react/hooks/useBlockMultipleAsyncCalls.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ import { useBlockMultipleAsyncCalls } from '@modern-kit/react';

## Interface
```ts title="typescript"
function useBlockMultipleAsyncCalls(): {
interface UseBlockMultipleAsyncCallsReturnType {
isError: boolean;
isLoading: boolean;
blockMultipleAsyncCalls: <T>(callback: () => Promise<T>) => Promise<T | undefined>;
};
blockMultipleAsyncCalls: <T>(
callback: () => Promise<T>
) => Promise<T | undefined>;
}
```
```ts title="typescript"
function useBlockMultipleAsyncCalls(): UseBlockMultipleAsyncCallsReturnType
```

## Usage
Expand All @@ -47,7 +53,7 @@ const Example = () => {
const [nonBlockingCount, setNonBlockingCount] = useState(1);
const [value, setValue] = useState<Value | null>(null);
const { isLoading, blockMultipleAsyncCalls } = useBlockMultipleAsyncCalls();
const { isError, isLoading, blockMultipleAsyncCalls } = useBlockMultipleAsyncCalls();
const fetchApi = async () => {
const res = await fetch(
Expand All @@ -71,6 +77,7 @@ const Example = () => {
<p>NonBlockingCount: {nonBlockingCount}</p>
</div>
{isLoading ? <p>로딩중</p> : <p>{value?.title}</p>}
{isError && <p>에러 발생</p>}
</div>
);
};
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/react/hooks/useEventListener.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,23 @@ function useEventListener<K extends keyof WindowEventMap>(
element: Window,
type: K,
listener: (event: WindowEventMap[K]) => void,
options?: AddEventListenerOptions
options?: boolean | AddEventListenerOptions
): void;

// Document Event based useEventListener interface
function useEventListener<K extends keyof DocumentEventMap>(
element: Document,
type: K,
listener: (event: DocumentEventMap[K]) => void,
options?: AddEventListenerOptions
options?: boolean | AddEventListenerOptions
): void;

// MediaQueryList Event based useEventListener interface
function useEventListener<K extends keyof MediaQueryListEventMap>(
element: MediaQueryList,
type: K,
listener: (event: MediaQueryListEventMap[K]) => void,
options?: AddEventListenerOptions
options?: boolean | AddEventListenerOptions
): void;

// Element Event based useEventListener interface
Expand All @@ -57,7 +57,7 @@ function useEventListener<
element: TargetElement<T>,
type: K,
listener: (event: HTMLElementEventMap[K]) => void,
options?: AddEventListenerOptions
options?: boolean | AddEventListenerOptions
): void;

// SVGElement Event based useEventListener interface
Expand All @@ -68,7 +68,7 @@ function useEventListener<
element: TargetElement<T>,
type: K,
listener: (event: SVGElementEventMap[K]) => void,
options?: AddEventListenerOptions
options?: boolean | AddEventListenerOptions
): void;
```

Expand Down
11 changes: 7 additions & 4 deletions docs/docs/react/hooks/useFileReader.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ interface ReadFileOptions {
readType: ReadType;
accepts?: string[];
}

const useFileReader: () => {
```
```ts title="typescript"
function useFileReader(): {
readFile: ({
file,
readType,
Expand All @@ -40,12 +41,14 @@ import React, { useState } from 'react';
import { useFileReader } from '@modern-kit/react';

const Example = () => {
const { readFile, fileContents, loading } = useFileReader()
const { readFile, fileContents, isLoading } = useFileReader()

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if(!e.target.files) return;

readFile({ file: e.target.files, readType: 'readAsText' });
const data = await readFile({ file: e.target.files, readType: 'readAsText' });
// data 처리

/*
* 1. readFile은 Promise<FileContent[]> 반환합니다. 해당 값은 fileContents와 동일합니다.
* ex) const data = await readFile(e.target.files, 'readAsDataURL');
Expand Down
33 changes: 32 additions & 1 deletion docs/docs/react/hooks/useKeyDown.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useKeyDown } from '@modern-kit/react';

# useKeyDown

`ref`를 전달한 요소가 포커싱된 상태에서 `keydown` 이벤트 발생 시 `keyDownCallbackMap`로 지정한 `key`에 트리거되어 콜백 함수를 호출합니다.
Expand Down Expand Up @@ -78,10 +80,39 @@ const Example = () => {
}
});
return <button ref={targetRef}>버튼</button>;
return (
<input
ref={targetRef}
placeholder="포커스를 하고, Enter, Shift, Space 눌러보세요"
style={{ width: '300px' }}
/>
);
};
```

## Example
export const Example = () => {
const targetRef = useKeyDown({
enabled: true, // default: true
keyDownCallbackMap: {
Enter: (event) => console.log('Enter', event.key),
Shift: (event) => console.log('Shift', event.key),
' ': (event) => console.log('Space', event.key),
}
});

return (
<input
ref={targetRef}
placeholder="포커스를 하고, Enter, Shift, Space 눌러보세요"
style={{ width: '300px' }}
/>
);
};

<Example />


## Note
- [Key values for keyboard events(en) - MDN](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)
- [KeyboardEvent.key(en) - MDN](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
Expand Down
62 changes: 41 additions & 21 deletions docs/docs/react/hooks/useOutsidePointerDown.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo, useState } from 'react';
import { useMemo, useState, useRef } from 'react';
import { useOutsidePointerDown } from '@modern-kit/react';
import BrowserOnly from '@docusaurus/BrowserOnly';

Expand All @@ -18,7 +18,10 @@ import BrowserOnly from '@docusaurus/BrowserOnly';
## Interface
```ts title="typescript"
function useOutsidePointerDown<T extends HTMLElement>(
callback: (targetElement: T) => void
callback: (targetElement: T) => void,
options?: {
excludeRefs: React.RefObject<HTMLElement>[];
}
): React.RefObject<T>;
```

Expand All @@ -29,35 +32,37 @@ import { useOutsidePointerDown } from '@modern-kit/react';

const Example = () => {
const [number, setNumber] = useState(0);

const excludeRef = useRef<HTMLDivElement>(null);
const targetRef = useOutsidePointerDown<HTMLDivElement>(() => {
setNumber(number + 1);
}, {
excludeRefs: [excludeRef], // 외부 클릭 및 터치 감지를 제외할 요소의 ref 배열입니다.
});

const outerBoxStyle = useMemo(() => {
return {
width: '400px',
height: '400px',
background: '#439966',
color: '#fff',
};
return { /* ... */ };
}, []);

const InnerBoxStyle = useMemo(() => {
return {
width: '400px',
height: '400px',
background: '#439966',
color: '#fff',
};
return { /* ... */ };
}, []);

const ExcludeBoxStyle = useMemo(() => {
return { /* ... */ };
}, []);

return (
<div style={outerBoxStyle}>
<h3>Inner Box 외부를 클릭해보세요!</h3>
<h3>Target Box 외부를 클릭해보세요!<br />(Exclude Box는 클릭 감지에 제외됩니다.)</h3>
<p>number: {number}</p>

<div ref={targetRef} style={InnerBoxStyle}>
<h3>Inner Box</h3>
<h3>Target Box</h3>
</div>

<div ref={excludeRef} style={ExcludeBoxStyle}>
<h3>Exclude Box</h3>
</div>
</div>
);
Expand All @@ -66,35 +71,50 @@ const Example = () => {

export const Example = () => {
const [number, setNumber] = useState(0);
const excludeRef = useRef(null);
const targetRef = useOutsidePointerDown(() => {
setNumber(number + 1);
}, {
excludeRefs: [excludeRef],
});

const outerBoxStyle = useMemo(() => {
return {
width: '400px',
height: '400px',
background: '#439966',
background: 'blue',
color: '#fff',
};
}, []);

const InnerBoxStyle = useMemo(() => {
return {
width: '400px',
height: '400px',
background: '#439966',
color: '#fff',
padding: '20px',
};
}, []);

const ExcludeBoxStyle = useMemo(() => {
return {
width: '200px',
background: 'red',
color: '#fff',
padding: '20px',
};
}, []);

return (
<div style={outerBoxStyle}>
<h3>Inner Box 외부를 클릭해보세요!</h3>
<h3>Target Box 외부를 클릭해보세요!<br />(Exclude Box는 클릭 감지에 제외됩니다.)</h3>
<p>number: {number}</p>

<div ref={targetRef} style={InnerBoxStyle}>
<h3>Inner Box</h3>
<h3>Target Box</h3>
</div>

<div ref={excludeRef} style={ExcludeBoxStyle}>
<h3>Exclude Box</h3>
</div>
</div>
);
Expand Down
Loading

0 comments on commit c1120fc

Please sign in to comment.