Skip to content

Commit 634b01d

Browse files
authored
feat: add initial function for default value of useDisclosure (#2)
1 parent d2304d1 commit 634b01d

File tree

3 files changed

+58
-18
lines changed

3 files changed

+58
-18
lines changed

packages/tiny-react-hooks/src/useDisclosure/useDisclosure.demo.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
import { useDisclosure } from './useDisclosure';
22

3-
export default function Component() {
3+
export function Component() {
44
const {
55
isOpen,
66
onClose,
77
onOpen,
88
onToggle,
99
} = useDisclosure();
10+
// const {
11+
// isOpen,
12+
// onClose,
13+
// onOpen,
14+
// onToggle,
15+
// } = useDisclosure(false);
16+
// const {
17+
// isOpen,
18+
// onClose,
19+
// onOpen,
20+
// onToggle,
21+
// } = useDisclosure(() => false);
1022

1123
return (
1224
<>
@@ -18,4 +30,4 @@ export default function Component() {
1830
<button onClick={onToggle}>Toggle</button>
1931
</>
2032
)
21-
}
33+
}

packages/tiny-react-hooks/src/useDisclosure/useDisclosure.test.ts

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,16 @@ describe('useDisclosure()', () => {
1212
expect(typeof result.current.onToggle).toBe('function');
1313
});
1414

15+
describe('with no default value', () => {
16+
it('should return isOpen with false when nothing is passed as argument', () => {
17+
const { result } = renderHook(() => useDisclosure());
18+
expect(result.current.isOpen).toBe(false);
19+
});
20+
});
1521

1622
describe('with default value', () => {
17-
describe('with correct default value as boolean', () => {
18-
describe('should work with default value', () => {
23+
describe('with correct default value', () => {
24+
describe('with default value is a boolean', () => {
1925
it('should return isOpen with true', () => {
2026
const { result } = renderHook(() => useDisclosure(true));
2127
expect(result.current.isOpen).toBe(true);
@@ -24,20 +30,39 @@ describe('useDisclosure()', () => {
2430
const { result } = renderHook(() => useDisclosure(false));
2531
expect(result.current.isOpen).toBe(false);
2632
});
27-
it('should return isOpen with false when nothing is passed as argument', () => {
28-
const { result } = renderHook(() => useDisclosure());
33+
});
34+
35+
describe('with default value is function', () => {
36+
it('should return isOpen with true', () => {
37+
const { result } = renderHook(() => useDisclosure(() => true));
38+
expect(result.current.isOpen).toBe(true);
39+
});
40+
it('should return isOpen with false', () => {
41+
const { result } = renderHook(() => useDisclosure(() => false));
2942
expect(result.current.isOpen).toBe(false);
3043
});
3144
});
3245
});
3346
describe('with incorrect default value type', () => {
34-
it('should throw an error', () => {
35-
const nonBoolean = '' as never;
36-
vi.spyOn(console, 'error').mockImplementation(() => vi.fn());
37-
expect(() => {
38-
renderHook(() => useDisclosure(nonBoolean));
39-
}).toThrowError('defaultValue must be a boolean value');
40-
vi.resetAllMocks();
47+
describe('with default value is a boolean', () => {
48+
it('should throw an error', () => {
49+
const nonBoolean = '' as never;
50+
vi.spyOn(console, 'error').mockImplementation(() => vi.fn());
51+
expect(() => {
52+
renderHook(() => useDisclosure(nonBoolean));
53+
}).toThrowError('defaultValue must be a boolean value');
54+
vi.resetAllMocks();
55+
});
56+
});
57+
describe('with default value is a function', () => {
58+
it('should throw an error', () => {
59+
const nonBoolean = () => '' as never;
60+
vi.spyOn(console, 'error').mockImplementation(() => vi.fn());
61+
expect(() => {
62+
renderHook(() => useDisclosure(nonBoolean));
63+
}).toThrowError('defaultValue must be a boolean value');
64+
vi.resetAllMocks();
65+
});
4166
});
4267
});
4368
});

packages/tiny-react-hooks/src/useDisclosure/useDisclosure.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useState } from 'react';
1+
import { useCallback, useRef, useState } from 'react';
22

33
type UseDisclosureReturn = {
44
isOpen: boolean;
@@ -7,9 +7,11 @@ type UseDisclosureReturn = {
77
onToggle: () => void;
88
}
99

10+
type DisclosureDefaultValue = boolean | (() => boolean);
11+
1012
/**
1113
* Custom hook that handles boolean state with useful utility functions.
12-
* @param {boolean} [defaultValue] - The initial value for the boolean state (default is `false`).
14+
* @param {DisclosureDefaultValue} [defaultValue] - The initial value or produce default value function for the boolean state (default is `false`).
1315
* @returns {UseDisclosureReturn} An object containing the boolean state value and utility functions to manipulate the state.
1416
* @throws Will throw an error if `defaultValue` is an invalid boolean value.
1517
* @public
@@ -18,9 +20,10 @@ type UseDisclosureReturn = {
1820
* const { isOpen, onOpen, onClose, onToggle } = UseDisclosureReturn(true);
1921
* ```
2022
*/
21-
export function useDisclosure(defaultValue = false): UseDisclosureReturn {
22-
if (typeof defaultValue !== 'boolean') throw new Error('defaultValue must be a boolean value');
23-
const [isOpen, setOpen] = useState<boolean>(defaultValue);
23+
export function useDisclosure(init: DisclosureDefaultValue = false): UseDisclosureReturn {
24+
const initialValue = useRef<boolean>(typeof init === 'function' ? init() : init);
25+
if (typeof initialValue.current !== 'boolean') throw new Error('defaultValue must be a boolean value');
26+
const [isOpen, setOpen] = useState<boolean>(initialValue.current);
2427

2528
const onOpen = useCallback(() => {
2629
setOpen(true);

0 commit comments

Comments
 (0)