@numidev/react-joyride 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +93 -0
- package/dist/index.cjs +2677 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +753 -0
- package/dist/index.d.mts +753 -0
- package/dist/index.mjs +2638 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +158 -0
- package/src/components/Arrow.tsx +138 -0
- package/src/components/Beacon.tsx +141 -0
- package/src/components/Floater.tsx +381 -0
- package/src/components/Loader.tsx +80 -0
- package/src/components/Overlay.tsx +167 -0
- package/src/components/Portal.tsx +17 -0
- package/src/components/Step.tsx +72 -0
- package/src/components/Tooltip/CloseButton.tsx +29 -0
- package/src/components/Tooltip/DefaultTooltip.tsx +82 -0
- package/src/components/Tooltip/index.tsx +163 -0
- package/src/components/TourRenderer.tsx +157 -0
- package/src/defaults.ts +64 -0
- package/src/global.d.ts +8 -0
- package/src/hooks/useControls.ts +219 -0
- package/src/hooks/useDebugLogger.ts +58 -0
- package/src/hooks/useEventEmitter.ts +55 -0
- package/src/hooks/useFocusTrap.ts +72 -0
- package/src/hooks/useJoyride.tsx +32 -0
- package/src/hooks/useLifecycleEffect.ts +512 -0
- package/src/hooks/usePortalElement.ts +49 -0
- package/src/hooks/usePropSync.ts +84 -0
- package/src/hooks/useScrollEffect.ts +217 -0
- package/src/hooks/useTargetPosition.ts +154 -0
- package/src/hooks/useTourEngine.ts +106 -0
- package/src/index.tsx +23 -0
- package/src/literals/index.ts +61 -0
- package/src/modules/changes.ts +20 -0
- package/src/modules/dom.ts +359 -0
- package/src/modules/helpers.tsx +230 -0
- package/src/modules/step.ts +156 -0
- package/src/modules/store.ts +215 -0
- package/src/modules/svg.ts +40 -0
- package/src/styles.ts +183 -0
- package/src/types/common.ts +315 -0
- package/src/types/components.ts +84 -0
- package/src/types/events.ts +89 -0
- package/src/types/floating.ts +60 -0
- package/src/types/index.ts +8 -0
- package/src/types/props.ts +124 -0
- package/src/types/state.ts +49 -0
- package/src/types/step.ts +108 -0
- package/src/types/utilities.ts +26 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import is from 'is-lite';
|
|
2
|
+
|
|
3
|
+
import { defaultFloatingOptions, defaultLocale, defaultOptions, defaultStep } from '~/defaults';
|
|
4
|
+
import { ACTIONS } from '~/literals';
|
|
5
|
+
import getStyles from '~/styles';
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
Actions,
|
|
9
|
+
FloatingOptions,
|
|
10
|
+
Locale,
|
|
11
|
+
Options,
|
|
12
|
+
Props,
|
|
13
|
+
SpotlightPadding,
|
|
14
|
+
State,
|
|
15
|
+
Step,
|
|
16
|
+
StepMerged,
|
|
17
|
+
} from '~/types';
|
|
18
|
+
|
|
19
|
+
import { deepMerge, log, pick } from './helpers';
|
|
20
|
+
|
|
21
|
+
const optionFieldNames = [
|
|
22
|
+
'after',
|
|
23
|
+
'arrowBase',
|
|
24
|
+
'arrowColor',
|
|
25
|
+
'arrowSize',
|
|
26
|
+
'arrowSpacing',
|
|
27
|
+
'backgroundColor',
|
|
28
|
+
'beaconSize',
|
|
29
|
+
'beaconTrigger',
|
|
30
|
+
'before',
|
|
31
|
+
'beforeTimeout',
|
|
32
|
+
'buttons',
|
|
33
|
+
'closeButtonAction',
|
|
34
|
+
'skipBeacon',
|
|
35
|
+
'dismissKeyAction',
|
|
36
|
+
'disableFocusTrap',
|
|
37
|
+
'hideOverlay',
|
|
38
|
+
'skipScroll',
|
|
39
|
+
'blockTargetInteraction',
|
|
40
|
+
'loaderDelay',
|
|
41
|
+
'offset',
|
|
42
|
+
'overlayClickAction',
|
|
43
|
+
'overlayColor',
|
|
44
|
+
'primaryColor',
|
|
45
|
+
'scrollDuration',
|
|
46
|
+
'scrollOffset',
|
|
47
|
+
'showProgress',
|
|
48
|
+
'spotlightPadding',
|
|
49
|
+
'spotlightRadius',
|
|
50
|
+
'targetWaitTimeout',
|
|
51
|
+
'textColor',
|
|
52
|
+
'width',
|
|
53
|
+
'zIndex',
|
|
54
|
+
] as const satisfies ReadonlyArray<keyof Options>;
|
|
55
|
+
|
|
56
|
+
export function getMergedStep(props: Props, currentStep?: Step): StepMerged | null {
|
|
57
|
+
if (!currentStep) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const mergedStep = deepMerge<StepMerged>(
|
|
62
|
+
defaultStep,
|
|
63
|
+
pick(
|
|
64
|
+
props,
|
|
65
|
+
'arrowComponent',
|
|
66
|
+
'beaconComponent',
|
|
67
|
+
'floatingOptions',
|
|
68
|
+
'loaderComponent',
|
|
69
|
+
'locale',
|
|
70
|
+
'styles',
|
|
71
|
+
'tooltipComponent',
|
|
72
|
+
),
|
|
73
|
+
currentStep,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const mergedOptions = deepMerge<Options>(
|
|
77
|
+
defaultOptions,
|
|
78
|
+
props.options ?? {},
|
|
79
|
+
pick(currentStep, ...optionFieldNames),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const mergedStyles = getStyles(props, { ...mergedStep, ...mergedOptions } as StepMerged);
|
|
83
|
+
|
|
84
|
+
const floatingOptions = deepMerge<FloatingOptions>(
|
|
85
|
+
defaultFloatingOptions,
|
|
86
|
+
props.floatingOptions ?? {},
|
|
87
|
+
mergedStep.floatingOptions ?? {},
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
...mergedStep,
|
|
92
|
+
...mergedOptions,
|
|
93
|
+
locale: deepMerge<Locale>(defaultLocale, props.locale ?? {}, mergedStep.locale || {}),
|
|
94
|
+
floatingOptions,
|
|
95
|
+
spotlightPadding: normalizeSpotlightPadding(mergedOptions.spotlightPadding),
|
|
96
|
+
styles: mergedStyles,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function normalizeSpotlightPadding(
|
|
101
|
+
value: number | SpotlightPadding | undefined,
|
|
102
|
+
): Required<SpotlightPadding> {
|
|
103
|
+
if (typeof value === 'number') {
|
|
104
|
+
return { top: value, right: value, bottom: value, left: value };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
top: value?.top ?? 0,
|
|
109
|
+
right: value?.right ?? 0,
|
|
110
|
+
bottom: value?.bottom ?? 0,
|
|
111
|
+
left: value?.left ?? 0,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Decide if the step shouldn't skip the beacon
|
|
117
|
+
*/
|
|
118
|
+
export function shouldHideBeacon(step: Step, state: State, continuous: boolean): boolean {
|
|
119
|
+
const { action } = state;
|
|
120
|
+
|
|
121
|
+
const withContinuous = continuous && ([ACTIONS.PREV, ACTIONS.NEXT] as Actions[]).includes(action);
|
|
122
|
+
|
|
123
|
+
return step.skipBeacon || step.placement === 'center' || withContinuous;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Validate if a step is valid
|
|
128
|
+
*/
|
|
129
|
+
export function validateStep(step: Step, debug: boolean = false): boolean {
|
|
130
|
+
if (!is.plainObject(step)) {
|
|
131
|
+
log(debug, 'tour', 'step must be an object');
|
|
132
|
+
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!step.target) {
|
|
137
|
+
log(debug, 'tour', 'target is missing from the step');
|
|
138
|
+
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Validate if steps are valid
|
|
147
|
+
*/
|
|
148
|
+
export function validateSteps(steps: Array<Step>, debug: boolean = false): boolean {
|
|
149
|
+
if (!is.array(steps)) {
|
|
150
|
+
log(debug, 'tour', 'steps must be an array');
|
|
151
|
+
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return steps.every(d => validateStep(d, debug));
|
|
156
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import deepEqual from '@gilbarbara/deep-equal';
|
|
2
|
+
import is from 'is-lite';
|
|
3
|
+
|
|
4
|
+
import { ACTIONS, LIFECYCLE, STATUS } from '~/literals';
|
|
5
|
+
import { log, omit } from '~/modules/helpers';
|
|
6
|
+
import { getMergedStep } from '~/modules/step';
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
Controls,
|
|
10
|
+
EventData,
|
|
11
|
+
EventHandler,
|
|
12
|
+
Events,
|
|
13
|
+
PositionData,
|
|
14
|
+
Props,
|
|
15
|
+
State,
|
|
16
|
+
Step,
|
|
17
|
+
StepMerged,
|
|
18
|
+
} from '~/types';
|
|
19
|
+
|
|
20
|
+
type Listener = (state: StoreState) => void;
|
|
21
|
+
|
|
22
|
+
/** Internal store state. Extends `State` with positioning tracking. */
|
|
23
|
+
export type StoreState = State & { positioned: boolean };
|
|
24
|
+
|
|
25
|
+
class Store {
|
|
26
|
+
private beaconPosition: PositionData | null = null;
|
|
27
|
+
private readonly debug: boolean;
|
|
28
|
+
private readonly eventListeners: Map<string, Set<EventHandler>> = new Map();
|
|
29
|
+
private readonly listeners: Set<Listener> = new Set();
|
|
30
|
+
private readonly props: Props;
|
|
31
|
+
private snapshot: StoreState;
|
|
32
|
+
private state: StoreState;
|
|
33
|
+
private steps: Array<Step>;
|
|
34
|
+
private tooltipPosition: PositionData | null = null;
|
|
35
|
+
|
|
36
|
+
constructor(options?: Props) {
|
|
37
|
+
const { initialStepIndex, stepIndex, steps = [] } = options ?? {};
|
|
38
|
+
const isControlled = is.number(stepIndex);
|
|
39
|
+
|
|
40
|
+
let startIndex = 0;
|
|
41
|
+
|
|
42
|
+
this.debug = options?.debug ?? false;
|
|
43
|
+
|
|
44
|
+
if (isControlled) {
|
|
45
|
+
startIndex = stepIndex;
|
|
46
|
+
|
|
47
|
+
if (is.number(initialStepIndex)) {
|
|
48
|
+
log(this.debug, 'tour', 'initialStepIndex is ignored in controlled mode');
|
|
49
|
+
}
|
|
50
|
+
} else if (is.number(initialStepIndex)) {
|
|
51
|
+
if (initialStepIndex >= 0 && initialStepIndex < steps.length) {
|
|
52
|
+
startIndex = initialStepIndex;
|
|
53
|
+
} else if (steps.length > 0) {
|
|
54
|
+
log(this.debug, 'tour', 'initialStepIndex is out of bounds');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.props = options ?? { steps: [] };
|
|
59
|
+
this.steps = steps;
|
|
60
|
+
this.state = {
|
|
61
|
+
action: ACTIONS.INIT,
|
|
62
|
+
controlled: isControlled,
|
|
63
|
+
index: startIndex,
|
|
64
|
+
lifecycle: LIFECYCLE.INIT,
|
|
65
|
+
origin: null,
|
|
66
|
+
positioned: false,
|
|
67
|
+
scrolling: false,
|
|
68
|
+
size: steps.length,
|
|
69
|
+
status: steps.length ? STATUS.READY : STATUS.IDLE,
|
|
70
|
+
waiting: false,
|
|
71
|
+
};
|
|
72
|
+
this.snapshot = Object.freeze({ ...this.state });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private applyTransitions(draft: StoreState): StoreState {
|
|
76
|
+
if (draft.status === STATUS.WAITING && draft.size > 0) {
|
|
77
|
+
return { ...draft, status: STATUS.RUNNING };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return draft;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private getStep(nextIndex?: number): StepMerged | null {
|
|
84
|
+
return getMergedStep(this.props, this.steps[nextIndex ?? this.state.index]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public cleanupPositionData = () => {
|
|
88
|
+
this.beaconPosition = null;
|
|
89
|
+
this.tooltipPosition = null;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
public getPositionData = (name: 'beacon' | 'tooltip'): PositionData | null => {
|
|
93
|
+
if (name === 'beacon') {
|
|
94
|
+
return this.beaconPosition;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this.tooltipPosition;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
public getServerSnapshot = (): StoreState => this.snapshot;
|
|
101
|
+
|
|
102
|
+
public getSnapshot = (): StoreState => this.snapshot;
|
|
103
|
+
|
|
104
|
+
public getEventState = (): Omit<StoreState, 'positioned'> => omit(this.snapshot, 'positioned');
|
|
105
|
+
|
|
106
|
+
public getState = (): State => omit(this.snapshot, 'positioned');
|
|
107
|
+
|
|
108
|
+
public setPositionData = (name: 'beacon' | 'tooltip', data: PositionData) => {
|
|
109
|
+
const previous = name === 'beacon' ? this.beaconPosition : this.tooltipPosition;
|
|
110
|
+
|
|
111
|
+
if (previous?.placement !== data.placement) {
|
|
112
|
+
log(this.debug, `step:${this.state.index}`, 'positioned', `${name} ${data.placement}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (name === 'beacon') {
|
|
116
|
+
this.beaconPosition = data;
|
|
117
|
+
} else {
|
|
118
|
+
this.tooltipPosition = data;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const isBeforePhase =
|
|
122
|
+
this.state.lifecycle === LIFECYCLE.BEACON_BEFORE ||
|
|
123
|
+
this.state.lifecycle === LIFECYCLE.TOOLTIP_BEFORE;
|
|
124
|
+
|
|
125
|
+
if (isBeforePhase && !this.state.positioned) {
|
|
126
|
+
this.updateState({ positioned: true });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const onPosition = this.getStep()?.floatingOptions?.onPosition;
|
|
130
|
+
|
|
131
|
+
if (onPosition) {
|
|
132
|
+
onPosition(data);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
public setSteps = (steps: Array<Step>) => {
|
|
137
|
+
this.steps = steps;
|
|
138
|
+
|
|
139
|
+
this.updateState({ size: steps.length });
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
public dispatch = (data: EventData, controls: Controls): void => {
|
|
143
|
+
const handlers = this.eventListeners.get(data.type);
|
|
144
|
+
|
|
145
|
+
if (handlers) {
|
|
146
|
+
for (const handler of handlers) {
|
|
147
|
+
try {
|
|
148
|
+
handler(data, controls);
|
|
149
|
+
} catch {
|
|
150
|
+
// fire-and-forget: don't let subscriber errors break the tour or other subscribers
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
public on = (eventType: Events, handler: EventHandler): (() => void) => {
|
|
157
|
+
let handlers = this.eventListeners.get(eventType);
|
|
158
|
+
|
|
159
|
+
if (!handlers) {
|
|
160
|
+
handlers = new Set();
|
|
161
|
+
this.eventListeners.set(eventType, handlers);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
handlers.add(handler);
|
|
165
|
+
|
|
166
|
+
return () => {
|
|
167
|
+
handlers.delete(handler);
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
public subscribe = (listener: Listener): (() => void) => {
|
|
172
|
+
this.listeners.add(listener);
|
|
173
|
+
|
|
174
|
+
return () => {
|
|
175
|
+
this.listeners.delete(listener);
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
public updateState = (patch: Partial<StoreState>, forceIndex = false) => {
|
|
180
|
+
const { controlled, index } = this.state;
|
|
181
|
+
const previousSnapshot = this.snapshot;
|
|
182
|
+
|
|
183
|
+
const resolvedIndex =
|
|
184
|
+
controlled && !forceIndex && patch.index !== undefined ? index : (patch.index ?? index);
|
|
185
|
+
|
|
186
|
+
const merged: StoreState = {
|
|
187
|
+
action: patch.action ?? this.state.action,
|
|
188
|
+
controlled,
|
|
189
|
+
index: resolvedIndex,
|
|
190
|
+
lifecycle: patch.lifecycle ?? this.state.lifecycle,
|
|
191
|
+
origin: patch.origin ?? null,
|
|
192
|
+
positioned: patch.positioned ?? this.state.positioned,
|
|
193
|
+
scrolling: patch.scrolling ?? this.state.scrolling,
|
|
194
|
+
size: patch.size ?? this.state.size,
|
|
195
|
+
status: patch.status ?? this.state.status,
|
|
196
|
+
waiting: patch.waiting ?? this.state.waiting,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const final = this.applyTransitions(merged);
|
|
200
|
+
|
|
201
|
+
this.state = final;
|
|
202
|
+
|
|
203
|
+
if (!deepEqual(previousSnapshot, final)) {
|
|
204
|
+
this.snapshot = Object.freeze({ ...final });
|
|
205
|
+
|
|
206
|
+
for (const listener of this.listeners) {
|
|
207
|
+
listener(this.snapshot);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export default function createStore(options?: Props) {
|
|
214
|
+
return new Store(options);
|
|
215
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function generateOverlayPath(
|
|
2
|
+
overlayWidth: number,
|
|
3
|
+
overlayHeight: number,
|
|
4
|
+
cutout: string,
|
|
5
|
+
): string {
|
|
6
|
+
let path = `M0 0H${overlayWidth}V${overlayHeight}H0Z`;
|
|
7
|
+
|
|
8
|
+
if (cutout) {
|
|
9
|
+
path += ` ${cutout}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return path;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function generateSpotlightPath(
|
|
16
|
+
x: number,
|
|
17
|
+
y: number,
|
|
18
|
+
width: number,
|
|
19
|
+
height: number,
|
|
20
|
+
borderRadius: number,
|
|
21
|
+
): string {
|
|
22
|
+
if (width <= 0 || height <= 0) {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const r = Math.max(0, Math.min(borderRadius, width / 2, height / 2));
|
|
27
|
+
|
|
28
|
+
let path = `M${x + r} ${y}`;
|
|
29
|
+
|
|
30
|
+
path += `H${x + width - r}`;
|
|
31
|
+
path += `A${r} ${r} 0 0 1 ${x + width} ${y + r}`;
|
|
32
|
+
path += `V${y + height - r}`;
|
|
33
|
+
path += `A${r} ${r} 0 0 1 ${x + width - r} ${y + height}`;
|
|
34
|
+
path += `H${x + r}`;
|
|
35
|
+
path += `A${r} ${r} 0 0 1 ${x} ${y + height - r}`;
|
|
36
|
+
path += `V${y + r}`;
|
|
37
|
+
path += `A${r} ${r} 0 0 1 ${x + r} ${y}Z`;
|
|
38
|
+
|
|
39
|
+
return path;
|
|
40
|
+
}
|
package/src/styles.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { canUseDOM } from '~/modules/dom';
|
|
2
|
+
import { deepMerge } from '~/modules/helpers';
|
|
3
|
+
|
|
4
|
+
import type { Props, StepMerged, Styles } from '~/types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Convert hex to RGB
|
|
8
|
+
*/
|
|
9
|
+
export function hexToRGB(hex: string): Array<number> {
|
|
10
|
+
const shorthandRegex = /^#?([\da-f])([\da-f])([\da-f])$/i;
|
|
11
|
+
const properHex = hex.replace(shorthandRegex, (_m, r, g, b) => r + r + g + g + b + b);
|
|
12
|
+
|
|
13
|
+
const result = /^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})/i.exec(properHex);
|
|
14
|
+
|
|
15
|
+
return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const buttonReset = {
|
|
19
|
+
backgroundColor: 'transparent',
|
|
20
|
+
border: 0,
|
|
21
|
+
borderRadius: 0,
|
|
22
|
+
color: '#555555',
|
|
23
|
+
cursor: 'pointer',
|
|
24
|
+
fontSize: 16,
|
|
25
|
+
lineHeight: 1,
|
|
26
|
+
padding: 0,
|
|
27
|
+
WebkitAppearance: 'none',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const buttonBase = {
|
|
31
|
+
...buttonReset,
|
|
32
|
+
borderRadius: 4,
|
|
33
|
+
padding: 8,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default function getStyles(props: Props, step: StepMerged) {
|
|
37
|
+
const { styles } = props;
|
|
38
|
+
const mergedStyles = deepMerge<Styles>(styles ?? {}, step.styles ?? {});
|
|
39
|
+
let { width } = step;
|
|
40
|
+
|
|
41
|
+
if (canUseDOM()) {
|
|
42
|
+
width = typeof width === 'number' && window.innerWidth < width ? window.innerWidth - 30 : width;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const overlay = {
|
|
46
|
+
bottom: 0,
|
|
47
|
+
left: 0,
|
|
48
|
+
overflow: 'hidden',
|
|
49
|
+
position: 'absolute',
|
|
50
|
+
right: 0,
|
|
51
|
+
top: 0,
|
|
52
|
+
zIndex: step.zIndex,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const defaultStyles = {
|
|
56
|
+
arrow: {
|
|
57
|
+
alignItems: 'center',
|
|
58
|
+
color: step.arrowColor,
|
|
59
|
+
display: 'inline-flex',
|
|
60
|
+
justifyContent: 'center',
|
|
61
|
+
position: 'absolute',
|
|
62
|
+
},
|
|
63
|
+
beaconWrapper: {
|
|
64
|
+
...buttonReset,
|
|
65
|
+
display: 'inline-flex',
|
|
66
|
+
borderRadius: '50%',
|
|
67
|
+
position: 'relative',
|
|
68
|
+
},
|
|
69
|
+
beacon: {
|
|
70
|
+
height: step.beaconSize,
|
|
71
|
+
width: step.beaconSize,
|
|
72
|
+
},
|
|
73
|
+
beaconInner: {
|
|
74
|
+
animation: 'joyride-beacon-inner 1.2s infinite ease-in-out',
|
|
75
|
+
backgroundColor: step.primaryColor,
|
|
76
|
+
borderRadius: '50%',
|
|
77
|
+
display: 'block',
|
|
78
|
+
height: '50%',
|
|
79
|
+
left: '50%',
|
|
80
|
+
opacity: 0.7,
|
|
81
|
+
position: 'absolute',
|
|
82
|
+
top: '50%',
|
|
83
|
+
transform: 'translate(-50%, -50%)',
|
|
84
|
+
width: '50%',
|
|
85
|
+
},
|
|
86
|
+
beaconOuter: {
|
|
87
|
+
animation: 'joyride-beacon-outer 1.2s infinite ease-in-out',
|
|
88
|
+
backgroundColor: `rgba(${hexToRGB(step.primaryColor).join(',')}, 0.2)`,
|
|
89
|
+
border: `2px solid ${step.primaryColor}`,
|
|
90
|
+
borderRadius: '50%',
|
|
91
|
+
boxSizing: 'border-box',
|
|
92
|
+
display: 'block',
|
|
93
|
+
height: '100%',
|
|
94
|
+
left: 0,
|
|
95
|
+
opacity: 0.9,
|
|
96
|
+
position: 'absolute',
|
|
97
|
+
top: 0,
|
|
98
|
+
transformOrigin: 'center',
|
|
99
|
+
width: '100%',
|
|
100
|
+
},
|
|
101
|
+
buttonBack: {
|
|
102
|
+
...buttonBase,
|
|
103
|
+
color: step.primaryColor,
|
|
104
|
+
marginLeft: 'auto',
|
|
105
|
+
marginRight: 5,
|
|
106
|
+
},
|
|
107
|
+
buttonClose: {
|
|
108
|
+
...buttonBase,
|
|
109
|
+
color: step.textColor,
|
|
110
|
+
height: 12,
|
|
111
|
+
padding: 8,
|
|
112
|
+
position: 'absolute',
|
|
113
|
+
right: 0,
|
|
114
|
+
top: 0,
|
|
115
|
+
width: 12,
|
|
116
|
+
},
|
|
117
|
+
buttonPrimary: {
|
|
118
|
+
...buttonBase,
|
|
119
|
+
backgroundColor: step.primaryColor,
|
|
120
|
+
color: step.backgroundColor,
|
|
121
|
+
},
|
|
122
|
+
buttonSkip: {
|
|
123
|
+
...buttonBase,
|
|
124
|
+
color: step.textColor,
|
|
125
|
+
fontSize: 14,
|
|
126
|
+
},
|
|
127
|
+
floater: {
|
|
128
|
+
display: 'inline-block',
|
|
129
|
+
filter: 'drop-shadow(0 0 3px rgba(0, 0, 0, 0.3))',
|
|
130
|
+
maxWidth: '100%',
|
|
131
|
+
transition: 'opacity 0.3s',
|
|
132
|
+
},
|
|
133
|
+
loader: {
|
|
134
|
+
alignItems: 'center',
|
|
135
|
+
display: 'flex',
|
|
136
|
+
height: 48,
|
|
137
|
+
inset: 0,
|
|
138
|
+
justifyContent: 'center',
|
|
139
|
+
pointerEvents: 'none',
|
|
140
|
+
position: 'fixed',
|
|
141
|
+
width: 48,
|
|
142
|
+
zIndex: step.zIndex + 1,
|
|
143
|
+
},
|
|
144
|
+
overlay: {
|
|
145
|
+
...overlay,
|
|
146
|
+
backgroundColor: step.overlayColor,
|
|
147
|
+
},
|
|
148
|
+
spotlight: {},
|
|
149
|
+
tooltip: {
|
|
150
|
+
backgroundColor: step.backgroundColor,
|
|
151
|
+
borderRadius: 5,
|
|
152
|
+
boxSizing: 'border-box',
|
|
153
|
+
color: step.textColor,
|
|
154
|
+
fontSize: 16,
|
|
155
|
+
maxWidth: '100%',
|
|
156
|
+
padding: 12,
|
|
157
|
+
position: 'relative',
|
|
158
|
+
width,
|
|
159
|
+
},
|
|
160
|
+
tooltipContainer: {
|
|
161
|
+
lineHeight: 1.4,
|
|
162
|
+
textAlign: 'center',
|
|
163
|
+
},
|
|
164
|
+
tooltipTitle: {
|
|
165
|
+
fontSize: 18,
|
|
166
|
+
margin: 0,
|
|
167
|
+
},
|
|
168
|
+
tooltipContent: {
|
|
169
|
+
paddingBottom: 12,
|
|
170
|
+
paddingTop: 12,
|
|
171
|
+
},
|
|
172
|
+
tooltipFooter: {
|
|
173
|
+
alignItems: 'center',
|
|
174
|
+
display: 'flex',
|
|
175
|
+
justifyContent: 'flex-end',
|
|
176
|
+
},
|
|
177
|
+
tooltipFooterSpacer: {
|
|
178
|
+
flex: 1,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
return deepMerge<Styles>(defaultStyles, mergedStyles);
|
|
183
|
+
}
|