-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
58 lines (46 loc) · 2.1 KB
/
index.ts
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
import { useLatest } from '../use-latest'
import { useManualStateHistory } from '../use-manual-state-history'
import { usePausableUpdateDeepCompareEffect } from '../use-pausable-update-deep-compare-effect'
import { usePausableUpdateEffect } from '../use-pausable-update-effect'
import { useStableFn } from '../use-stable-fn'
import type { UseManualStateHistoryOptions, UseManualStateHistoryReturns } from '../use-manual-state-history'
import type { Pausable } from '../use-pausable'
export interface UseStateHistoryOptions<Raw, Serialized = Raw> extends UseManualStateHistoryOptions<Raw, Serialized> {
deep?: boolean
}
export interface UseStateHistoryReturns<Raw, Serialized>
extends UseManualStateHistoryReturns<Raw, Serialized>,
Pausable<[commit?: boolean], [commit?: boolean]> {}
/**
* A React Hook that track and manipulate the history of a state automatically.
*/
export function useStateHistory<Raw, Serialized = Raw>(
source: Raw,
options: UseStateHistoryOptions<Raw, Serialized> = {},
): UseStateHistoryReturns<Raw, Serialized> {
const isDeep = options.deep || false
const manualHistory = useManualStateHistory(source, { ...options, clone: options.clone || isDeep })
const pausable = usePausableUpdateEffect(() => latest.current.manualHistory.commit(), isDeep ? [] : [source])
const deepPausable = usePausableUpdateDeepCompareEffect(
() => latest.current.manualHistory.commit(),
isDeep ? [source] : [],
)
const latest = useLatest({ manualHistory, isDeep, deepPausable, pausable })
const pause = useStableFn((update = false, commit = false) => {
const { manualHistory, isDeep, deepPausable, pausable } = latest.current
commit && manualHistory.commit()
;(isDeep ? deepPausable : pausable).pause(update)
})
const resume = useStableFn((update = false, commit = false) => {
const { manualHistory, isDeep, deepPausable, pausable } = latest.current
commit && manualHistory.commit()
;(isDeep ? deepPausable : pausable).resume(update)
})
const isActive = (isDeep ? deepPausable : pausable).isActive
return {
...manualHistory,
isActive,
resume,
pause,
}
}