-
Notifications
You must be signed in to change notification settings - Fork 138
/
useActiveStep.ts
129 lines (106 loc) Β· 3.39 KB
/
useActiveStep.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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* @license
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/
import type { MergedTourProps } from './useMergedProps'
import type { ResolvedTourStep } from '../types'
import type { ButtonMode, ButtonSize } from '@idux/components/button'
import type { TourLocale } from '@idux/components/locales'
import { type ComputedRef, watch } from 'vue'
import { isFunction, isNumber, isString, merge } from 'lodash-es'
import { convertElement, useState } from '@idux/cdk/utils'
export function useActiveStep(
mergedProps: ComputedRef<MergedTourProps>,
activeIndex: ComputedRef<number>,
isCurrentMax: ComputedRef<boolean>,
locale: TourLocale,
): ComputedRef<ResolvedTourStep | undefined> {
const [activeStep, setActiveStep] = useState<ResolvedTourStep | undefined>(undefined)
let destructions: (() => Promise<void>)[] = []
const destroySteps = () => {
destructions.forEach(destory => destory())
destructions = []
}
const getActiveStep = async (index: number) => {
const props = mergedProps.value
const step = props.steps?.[index]
if (!step) {
return
}
if (step.beforeEnter) {
await step.beforeEnter()
}
const gap = step.gap ?? props.gap
const mergedGap = merge({ ...props.gap }, isNumber(gap) ? { offset: gap } : gap)
const target = async () => {
if (!step.target) {
return null
}
if (isString(step.target)) {
return document.querySelector(step.target) as HTMLElement
}
if (isFunction(step.target)) {
return convertElement(await step.target()) ?? null
}
return convertElement(step.target) ?? null
}
/* eslint-disable indent */
const nextButton =
step.nextButton === false
? null
: {
size: 'xs' as ButtonSize,
mode: 'primary' as ButtonMode,
...(step.nextButton === true ? {} : step.nextButton),
}
const prevButton =
step.prevButton === false
? null
: {
size: 'xs' as ButtonSize,
...(step.prevButton === true ? {} : step.prevButton),
}
/* eslint-enable indent */
return {
...step,
index,
target,
targetDisabled: step.targetDisabled ?? props.targetDisabled,
gap: mergedGap,
mask: step.mask ?? props.mask,
placement: step.placement ?? props.placement,
showArrow: step.showArrow ?? props.showArrow,
nextButton,
prevButton,
nextButtonText: step.nextButtonText ?? (isCurrentMax.value ? locale.finishText : locale.nextText),
prevButtonText: step.prevButtonText ?? locale.prevText,
scrollIntoViewOptions: step.scrollIntoViewOptions ?? props.scrollIntoViewOptions,
}
}
const pushCurrentUpdate = async (index: number) => {
if (index < 0) {
setActiveStep(undefined)
return
}
const promise = getActiveStep(index)
destructions.push(async () => {
const step = await promise
step?.afterLeave?.()
})
const step = await promise
if (activeIndex.value === index) {
setActiveStep(step)
}
}
watch(
[activeIndex, () => mergedProps.value.steps, mergedProps],
([current]) => {
destroySteps()
pushCurrentUpdate(current)
},
{ immediate: true, flush: 'post', deep: true },
)
return activeStep
}