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

feat(react): useOutsidePointerDown 훅 excludeRefs 신규 props 추가 #635

Merged
merged 4 commits into from
Dec 10, 2024
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
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
Loading