Skip to content

Commit

Permalink
merge: useDisclosure 훅 구현 (#22)
Browse files Browse the repository at this point in the history
merge: useDisclosure 훅 구현 (#22)
  • Loading branch information
d0422 authored Jun 6, 2024
2 parents def1755 + 426ba2c commit 6813cac
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 0 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,35 @@ function App() {
}
```
### useDisclosure
`useDisclosure` is a custom hook for managing the open/closed state of a component. It initializes the state and provides open and close functions to control the component's visibility. This allows for easy and efficient control of the modal, disclosure, ...etc's open/closed state.
```tsx
import useBoolean from '../useBoolean/useBoolean';
import { useCallback } from 'react';

export type UseDisclosureReturn = ReturnType<typeof useDisclosure>;

export default function useDisclosure(defaultValue: boolean = false) {
const [isOpen, setIsOpen] = useBoolean(defaultValue);

const open = useCallback(() => {
setIsOpen(true);
}, [setIsOpen]);

const close = useCallback(() => {
setIsOpen(false);
}, [setIsOpen]);

return {
isOpen,
open,
close,
};
}
```
#### Generic
`<T>`: Type of data stored on local storage.
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import useRadio from './useRadio/useRadio';
import useThrottle from './useThrottle/useThrottle';
import useDebounce from './useDebounce/useDebounce';
import useLocalStorage from './useLocalStorage/useLocalStorage';
import useDisclosure from './useDisclosure/useDisclosure';

export {
useInput,
Expand All @@ -24,4 +25,5 @@ export {
useThrottle,
useDebounce,
useLocalStorage,
useDisclosure,
};
19 changes: 19 additions & 0 deletions src/stories/useDisclosure/Disclosure.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Meta, StoryObj } from '@storybook/react';
import UseDisclosureExample from './UseDisclosureExample';

const meta = {
title: 'hooks/useDisclosure',
component: UseDisclosureExample,
parameters: {
layout: 'centered',
docs: {
canvas: {},
},
},
} satisfies Meta<typeof UseDisclosureExample>;

export default meta;

type Story = StoryObj<typeof meta>;

export const defaultStory: Story = {};
56 changes: 56 additions & 0 deletions src/stories/useDisclosure/Docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Canvas, Meta, Description } from '@storybook/blocks';
import * as DisclosureStories from './Disclosure.stories';

<Meta of={DisclosureStories} />

# useDisclosure

useDisclosure를 통해 선언적으로 Modal, Disclosure등의 컴포넌트를 관리할 수 있습니다.

## 함수인자

defaultValue를 통해 초기 요소의 열림/닫힘 상태를 결정할 수 있습니다.

## 반환값

### `isOpen` (default `false`)

요소의 열림 상태를 나타냅니다. 요소가 열려있으면 `true`, 아니면 `false`입니다.

### `open`

요소를 열림 상태로 전환합니다.

### `close`

요소를 닫힘 상태로 전환합니다.

## 기본 사용 예시

```typescript
import useDisclosure from '../../useDisclosure/useDisclosure';
import React from 'react';

export default function UseDisclosureExample() {
const modal = useDisclosure(false);

const handleOpenModal = () => {
modal.open();
};
const handleCloseModal = () => {
modal.close();
};

return (
<label className="switch">
<button onClick={handleOpenModal}>open</button>
<dialog open={modal.isOpen}>
Hello World
<button onClick={handleCloseModal}>close</button>
</dialog>
</label>
);
}
```

<Canvas of={DisclosureStories.defaultStory} />
23 changes: 23 additions & 0 deletions src/stories/useDisclosure/UseDisclosureExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import useDisclosure from '../../useDisclosure/useDisclosure';
import React from 'react';

export default function UseDisclosureExample() {
const modal = useDisclosure(false);

const handleOpenModal = () => {
modal.open();
};
const handleCloseModal = () => {
modal.close();
};

return (
<label className="switch">
<button onClick={handleOpenModal}>open</button>
<dialog open={modal.isOpen}>
Hello World
<button onClick={handleCloseModal}>close</button>
</dialog>
</label>
);
}
28 changes: 28 additions & 0 deletions src/useDisclosure/_useDisclosure.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import useDisclosure from './useDisclosure';
import { renderHook, act } from '@testing-library/react';

describe('useDisclosure 기능테스트', () => {
it('useDisclosure는 modal, disclosure와 같이 컴포넌트의 열림과 닫힘 상태를 조절할 수 있는 기능들을 반환한다.', () => {
const { result } = renderHook(() => useDisclosure(false));

expect(result.current.isOpen).toBe(false);
act(() => {
result.current.open();
});
expect(result.current.isOpen).toBe(true);
act(() => {
result.current.close();
});
expect(result.current.isOpen).toBe(false);
});

it('useDisclosure는 초기값을 파라미터로 받는다.', () => {
const { result: resultFalse } = renderHook(() => useDisclosure(false));
const { result: resultTrue } = renderHook(() => useDisclosure(true));
const maybeFalse = resultFalse.current.isOpen;
const maybeTrue = resultTrue.current.isOpen;

expect(maybeFalse).toBe(false);
expect(maybeTrue).toBe(true);
});
});
22 changes: 22 additions & 0 deletions src/useDisclosure/useDisclosure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import useBoolean from '../useBoolean/useBoolean';
import { useCallback } from 'react';

export type UseDisclosureReturn = ReturnType<typeof useDisclosure>;

export default function useDisclosure(defaultValue: boolean = false) {
const [isOpen, setIsOpen] = useBoolean(defaultValue);

const open = useCallback(() => {
setIsOpen(true);
}, [setIsOpen]);

const close = useCallback(() => {
setIsOpen(false);
}, [setIsOpen]);

return {
isOpen,
open,
close,
};
}

0 comments on commit 6813cac

Please sign in to comment.