-
Notifications
You must be signed in to change notification settings - Fork 564
/
Copy pathstep.ts
120 lines (101 loc) · 2.95 KB
/
step.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
import { Props as FloaterProps } from 'react-floater';
import deepmerge from 'deepmerge';
import is from 'is-lite';
import { SetRequired } from 'type-fest';
import { defaultFloaterProps, defaultLocale, defaultStep } from '~/defaults';
import getStyles from '~/styles';
import { Props, Step, StepMerged } from '~/types';
import { getElement, hasCustomScrollParent } from './dom';
import { log, omit, pick } from './helpers';
function getTourProps(props: Props) {
return pick(
props,
'beaconComponent',
'disableCloseOnEsc',
'disableOverlay',
'disableOverlayClose',
'disableScrolling',
'disableScrollParentFix',
'floaterProps',
'hideBackButton',
'hideCloseButton',
'locale',
'showProgress',
'showSkipButton',
'spotlightClicks',
'spotlightPadding',
'styles',
'tooltipComponent',
);
}
export function getMergedStep(props: Props, currentStep?: Step): StepMerged {
const step = currentStep ?? {};
const mergedStep = deepmerge.all([defaultStep, getTourProps(props), step], {
isMergeableObject: is.plainObject,
}) as StepMerged;
const mergedStyles = getStyles(props, mergedStep);
const scrollParent = hasCustomScrollParent(
getElement(mergedStep.target),
mergedStep.disableScrollParentFix,
);
const floaterProps = deepmerge.all([
defaultFloaterProps,
props.floaterProps ?? {},
mergedStep.floaterProps ?? {},
]) as SetRequired<FloaterProps, 'options' | 'wrapperOptions'>;
// Set react-floater props
floaterProps.offset = mergedStep.offset;
floaterProps.styles = deepmerge(floaterProps.styles ?? {}, mergedStyles.floaterStyles);
floaterProps.offset += props.spotlightPadding ?? mergedStep.spotlightPadding ?? 0;
if (mergedStep.placementBeacon && floaterProps.wrapperOptions) {
floaterProps.wrapperOptions.placement = mergedStep.placementBeacon;
}
if (scrollParent && floaterProps.options.preventOverflow) {
floaterProps.options.preventOverflow.boundariesElement = 'window';
}
return {
...mergedStep,
locale: deepmerge.all([defaultLocale, props.locale ?? {}, mergedStep.locale || {}]),
floaterProps,
styles: omit(mergedStyles, 'floaterStyles'),
};
}
/**
* Validate if a step is valid
*/
export function validateStep(step: Step, debug: boolean = false): boolean {
if (!is.plainObject(step)) {
log({
title: 'validateStep',
data: 'step must be an object',
warn: true,
debug,
});
return false;
}
if (!step.target) {
log({
title: 'validateStep',
data: 'target is missing from the step',
warn: true,
debug,
});
return false;
}
return true;
}
/**
* Validate if steps are valid
*/
export function validateSteps(steps: Array<Step>, debug: boolean = false): boolean {
if (!is.array(steps)) {
log({
title: 'validateSteps',
data: 'steps must be an array',
warn: true,
debug,
});
return false;
}
return steps.every(d => validateStep(d, debug));
}