@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.
Files changed (51) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +93 -0
  3. package/dist/index.cjs +2677 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +753 -0
  6. package/dist/index.d.mts +753 -0
  7. package/dist/index.mjs +2638 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +158 -0
  10. package/src/components/Arrow.tsx +138 -0
  11. package/src/components/Beacon.tsx +141 -0
  12. package/src/components/Floater.tsx +381 -0
  13. package/src/components/Loader.tsx +80 -0
  14. package/src/components/Overlay.tsx +167 -0
  15. package/src/components/Portal.tsx +17 -0
  16. package/src/components/Step.tsx +72 -0
  17. package/src/components/Tooltip/CloseButton.tsx +29 -0
  18. package/src/components/Tooltip/DefaultTooltip.tsx +82 -0
  19. package/src/components/Tooltip/index.tsx +163 -0
  20. package/src/components/TourRenderer.tsx +157 -0
  21. package/src/defaults.ts +64 -0
  22. package/src/global.d.ts +8 -0
  23. package/src/hooks/useControls.ts +219 -0
  24. package/src/hooks/useDebugLogger.ts +58 -0
  25. package/src/hooks/useEventEmitter.ts +55 -0
  26. package/src/hooks/useFocusTrap.ts +72 -0
  27. package/src/hooks/useJoyride.tsx +32 -0
  28. package/src/hooks/useLifecycleEffect.ts +512 -0
  29. package/src/hooks/usePortalElement.ts +49 -0
  30. package/src/hooks/usePropSync.ts +84 -0
  31. package/src/hooks/useScrollEffect.ts +217 -0
  32. package/src/hooks/useTargetPosition.ts +154 -0
  33. package/src/hooks/useTourEngine.ts +106 -0
  34. package/src/index.tsx +23 -0
  35. package/src/literals/index.ts +61 -0
  36. package/src/modules/changes.ts +20 -0
  37. package/src/modules/dom.ts +359 -0
  38. package/src/modules/helpers.tsx +230 -0
  39. package/src/modules/step.ts +156 -0
  40. package/src/modules/store.ts +215 -0
  41. package/src/modules/svg.ts +40 -0
  42. package/src/styles.ts +183 -0
  43. package/src/types/common.ts +315 -0
  44. package/src/types/components.ts +84 -0
  45. package/src/types/events.ts +89 -0
  46. package/src/types/floating.ts +60 -0
  47. package/src/types/index.ts +8 -0
  48. package/src/types/props.ts +124 -0
  49. package/src/types/state.ts +49 -0
  50. package/src/types/step.ts +108 -0
  51. package/src/types/utilities.ts +26 -0
