-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Expand file tree
/
Copy pathuseStateList.ts
More file actions
75 lines (70 loc) · 2.14 KB
/
useStateList.ts
File metadata and controls
75 lines (70 loc) · 2.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import { useMemo, useRef } from 'react';
import useMountedState from './useMountedState';
import useUpdate from './useUpdate';
import useUpdateEffect from './useUpdateEffect';
export interface UseStateListReturn<T> {
state: T;
currentIndex: number;
setStateAt: (newIndex: number) => void;
setState: (state: T) => void;
next: () => void;
prev: () => void;
isFirst: boolean;
isLast: boolean;
}
// Add defaultCurrentIndex parameter
export default function useStateList<T>(
stateSet: T[] = [],
defaultCurrentIndex: number = 0
): UseStateListReturn<T> {
const isMounted = useMountedState();
const update = useUpdate();
// Initialize index with defaultCurrentIndex, clamp to valid range
const initialIndex =
stateSet.length === 0
? 0
: Math.max(0, Math.min(defaultCurrentIndex, stateSet.length - 1));
const index = useRef(initialIndex);
// If new state list is shorter than before - switch to the last element
useUpdateEffect(() => {
if (stateSet.length <= index.current) {
index.current = stateSet.length - 1;
update();
}
}, [stateSet.length]);
const actions = useMemo(
() => ({
next: () => actions.setStateAt(index.current + 1),
prev: () => actions.setStateAt(index.current - 1),
setStateAt: (newIndex: number) => {
if (!isMounted()) return;
if (!stateSet.length) return;
if (newIndex === index.current) return;
index.current =
newIndex >= 0
? newIndex % stateSet.length
: stateSet.length + (newIndex % stateSet.length);
update();
},
setState: (state: T) => {
if (!isMounted()) return;
const newIndex = stateSet.length ? stateSet.indexOf(state) : -1;
if (newIndex === -1) {
throw new Error(
`State '${state}' is not a valid state (does not exist in state list)`
);
}
index.current = newIndex;
update();
},
}),
[stateSet]
);
return {
state: stateSet[index.current],
currentIndex: index.current,
isFirst: index.current === 0,
isLast: index.current === stateSet.length - 1,
...actions,
};
}