Skip to content

Commit

Permalink
[@mantine/hooks] use-toggle: Add handling for more than two values in…
Browse files Browse the repository at this point in the history
… an array (#2912)

* [@mantine/hooks] use-toggle: Add handling for more than two values in an array

* [@mantine/hooks] use-toggle: Fixes after review
  • Loading branch information
yverby committed Nov 12, 2022
1 parent 4f46576 commit 1f2bd13
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 17 deletions.
19 changes: 19 additions & 0 deletions src/mantine-hooks/src/use-toggle/use-toggle.test.ts
Expand Up @@ -17,6 +17,25 @@ describe('@mantine/hooks/use-toggle', () => {
expect(hook.result.current[0]).toBe('dark');
});

it('correctly toggles more than two values', () => {
const hook = renderHook(() => useToggle(['dark', 'light', 'normal'] as const));

act(() => hook.result.current[1]());
expect(hook.result.current[0]).toBe('light');

act(() => hook.result.current[1]());
expect(hook.result.current[0]).toBe('normal');

act(() => hook.result.current[1]());
expect(hook.result.current[0]).toBe('dark');

act(() => hook.result.current[1]('normal'));
expect(hook.result.current[0]).toBe('normal');

act(() => hook.result.current[1]());
expect(hook.result.current[0]).toBe('dark');
});

it('allows to set value', () => {
const hook = renderHook(() => useToggle(['dark', 'light'] as const));

Expand Down
25 changes: 8 additions & 17 deletions src/mantine-hooks/src/use-toggle/use-toggle.ts
@@ -1,21 +1,12 @@
import { useState } from 'react';
import { useReducer } from 'react';

export function useToggle<T = boolean>(options: readonly [T, T] = [false, true] as any) {
const [state, setState] = useState(options[0]);
export function useToggle<T = boolean>(options: readonly T[] = [false, true] as any) {
const [[option], toggle] = useReducer((state: T[], action: React.SetStateAction<T>) => {
const value = action instanceof Function ? action(state[0]) : action;
const index = Math.abs(state.indexOf(value));

const toggle = (value?: React.SetStateAction<T>) => {
if (typeof value !== 'undefined') {
setState(value);
} else {
setState((current) => {
if (current === options[0]) {
return options[1];
}
return state.slice(index).concat(state.slice(0, index));
}, options as T[]);

return options[0];
});
}
};

return [state, toggle] as const;
return [option, toggle as (value?: React.SetStateAction<T>) => void] as const;
}

0 comments on commit 1f2bd13

Please sign in to comment.