@@ -0,0 +1,80 @@
1
+ import { type CSSProperties, useEffect } from 'react';
2
+
3
+ import { noop } from '~/modules/helpers';
4
+
5
+ import type { LoaderRenderProps, Props, Simplify } from '~/types';
6
+
7
+ type LoaderProps = Simplify<Pick<Props, 'nonce'> & LoaderRenderProps>;
8
+
9
+ const spinnerStyles: CSSProperties = {
10
+ animation: 'joyride-loader-spin 1s linear infinite',
11
+ border: '5px solid rgba(0, 0, 0, 0.1)',
12
+ borderRadius: '50%',
13
+ borderTopColor: '#555',
14
+ };
15
+
16
+ export default function JoyrideLoader({ nonce, step }: LoaderProps) {
17
+ const { loaderComponent } = step;
18
+
19
+ const hasLoaderComponent = Boolean(loaderComponent);
20
+
21
+ useEffect(() => {
22
+ if (hasLoaderComponent) {
23
+ return noop;
24
+ }
25
+
26
+ if (document.getElementById('joyride-loader-animation')) {
27
+ return noop;
28
+ }
29
+
30
+ const style = document.createElement('style');
31
+
32
+ style.id = 'joyride-loader-animation';
33
+
34
+ if (nonce) {
35
+ style.setAttribute('nonce', nonce);
36
+ }
37
+
38
+ style.appendChild(
39
+ document.createTextNode(`
40
+ @keyframes joyride-loader-spin {
41
+ to { transform: rotate(360deg); }
42
+ }
43
+ `),
44
+ );
45
+
46
+ document.head.appendChild(style);
47
+
48
+ return () => {
49
+ const insertedStyle = document.getElementById('joyride-loader-animation');
50
+
51
+ if (insertedStyle?.parentNode) {
52
+ insertedStyle.parentNode.removeChild(insertedStyle);
53
+ }
54
+ };
55
+ }, [hasLoaderComponent, nonce]);
56
+
57
+ if (loaderComponent === null) {
58
+ return null;
59
+ }
60
+
61
+ const { height, width, ...loaderStyle } = step.styles.loader;
62
+
63
+ let content;
64
+
65
+ if (loaderComponent) {
66
+ const CustomLoader = loaderComponent;
67
+
68
+ content = <CustomLoader step={step} />;
69
+ } else {
70
+ content = (
71
+ <div style={{ ...spinnerStyles, height, width, borderTopColor: step.primaryColor }} />
72
+ );
73
+ }
74
+
75
+ return (
76
+ <div className="react-joyride__loader" data-testid="loader" style={loaderStyle}>
77
+ {content}
78
+ </div>
79
+ );
80
+ }
@@ -0,0 +1,167 @@
1
+ import { type CSSProperties, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { useWindowSize } from '@gilbarbara/hooks';
3
+
4
+ import useTargetPosition from '~/hooks/useTargetPosition';
5
+ import { LIFECYCLE } from '~/literals';
6
+ import { getAbsoluteOffset, getDocumentHeight, getElement } from '~/modules/dom';
7
+ import { generateOverlayPath, generateSpotlightPath } from '~/modules/svg';
8
+
9
+ import type { Lifecycle, Simplify, StepMerged } from '~/types';
10
+
11
+ export type OverlayProps = Simplify<
12
+ StepMerged & {
13
+ continuous: boolean;
14
+ lifecycle: Lifecycle;
15
+ onClickOverlay: () => void;
16
+ portalElement?: HTMLElement | null;
17
+ scrolling: boolean;
18
+ waiting: boolean;
19
+ }
20
+ >;
21
+
22
+ const hiddenLifecycles: Lifecycle[] = [LIFECYCLE.BEACON_BEFORE, LIFECYCLE.BEACON];
23
+
24
+ export default function JoyrideOverlay(props: OverlayProps) {
25
+ const {
26
+ blockTargetInteraction,
27
+ continuous,
28
+ hideOverlay,
29
+ lifecycle,
30
+ onClickOverlay,
31
+ overlayClickAction,
32
+ placement,
33
+ portalElement,
34
+ scrolling,
35
+ spotlightPadding,
36
+ spotlightRadius,
37
+ spotlightTarget,
38
+ styles,
39
+ target,
40
+ waiting,
41
+ } = props;
42
+ const windowSize = useWindowSize();
43
+ const targetRect = useTargetPosition(
44
+ spotlightTarget ?? target,
45
+ spotlightPadding,
46
+ scrolling || waiting,
47
+ );
48
+ const overlayRef = useRef<HTMLDivElement>(null);
49
+
50
+ const showSpotlight =
51
+ (lifecycle === LIFECYCLE.TOOLTIP || lifecycle === LIFECYCLE.TOOLTIP_BEFORE) &&
52
+ placement !== 'center';
53
+ const [spotlightReady, setSpotlightReady] = useState(false);
54
+
55
+ const container = portalElement ? (overlayRef.current?.offsetParent as HTMLElement | null) : null;
56
+ const overlayWidth = container?.clientWidth ?? windowSize.width;
57
+ const overlayHeight = container?.clientHeight ?? getDocumentHeight() ?? windowSize.height;
58
+
59
+ const overlayColor = (styles.overlay?.backgroundColor ?? 'rgba(0, 0, 0, 0.5)') as string;
60
+
61
+ const overlayStyles = useMemo(() => {
62
+ const { backgroundColor: _bg, mixBlendMode: _mbm, ...rest } = styles.overlay;
63
+
64
+ return {
65
+ height: overlayHeight,
66
+ pointerEvents: 'none',
67
+ ...rest,
68
+ } as CSSProperties;
69
+ }, [overlayHeight, styles.overlay]);
70
+
71
+ const showCutout = showSpotlight && !scrolling && !waiting;
72
+
73
+ useEffect(() => {
74
+ if (showCutout) {
75
+ requestAnimationFrame(() => setSpotlightReady(true));
76
+ } else {
77
+ setSpotlightReady(false);
78
+ }
79
+ }, [showCutout]);
80
+
81
+ const isHiddenInContinuous = continuous && hiddenLifecycles.includes(lifecycle);
82
+ const isHiddenInNonContinuous = !continuous && lifecycle !== LIFECYCLE.TOOLTIP;
83
+
84
+ if (hideOverlay || (!waiting && (isHiddenInContinuous || isHiddenInNonContinuous))) {
85
+ return null;
86
+ }
87
+
88
+ // When using a custom portal, compute spotlight in layout space (offsetTop/offsetLeft/offsetWidth/offsetHeight)
89
+ // because targetRect uses getBoundingClientRect() which is viewport-relative and doesn't match the SVG's layout space.
90
+ let coverPath = '';
91
+
92
+ if (showCutout) {
93
+ if (portalElement && container) {
94
+ const targetEl = getElement(spotlightTarget ?? target);
95
+
96
+ if (targetEl) {
97
+ const targetOffset = getAbsoluteOffset(targetEl);
98
+ const containerOffset = getAbsoluteOffset(container);
99
+
100
+ coverPath = generateSpotlightPath(
101
+ targetOffset.left - containerOffset.left - spotlightPadding.left,
102
+ targetOffset.top - containerOffset.top - spotlightPadding.top,
103
+ targetEl.offsetWidth + spotlightPadding.left + spotlightPadding.right,
104
+ targetEl.offsetHeight + spotlightPadding.top + spotlightPadding.bottom,
105
+ spotlightRadius,
106
+ );
107
+ }
108
+ } else {
109
+ coverPath = generateSpotlightPath(
110
+ targetRect.left,
111
+ targetRect.top,
112
+ targetRect.width,
113
+ targetRect.height,
114
+ spotlightRadius,
115
+ );
116
+ }
117
+ }
118
+
119
+ const path = generateOverlayPath(overlayWidth, overlayHeight, coverPath);
120
+
121
+ return (
122
+ <div
123
+ ref={overlayRef}
124
+ aria-hidden="true"
125
+ className="react-joyride__overlay"
126
+ data-testid="overlay"
127
+ style={overlayStyles}
128
+ >
129
+ <svg
130
+ className="react-joyride__spotlight"
131
+ data-testid="spotlight"
132
+ style={{
133
+ height: overlayHeight,
134
+ left: 0,
135
+ position: targetRect.isFixed ? 'fixed' : 'absolute',
136
+ top: 0,
137
+ width: overlayWidth,
138
+ }}
139
+ >
140
+ <path
141
+ d={path}
142
+ fill={overlayColor}
143
+ fillRule="evenodd"
144
+ onClick={onClickOverlay}
145
+ style={{
146
+ cursor: overlayClickAction ? 'pointer' : 'default',
147
+ pointerEvents: 'auto',
148
+ }}
149
+ />
150
+ {coverPath && (
151
+ <path
152
+ d={coverPath}
153
+ fill={overlayColor}
154
+ style={{
155
+ opacity: spotlightReady ? 0 : 1,
156
+ pointerEvents: blockTargetInteraction ? 'auto' : 'none',
157
+ transition: 'opacity 0.2s',
158
+ }}
159
+ />
160
+ )}
161
+ {coverPath && Object.keys(styles.spotlight).length > 0 && (
162
+ <path d={coverPath} fill="none" style={{ pointerEvents: 'none' }} {...styles.spotlight} />
163
+ )}
164
+ </svg>
165
+ </div>
166
+ );
167
+ }
@@ -0,0 +1,17 @@
1
+ import type { ReactNode } from 'react';
2
+ import { createPortal } from 'react-dom';
3
+
4
+ interface Props {
5
+ children: ReactNode;
6
+ element: HTMLElement | null;
7
+ }
8
+
9
+ export default function JoyridePortal(props: Props) {
10
+ const { children, element } = props;
11
+
12
+ if (!element) {
13
+ return null;
14
+ }
15
+
16
+ return createPortal(children, element);
17
+ }
@@ -0,0 +1,72 @@
1
+ import { useState } from 'react';
2
+ import is from 'is-lite';
3
+
4
+ import useFocusTrap from '~/hooks/useFocusTrap';
5
+ import { LIFECYCLE } from '~/literals';
6
+ import { getElement } from '~/modules/dom';
7
+ import { validateStep } from '~/modules/step';
8
+ import type { StoreState } from '~/modules/store';
9
+
10
+ import type { Controls, PositionData, Simplify, StepMerged } from '~/types';
11
+
12
+ import Floater from './Floater';
13
+
14
+ type StepProps = Simplify<
15
+ StoreState & {
16
+ continuous: boolean;
17
+ controls: Controls;
18
+ debug: boolean;
19
+ nonce?: string;
20
+ portalElement: HTMLElement | null;
21
+ setPositionData: (name: 'beacon' | 'tooltip', data: PositionData) => void;
22
+ shouldScroll: boolean;
23
+ step: StepMerged;
24
+ updateState: (state: Partial<StoreState>) => void;
25
+ }
26
+ >;
27
+
28
+ export default function JoyrideStep(props: StepProps) {
29
+ const {
30
+ continuous,
31
+ controls,
32
+ index,
33
+ lifecycle,
34
+ nonce,
35
+ portalElement,
36
+ setPositionData,
37
+ shouldScroll,
38
+ size,
39
+ step,
40
+ updateState,
41
+ } = props;
42
+ const [tooltipElement, setTooltipElement] = useState<HTMLElement | null>(null);
43
+
44
+ useFocusTrap(step.disableFocusTrap ? null : tooltipElement, '[data-action=primary]');
45
+
46
+ const target = getElement(step.target);
47
+ const open = lifecycle === LIFECYCLE.TOOLTIP;
48
+
49
+ if (!validateStep(step) || !is.domElement(target)) {
50
+ return null;
51
+ }
52
+
53
+ return (
54
+ <Floater
55
+ key={`JoyrideStep-${index}`}
56
+ continuous={continuous}
57
+ controls={controls}
58
+ index={index}
59
+ lifecycle={lifecycle}
60
+ nonce={nonce}
61
+ open={open}
62
+ portalElement={portalElement}
63
+ setPositionData={setPositionData}
64
+ setTooltipRef={setTooltipElement}
65
+ shouldScroll={shouldScroll}
66
+ size={size}
67
+ step={step}
68
+ target={target}
69
+ updateState={updateState}
70
+ />
71
+ );
72
+ }
@@ -0,0 +1,29 @@
1
+ import type { CSSProperties } from 'react';
2
+
3
+ interface Props {
4
+ styles: CSSProperties;
5
+ }
6
+
7
+ export default function JoyrideTooltipCloseButton({ styles, ...props }: Props) {
8
+ const { color, height, width, ...style } = styles;
9
+
10
+ return (
11
+ <button style={style} type="button" {...props}>
12
+ <svg
13
+ height={typeof height === 'number' ? `${height}px` : height}
14
+ preserveAspectRatio="xMidYMid"
15
+ version="1.1"
16
+ viewBox="0 0 18 18"
17
+ width={typeof width === 'number' ? `${width}px` : width}
18
+ xmlns="http://www.w3.org/2000/svg"
19
+ >
20
+ <g>
21
+ <path
22
+ d="M8.13911129,9.00268191 L0.171521827,17.0258467 C-0.0498027049,17.248715 -0.0498027049,17.6098394 0.171521827,17.8327545 C0.28204354,17.9443526 0.427188206,17.9998706 0.572051765,17.9998706 C0.71714958,17.9998706 0.862013139,17.9443526 0.972581703,17.8327545 L9.0000937,9.74924618 L17.0276057,17.8327545 C17.1384085,17.9443526 17.2832721,17.9998706 17.4281356,17.9998706 C17.5729992,17.9998706 17.718097,17.9443526 17.8286656,17.8327545 C18.0499901,17.6098862 18.0499901,17.2487618 17.8286656,17.0258467 L9.86135722,9.00268191 L17.8340066,0.973848225 C18.0553311,0.750979934 18.0553311,0.389855532 17.8340066,0.16694039 C17.6126821,-0.0556467968 17.254037,-0.0556467968 17.0329467,0.16694039 L9.00042166,8.25611765 L0.967006424,0.167268345 C0.745681892,-0.0553188426 0.387317931,-0.0553188426 0.165993399,0.167268345 C-0.0553311331,0.390136635 -0.0553311331,0.751261038 0.165993399,0.974176179 L8.13920499,9.00268191 L8.13911129,9.00268191 Z"
23
+ fill={color}
24
+ />
25
+ </g>
26
+ </svg>
27
+ </button>
28
+ );
29
+ }
@@ -0,0 +1,82 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ import { getReactNodeText } from '~/modules/helpers';
4
+
5
+ import type { TooltipRenderProps } from '~/types';
6
+
7
+ import CloseButton from './CloseButton';
8
+
9
+ export default function JoyrideDefaultTooltip(props: TooltipRenderProps) {
10
+ const { backProps, closeProps, index, isLastStep, primaryProps, skipProps, step, tooltipProps } =
11
+ props;
12
+ const { buttons, content, styles, title } = step;
13
+ const buttonElements: Record<string, ReactNode> = {};
14
+
15
+ if (buttons.includes('primary')) {
16
+ buttonElements.primary = (
17
+ <button
18
+ data-testid="button-primary"
19
+ style={styles.buttonPrimary}
20
+ type="button"
21
+ {...primaryProps}
22
+ />
23
+ );
24
+ }
25
+
26
+ if (buttons.includes('skip') && !isLastStep) {
27
+ buttonElements.skip = (
28
+ <button
29
+ aria-live="off"
30
+ data-testid="button-skip"
31
+ style={styles.buttonSkip}
32
+ type="button"
33
+ {...skipProps}
34
+ />
35
+ );
36
+ }
37
+
38
+ if (buttons.includes('back') && index > 0) {
39
+ buttonElements.back = (
40
+ <button data-testid="button-back" style={styles.buttonBack} type="button" {...backProps} />
41
+ );
42
+ }
43
+
44
+ buttonElements.close = buttons.includes('close') && (
45
+ <CloseButton data-testid="button-close" styles={styles.buttonClose} {...closeProps} />
46
+ );
47
+
48
+ const ariaProps = title
49
+ ? { 'aria-labelledby': 'joyride-tooltip-title', 'aria-describedby': 'joyride-tooltip-content' }
50
+ : { 'aria-label': getReactNodeText(content), 'aria-describedby': 'joyride-tooltip-content' };
51
+
52
+ return (
53
+ <div
54
+ key="JoyrideTooltip"
55
+ className="react-joyride__tooltip"
56
+ data-joyride-step={index}
57
+ {...(step.id && { 'data-joyride-id': step.id })}
58
+ style={styles.tooltip}
59
+ {...tooltipProps}
60
+ {...ariaProps}
61
+ >
62
+ <div style={styles.tooltipContainer}>
63
+ {title && (
64
+ <h4 id="joyride-tooltip-title" style={styles.tooltipTitle}>
65
+ {title}
66
+ </h4>
67
+ )}
68
+ <div id="joyride-tooltip-content" style={styles.tooltipContent}>
69
+ {content}
70
+ </div>
71
+ </div>
72
+ {buttons.some(b => b === 'back' || b === 'primary' || b === 'skip') && (
73
+ <div style={styles.tooltipFooter}>
74
+ <div style={styles.tooltipFooterSpacer}>{buttonElements.skip}</div>
75
+ {buttonElements.back}
76
+ {buttonElements.primary}
77
+ </div>
78
+ )}
79
+ {buttonElements.close}
80
+ </div>
81
+ );
82
+ }
@@ -0,0 +1,163 @@
1
+ import type { MouseEvent } from 'react';
2
+
3
+ import { ORIGIN } from '~/literals';
4
+ import { getReactNodeText, replaceLocaleContent } from '~/modules/helpers';
5
+
6
+ import type { Controls, StepMerged } from '~/types';
7
+
8
+ import DefaultTooltip from './DefaultTooltip';
9
+
10
+ interface TooltipProps {
11
+ continuous: boolean;
12
+ controls: Controls;
13
+ index: number;
14
+ isLastStep: boolean;
15
+ size: number;
16
+ step: StepMerged;
17
+ }
18
+
19
+ export default function Tooltip(props: TooltipProps) {
20
+ const { continuous, controls, index, isLastStep, size, step } = props;
21
+
22
+ const handleClickBack = (event: MouseEvent<HTMLElement>) => {
23
+ event.preventDefault();
24
+
25
+ controls.prev(ORIGIN.BUTTON_BACK);
26
+ };
27
+
28
+ const handleClickClose = (event: MouseEvent<HTMLElement>) => {
29
+ event.preventDefault();
30
+
31
+ if (step.closeButtonAction === 'skip') {
32
+ controls.skip(ORIGIN.BUTTON_CLOSE);
33
+ } else if (step.closeButtonAction === 'replay') {
34
+ controls.replay(ORIGIN.BUTTON_CLOSE);
35
+ } else {
36
+ controls.close(ORIGIN.BUTTON_CLOSE);
37
+ }
38
+ };
39
+
40
+ const handleClickPrimary = (event: MouseEvent<HTMLElement>) => {
41
+ event.preventDefault();
42
+
43
+ if (!continuous) {
44
+ controls.close(ORIGIN.BUTTON_PRIMARY);
45
+
46
+ return;
47
+ }
48
+
49
+ controls.next(ORIGIN.BUTTON_PRIMARY);
50
+ };
51
+
52
+ const handleClickSkip = (event: MouseEvent<HTMLElement>) => {
53
+ event.preventDefault();
54
+
55
+ controls.skip(ORIGIN.BUTTON_SKIP);
56
+ };
57
+
58
+ const getElementsProps = () => {
59
+ const { back, close, last, next, nextWithProgress, skip } = step.locale;
60
+
61
+ const backText = getReactNodeText(back);
62
+ const closeText = getReactNodeText(close);
63
+ const lastText = getReactNodeText(last);
64
+ const nextText = getReactNodeText(next);
65
+ const skipText = getReactNodeText(skip);
66
+
67
+ let primary = close;
68
+ let primaryText = closeText;
69
+
70
+ if (continuous) {
71
+ primary = next;
72
+ primaryText = nextText;
73
+
74
+ if (step.showProgress && !isLastStep) {
75
+ const labelWithProgress = getReactNodeText(nextWithProgress, {
76
+ step: index + 1,
77
+ steps: size,
78
+ });
79
+
80
+ primary = replaceLocaleContent(nextWithProgress, index + 1, size);
81
+ primaryText = labelWithProgress;
82
+ }
83
+
84
+ if (isLastStep) {
85
+ primary = last;
86
+ primaryText = lastText;
87
+ }
88
+ }
89
+
90
+ return {
91
+ backProps: {
92
+ 'aria-label': backText,
93
+ children: back,
94
+ 'data-action': 'back',
95
+ onClick: handleClickBack,
96
+ role: 'button',
97
+ title: backText,
98
+ },
99
+ closeProps: {
100
+ 'aria-label': closeText,
101
+ children: close,
102
+ 'data-action': 'close',
103
+ onClick: handleClickClose,
104
+ role: 'button',
105
+ title: closeText,
106
+ },
107
+ primaryProps: {
108
+ 'aria-label': primaryText,
109
+ children: primary,
110
+ 'data-action': 'primary',
111
+ onClick: handleClickPrimary,
112
+ role: 'button',
113
+ title: primaryText,
114
+ },
115
+ skipProps: {
116
+ 'aria-label': skipText,
117
+ children: skip,
118
+ 'data-action': 'skip',
119
+ onClick: handleClickSkip,
120
+ role: 'button',
121
+ title: skipText,
122
+ },
123
+ tooltipProps: {
124
+ 'aria-modal': true,
125
+ role: 'alertdialog',
126
+ },
127
+ };
128
+ };
129
+
130
+ // eslint-disable-next-line unused-imports/no-unused-vars
131
+ const { arrowComponent, beaconComponent, tooltipComponent, ...stepProps } = step;
132
+ let component;
133
+
134
+ if (tooltipComponent) {
135
+ const TooltipComponent = tooltipComponent;
136
+
137
+ component = (
138
+ <TooltipComponent
139
+ {...getElementsProps()}
140
+ continuous={continuous}
141
+ controls={controls}
142
+ index={index}
143
+ isLastStep={isLastStep}
144
+ size={size}
145
+ step={stepProps}
146
+ />
147
+ );
148
+ } else {
149
+ component = (
150
+ <DefaultTooltip
151
+ {...getElementsProps()}
152
+ continuous={continuous}
153
+ controls={controls}
154
+ index={index}
155
+ isLastStep={isLastStep}
156
+ size={size}
157
+ step={stepProps}
158
+ />
159
+ );
160
+ }
161
+
162
+ return component;
163
+ }