react-native-lumen 1.1.0 → 1.1.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/README.md +12 -5
- package/lib/module/components/TourOverlay.js +9 -49
- package/lib/module/components/TourOverlay.js.map +1 -1
- package/lib/module/components/TourProvider.js +37 -29
- package/lib/module/components/TourProvider.js.map +1 -1
- package/lib/module/components/TourZone.js +66 -29
- package/lib/module/components/TourZone.js.map +1 -1
- package/lib/module/hooks/useTourScrollView.js +6 -3
- package/lib/module/hooks/useTourScrollView.js.map +1 -1
- package/lib/typescript/src/components/TourOverlay.d.ts.map +1 -1
- package/lib/typescript/src/components/TourProvider.d.ts.map +1 -1
- package/lib/typescript/src/components/TourZone.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useTourScrollView.d.ts +12 -1
- package/lib/typescript/src/hooks/useTourScrollView.d.ts.map +1 -1
- package/lib/typescript/src/types/index.d.ts +20 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/package.json +1 -5
- package/src/components/TourOverlay.tsx +0 -196
- package/src/components/TourProvider.tsx +0 -713
- package/src/components/TourTooltip.tsx +0 -329
- package/src/components/TourZone.tsx +0 -469
- package/src/constants/animations.ts +0 -71
- package/src/constants/defaults.ts +0 -66
- package/src/context/TourContext.ts +0 -4
- package/src/hooks/useTour.ts +0 -10
- package/src/hooks/useTourScrollView.ts +0 -111
- package/src/index.tsx +0 -35
- package/src/types/index.ts +0 -447
- package/src/utils/storage.ts +0 -226
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import { useMemo, memo, useState, type ComponentType } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
StyleSheet,
|
|
4
|
-
Text,
|
|
5
|
-
View,
|
|
6
|
-
Dimensions,
|
|
7
|
-
TouchableOpacity,
|
|
8
|
-
} from 'react-native';
|
|
9
|
-
import Animated, {
|
|
10
|
-
useAnimatedStyle,
|
|
11
|
-
useSharedValue,
|
|
12
|
-
interpolate,
|
|
13
|
-
Extrapolation,
|
|
14
|
-
} from 'react-native-reanimated';
|
|
15
|
-
import { useTour } from '../hooks/useTour';
|
|
16
|
-
import type {
|
|
17
|
-
CardProps,
|
|
18
|
-
InternalTourContextType,
|
|
19
|
-
TooltipStyles,
|
|
20
|
-
} from '../types';
|
|
21
|
-
import { DEFAULT_LABELS } from '../constants/defaults';
|
|
22
|
-
|
|
23
|
-
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');
|
|
24
|
-
|
|
25
|
-
const getDynamicStyles = (tooltipStyles?: TooltipStyles) => {
|
|
26
|
-
const defaultStyles = {
|
|
27
|
-
backgroundColor: tooltipStyles?.backgroundColor || 'white',
|
|
28
|
-
borderRadius: tooltipStyles?.borderRadius || 12,
|
|
29
|
-
titleColor: tooltipStyles?.titleColor || '#000',
|
|
30
|
-
descriptionColor: tooltipStyles?.descriptionColor || '#444',
|
|
31
|
-
primaryButtonColor: tooltipStyles?.primaryButtonColor || '#007AFF',
|
|
32
|
-
primaryButtonTextColor: tooltipStyles?.primaryButtonTextColor || '#fff',
|
|
33
|
-
primaryButtonBorderRadius: tooltipStyles?.primaryButtonBorderRadius || 25,
|
|
34
|
-
skipButtonTextColor: tooltipStyles?.skipButtonTextColor || '#666',
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
return StyleSheet.create({
|
|
38
|
-
cardStyle: {
|
|
39
|
-
backgroundColor: defaultStyles.backgroundColor,
|
|
40
|
-
borderRadius: defaultStyles.borderRadius,
|
|
41
|
-
padding: 20,
|
|
42
|
-
minHeight: 120,
|
|
43
|
-
...(tooltipStyles?.containerStyle || {}),
|
|
44
|
-
},
|
|
45
|
-
title: {
|
|
46
|
-
fontSize: 18,
|
|
47
|
-
fontWeight: 'bold',
|
|
48
|
-
color: defaultStyles.titleColor,
|
|
49
|
-
flex: 1,
|
|
50
|
-
...(tooltipStyles?.titleStyle || {}),
|
|
51
|
-
},
|
|
52
|
-
description: {
|
|
53
|
-
fontSize: 15,
|
|
54
|
-
color: defaultStyles.descriptionColor,
|
|
55
|
-
marginBottom: 20,
|
|
56
|
-
lineHeight: 22,
|
|
57
|
-
...(tooltipStyles?.descriptionStyle || {}),
|
|
58
|
-
},
|
|
59
|
-
buttonPrimary: {
|
|
60
|
-
backgroundColor: defaultStyles.primaryButtonColor,
|
|
61
|
-
paddingVertical: 10,
|
|
62
|
-
paddingHorizontal: 20,
|
|
63
|
-
borderRadius: defaultStyles.primaryButtonBorderRadius,
|
|
64
|
-
...(tooltipStyles?.primaryButtonStyle || {}),
|
|
65
|
-
},
|
|
66
|
-
primaryButtonText: {
|
|
67
|
-
color: defaultStyles.primaryButtonTextColor,
|
|
68
|
-
fontWeight: 'bold',
|
|
69
|
-
fontSize: 14,
|
|
70
|
-
...(tooltipStyles?.primaryButtonTextStyle || {}),
|
|
71
|
-
},
|
|
72
|
-
skipText: {
|
|
73
|
-
color: defaultStyles.skipButtonTextColor,
|
|
74
|
-
fontWeight: '600',
|
|
75
|
-
...(tooltipStyles?.skipButtonTextStyle || {}),
|
|
76
|
-
},
|
|
77
|
-
buttonText: {
|
|
78
|
-
padding: 8,
|
|
79
|
-
...(tooltipStyles?.skipButtonStyle || {}),
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const TourTooltip = memo(() => {
|
|
85
|
-
const {
|
|
86
|
-
targetX,
|
|
87
|
-
targetY,
|
|
88
|
-
targetWidth,
|
|
89
|
-
targetHeight,
|
|
90
|
-
currentStep,
|
|
91
|
-
steps,
|
|
92
|
-
next,
|
|
93
|
-
prev,
|
|
94
|
-
stop,
|
|
95
|
-
opacity,
|
|
96
|
-
config,
|
|
97
|
-
orderedStepKeys,
|
|
98
|
-
} = useTour() as InternalTourContextType;
|
|
99
|
-
|
|
100
|
-
const currentStepData = currentStep ? steps[currentStep] : null;
|
|
101
|
-
|
|
102
|
-
const tooltipHeight = useSharedValue(150);
|
|
103
|
-
const [tooltipWidth] = useState(280);
|
|
104
|
-
|
|
105
|
-
const dynamicStyles = useMemo(
|
|
106
|
-
() => getDynamicStyles(config?.tooltipStyles),
|
|
107
|
-
[config?.tooltipStyles]
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
// Use orderedStepKeys from context (consistent with TourProvider's ordering)
|
|
111
|
-
const orderedSteps = orderedStepKeys;
|
|
112
|
-
|
|
113
|
-
const currentIndex = currentStep ? orderedSteps.indexOf(currentStep) : -1;
|
|
114
|
-
const totalSteps = orderedSteps.length;
|
|
115
|
-
const isFirst = currentIndex === 0;
|
|
116
|
-
const isLast = currentIndex === totalSteps - 1;
|
|
117
|
-
|
|
118
|
-
const tooltipStyle = useAnimatedStyle(() => {
|
|
119
|
-
'worklet';
|
|
120
|
-
|
|
121
|
-
const safeTargetX = targetX.value || 0;
|
|
122
|
-
const safeTargetY = targetY.value || 0;
|
|
123
|
-
const safeTargetWidth = Math.max(targetWidth.value || 0, 1);
|
|
124
|
-
const safeTargetHeight = Math.max(targetHeight.value || 0, 1);
|
|
125
|
-
const safeTooltipHeight = tooltipHeight.value || 150;
|
|
126
|
-
|
|
127
|
-
// FIX: Aggressive Interpolation
|
|
128
|
-
// Map the input value [0 -> 0.6] to output [0 -> 1].
|
|
129
|
-
// This ensures that even if 'opacity.value' stops at 0.7 (backdrop level),
|
|
130
|
-
// the tooltip is already fully opaque (1.0).
|
|
131
|
-
const activeOpacity = interpolate(
|
|
132
|
-
opacity.value,
|
|
133
|
-
[0, 0.6],
|
|
134
|
-
[0, 1],
|
|
135
|
-
Extrapolation.CLAMP
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
const spaceAbove = safeTargetY;
|
|
139
|
-
const spaceBelow = SCREEN_HEIGHT - (safeTargetY + safeTargetHeight);
|
|
140
|
-
|
|
141
|
-
const shouldPlaceAbove =
|
|
142
|
-
(spaceAbove > spaceBelow && spaceAbove > safeTooltipHeight + 30) ||
|
|
143
|
-
(safeTargetY > SCREEN_HEIGHT / 2 && spaceAbove > safeTooltipHeight + 20);
|
|
144
|
-
|
|
145
|
-
const horizontalCenter = safeTargetX + safeTargetWidth / 2;
|
|
146
|
-
const left = horizontalCenter - tooltipWidth / 2;
|
|
147
|
-
|
|
148
|
-
const clampedLeft = Math.max(
|
|
149
|
-
12,
|
|
150
|
-
Math.min(SCREEN_WIDTH - tooltipWidth - 12, left)
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
const style: any = {
|
|
154
|
-
position: 'absolute',
|
|
155
|
-
width: tooltipWidth,
|
|
156
|
-
left: clampedLeft,
|
|
157
|
-
opacity: activeOpacity,
|
|
158
|
-
backgroundColor: config?.tooltipStyles?.backgroundColor || 'white',
|
|
159
|
-
transform: [{ translateY: interpolate(activeOpacity, [0, 1], [10, 0]) }],
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
if (shouldPlaceAbove) {
|
|
163
|
-
style.top = Math.max(10, safeTargetY - safeTooltipHeight - 20);
|
|
164
|
-
style.bottom = undefined;
|
|
165
|
-
} else {
|
|
166
|
-
style.top = safeTargetY + safeTargetHeight + 20;
|
|
167
|
-
style.bottom = undefined;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return style;
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
if (!currentStepData) return null;
|
|
174
|
-
|
|
175
|
-
const AnimatedView = Animated.View as unknown as ComponentType<any>;
|
|
176
|
-
|
|
177
|
-
const handleTooltipLayout = (event: any) => {
|
|
178
|
-
const { height } = event.nativeEvent.layout;
|
|
179
|
-
if (height > 0) {
|
|
180
|
-
tooltipHeight.value = height;
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// Build card props for custom renders
|
|
185
|
-
const cardProps: CardProps = {
|
|
186
|
-
step: currentStepData,
|
|
187
|
-
currentStepIndex: currentIndex,
|
|
188
|
-
totalSteps,
|
|
189
|
-
next,
|
|
190
|
-
prev,
|
|
191
|
-
stop,
|
|
192
|
-
isFirst,
|
|
193
|
-
isLast,
|
|
194
|
-
labels: config?.labels,
|
|
195
|
-
required: currentStepData.required,
|
|
196
|
-
completed: currentStepData.completed,
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
// Priority: Per-step custom card > Global custom card > Default card
|
|
200
|
-
// 1. Per-step custom render (highest priority)
|
|
201
|
-
if (currentStepData.renderCustomCard) {
|
|
202
|
-
return (
|
|
203
|
-
<AnimatedView
|
|
204
|
-
style={[
|
|
205
|
-
styles.container,
|
|
206
|
-
tooltipStyle,
|
|
207
|
-
// Reset styles for custom render so the user has full control
|
|
208
|
-
styles.resetStyle,
|
|
209
|
-
]}
|
|
210
|
-
onLayout={handleTooltipLayout}
|
|
211
|
-
>
|
|
212
|
-
{currentStepData.renderCustomCard(cardProps)}
|
|
213
|
-
</AnimatedView>
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// 2. Global custom render
|
|
218
|
-
if (config?.renderCard) {
|
|
219
|
-
return (
|
|
220
|
-
<AnimatedView
|
|
221
|
-
style={[
|
|
222
|
-
styles.container,
|
|
223
|
-
tooltipStyle,
|
|
224
|
-
// Reset styles for custom render so the user has full control
|
|
225
|
-
styles.resetStyle,
|
|
226
|
-
]}
|
|
227
|
-
onLayout={handleTooltipLayout}
|
|
228
|
-
>
|
|
229
|
-
{config.renderCard(cardProps)}
|
|
230
|
-
</AnimatedView>
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// 3. Default Render
|
|
235
|
-
const labels = { ...DEFAULT_LABELS, ...config?.labels };
|
|
236
|
-
const labelNext = isLast ? labels.finish : labels.next;
|
|
237
|
-
const labelSkip = labels.skip;
|
|
238
|
-
|
|
239
|
-
const isRequired = currentStepData.required === true;
|
|
240
|
-
const isNextDisabled = currentStepData.completed === false;
|
|
241
|
-
|
|
242
|
-
return (
|
|
243
|
-
<AnimatedView
|
|
244
|
-
style={[styles.container, dynamicStyles.cardStyle, tooltipStyle]}
|
|
245
|
-
onLayout={handleTooltipLayout}
|
|
246
|
-
>
|
|
247
|
-
<View style={styles.header}>
|
|
248
|
-
<Text style={dynamicStyles.title}>
|
|
249
|
-
{currentStepData.name || 'Step'}
|
|
250
|
-
</Text>
|
|
251
|
-
<Text style={styles.stepIndicator}>
|
|
252
|
-
{currentIndex + 1} / {totalSteps}
|
|
253
|
-
</Text>
|
|
254
|
-
</View>
|
|
255
|
-
<Text style={dynamicStyles.description}>
|
|
256
|
-
{currentStepData.description}
|
|
257
|
-
</Text>
|
|
258
|
-
|
|
259
|
-
<View style={styles.footer}>
|
|
260
|
-
{!isLast && !isRequired && (
|
|
261
|
-
<TouchableOpacity onPress={stop} style={dynamicStyles.buttonText}>
|
|
262
|
-
<Text style={dynamicStyles.skipText}>{labelSkip}</Text>
|
|
263
|
-
</TouchableOpacity>
|
|
264
|
-
)}
|
|
265
|
-
{(isLast || isRequired) && <View style={styles.spacer} />}
|
|
266
|
-
|
|
267
|
-
<TouchableOpacity
|
|
268
|
-
onPress={isNextDisabled ? undefined : next}
|
|
269
|
-
disabled={isNextDisabled}
|
|
270
|
-
style={[
|
|
271
|
-
dynamicStyles.buttonPrimary,
|
|
272
|
-
isNextDisabled && styles.disabledButton,
|
|
273
|
-
]}
|
|
274
|
-
>
|
|
275
|
-
<Text
|
|
276
|
-
style={[
|
|
277
|
-
dynamicStyles.primaryButtonText,
|
|
278
|
-
isNextDisabled && styles.disabledButtonText,
|
|
279
|
-
]}
|
|
280
|
-
>
|
|
281
|
-
{labelNext}
|
|
282
|
-
</Text>
|
|
283
|
-
</TouchableOpacity>
|
|
284
|
-
</View>
|
|
285
|
-
</AnimatedView>
|
|
286
|
-
);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
const styles = StyleSheet.create({
|
|
290
|
-
container: {
|
|
291
|
-
// Shadow Props
|
|
292
|
-
shadowColor: '#000',
|
|
293
|
-
shadowOffset: { width: 0, height: 4 },
|
|
294
|
-
shadowOpacity: 0.3,
|
|
295
|
-
shadowRadius: 5,
|
|
296
|
-
elevation: 8,
|
|
297
|
-
zIndex: 999,
|
|
298
|
-
},
|
|
299
|
-
header: {
|
|
300
|
-
flexDirection: 'row',
|
|
301
|
-
justifyContent: 'space-between',
|
|
302
|
-
marginBottom: 8,
|
|
303
|
-
},
|
|
304
|
-
stepIndicator: {
|
|
305
|
-
fontSize: 12,
|
|
306
|
-
color: '#999',
|
|
307
|
-
},
|
|
308
|
-
footer: {
|
|
309
|
-
flexDirection: 'row',
|
|
310
|
-
justifyContent: 'space-between',
|
|
311
|
-
alignItems: 'center',
|
|
312
|
-
},
|
|
313
|
-
resetStyle: {
|
|
314
|
-
backgroundColor: 'transparent',
|
|
315
|
-
shadowOpacity: 0,
|
|
316
|
-
elevation: 0,
|
|
317
|
-
padding: 0,
|
|
318
|
-
borderRadius: 0,
|
|
319
|
-
},
|
|
320
|
-
spacer: {
|
|
321
|
-
width: 10,
|
|
322
|
-
},
|
|
323
|
-
disabledButton: {
|
|
324
|
-
opacity: 0.4,
|
|
325
|
-
},
|
|
326
|
-
disabledButtonText: {
|
|
327
|
-
opacity: 0.7,
|
|
328
|
-
},
|
|
329
|
-
});
|