related-ui-components 3.2.8 → 3.3.0
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/lib/module/components/Card/templates/SelaDealCard.js +0 -10
- package/lib/module/components/Card/templates/SelaDealCard.js.map +1 -1
- package/lib/module/components/RangeSlider/RangeSlider.js +103 -14
- package/lib/module/components/RangeSlider/RangeSlider.js.map +1 -1
- package/lib/module/components/Wheel/Wheel.js +32 -80
- package/lib/module/components/Wheel/Wheel.js.map +1 -1
- package/lib/typescript/src/components/Card/templates/SelaDealCard.d.ts.map +1 -1
- package/lib/typescript/src/components/RangeSlider/RangeSlider.d.ts +7 -0
- package/lib/typescript/src/components/RangeSlider/RangeSlider.d.ts.map +1 -1
- package/lib/typescript/src/components/Wheel/Wheel.d.ts.map +1 -1
- package/package.json +81 -81
- package/src/components/Card/templates/SelaDealCard.tsx +0 -11
- package/src/components/RangeSlider/RangeSlider.tsx +141 -36
- package/src/components/Wheel/Wheel.tsx +39 -83
|
@@ -22,55 +22,25 @@ export interface SpinWheelItem {
|
|
|
22
22
|
|
|
23
23
|
//default random colors
|
|
24
24
|
const colors = [
|
|
25
|
-
"#FF0000",
|
|
26
|
-
"#
|
|
27
|
-
"#
|
|
28
|
-
"#
|
|
29
|
-
"#
|
|
30
|
-
"#800080", // Purple
|
|
31
|
-
"#FFC0CB", // Pink
|
|
32
|
-
"#00FFFF", // Cyan
|
|
33
|
-
"#FF00FF", // Magenta
|
|
34
|
-
"#00FF00", // Lime
|
|
35
|
-
"#4B0082", // Indigo
|
|
36
|
-
"#EE82EE", // Violet
|
|
37
|
-
"#40E0D0", // Turquoise
|
|
38
|
-
"#FFD700", // Gold
|
|
39
|
-
"#C0C0C0", // Silver
|
|
40
|
-
"#FFDAB9", // Peach
|
|
41
|
-
"#E6E6FA", // Lavender
|
|
42
|
-
"#008080", // Teal
|
|
43
|
-
"#FF7F50", // Coral
|
|
44
|
-
"#DC143C", // Crimson
|
|
45
|
-
"#87CEEB", // Sky Blue
|
|
46
|
-
"#7FFF00", // Chartreuse
|
|
47
|
-
"#CCCCFF", // Periwinkle
|
|
48
|
-
"#FF6347", // Tomato
|
|
49
|
-
"#FA8072", // Salmon
|
|
25
|
+
"#FF0000", "#FFA500", "#FFFF00", "#008000", "#0000FF", "#800080",
|
|
26
|
+
"#FFC0CB", "#00FFFF", "#FF00FF", "#00FF00", "#4B0082", "#EE82EE",
|
|
27
|
+
"#40E0D0", "#FFD700", "#C0C0C0", "#FFDAB9", "#E6E6FA", "#008080",
|
|
28
|
+
"#FF7F50", "#DC143C", "#87CEEB", "#7FFF00", "#CCCCFF", "#FF6347",
|
|
29
|
+
"#FA8072",
|
|
50
30
|
];
|
|
51
31
|
|
|
52
32
|
interface SpinWheelProps {
|
|
53
|
-
// Data
|
|
54
33
|
items: SpinWheelItem[];
|
|
55
34
|
predeterminedWinner?: SpinWheelItem | string | number;
|
|
56
|
-
|
|
57
|
-
// Dimensions
|
|
58
35
|
size?: number;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
minSpinDuration?: number; // buffer in ms before stopping
|
|
63
|
-
|
|
64
|
-
// Behavior
|
|
36
|
+
startSpin?: boolean;
|
|
37
|
+
winner?: SpinWheelItem | string | number;
|
|
38
|
+
minSpinDuration?: number;
|
|
65
39
|
spinDuration?: number;
|
|
66
40
|
friction?: number;
|
|
67
41
|
enabled?: boolean;
|
|
68
|
-
|
|
69
|
-
// Events
|
|
70
42
|
onSpinStart?: () => void;
|
|
71
43
|
onSpinEnd?: (item: SpinWheelItem) => void;
|
|
72
|
-
|
|
73
|
-
// Styling
|
|
74
44
|
containerStyle?: ViewStyle;
|
|
75
45
|
centerStyle?: ViewStyle;
|
|
76
46
|
spinButtonText?: string;
|
|
@@ -79,17 +49,19 @@ interface SpinWheelProps {
|
|
|
79
49
|
actionButtonStyle?: ViewStyle;
|
|
80
50
|
actionButtonTextStyle?: TextStyle;
|
|
81
51
|
actionButtonProps?: Partial<Omit<AppButtonProps, "title" | "onPress">>;
|
|
82
|
-
|
|
83
52
|
wheelBorderColor?: string;
|
|
84
53
|
wheelBorderWidth?: number;
|
|
85
54
|
wheelTextColor?: string;
|
|
86
55
|
knobColor?: string;
|
|
87
|
-
|
|
88
56
|
centerSize?: number;
|
|
89
|
-
|
|
90
|
-
centerComponent?: React.ReactNode; // Note: centerComponent prop is declared but not used
|
|
57
|
+
centerComponent?: React.ReactNode;
|
|
91
58
|
}
|
|
92
59
|
|
|
60
|
+
// Constants for consistent animation
|
|
61
|
+
const ROTATION_DURATION = 2500; // Duration for one full rotation
|
|
62
|
+
const DECEL_DURATION = 3000; // Duration for deceleration phase
|
|
63
|
+
const EXTRA_SPINS = 3; // Number of extra full rotations before stopping
|
|
64
|
+
|
|
93
65
|
const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
94
66
|
items,
|
|
95
67
|
size = 300,
|
|
@@ -119,19 +91,16 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
119
91
|
|
|
120
92
|
const [spinning, setSpinning] = useState(false);
|
|
121
93
|
const rotateValue = useRef(new Animated.Value(0)).current;
|
|
122
|
-
|
|
123
|
-
// Track rotation manually for calculations
|
|
124
94
|
const rotationRef = useRef(0);
|
|
125
95
|
|
|
126
96
|
const startInfiniteSpin = () => {
|
|
127
97
|
rotateValue.setValue(rotationRef.current);
|
|
128
|
-
|
|
129
98
|
spinStartTime.current = Date.now();
|
|
130
99
|
|
|
131
100
|
spinLoop.current = Animated.loop(
|
|
132
101
|
Animated.timing(rotateValue, {
|
|
133
|
-
toValue: rotationRef.current + 1,
|
|
134
|
-
duration:
|
|
102
|
+
toValue: rotationRef.current + 1,
|
|
103
|
+
duration: ROTATION_DURATION,
|
|
135
104
|
easing: Easing.linear,
|
|
136
105
|
useNativeDriver: true,
|
|
137
106
|
})
|
|
@@ -154,26 +123,38 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
154
123
|
const index = items.findIndex((i) => i.id === winnerId);
|
|
155
124
|
if (index === -1) return;
|
|
156
125
|
|
|
126
|
+
// Calculate target angle (pointer at top = 270 degrees)
|
|
127
|
+
const anglePerItem = 360 / items.length;
|
|
157
128
|
const segmentCenter = (index + 0.5) * anglePerItem;
|
|
158
129
|
const targetAngle = (270 - segmentCenter + 360) % 360;
|
|
159
130
|
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
131
|
+
// Get current rotation position
|
|
132
|
+
const currentRotation = rotationRef.current;
|
|
133
|
+
const currentAngle = (currentRotation * 360) % 360;
|
|
134
|
+
|
|
135
|
+
// Calculate shortest path to target
|
|
136
|
+
let offset = (targetAngle - currentAngle + 360) % 360;
|
|
137
|
+
|
|
138
|
+
// Add extra full rotations for dramatic effect
|
|
139
|
+
const extraRotations = EXTRA_SPINS * 360;
|
|
140
|
+
const totalRotation = offset + extraRotations;
|
|
141
|
+
|
|
142
|
+
// Final rotation value
|
|
143
|
+
const finalRotation = currentRotation + totalRotation / 360;
|
|
144
|
+
|
|
145
|
+
// Use ease-out cubic for smooth deceleration
|
|
165
146
|
Animated.timing(rotateValue, {
|
|
166
147
|
toValue: finalRotation,
|
|
167
|
-
duration:
|
|
148
|
+
duration: DECEL_DURATION,
|
|
168
149
|
easing: Easing.out(Easing.cubic),
|
|
169
150
|
useNativeDriver: true,
|
|
170
151
|
}).start(() => {
|
|
152
|
+
rotationRef.current = finalRotation;
|
|
171
153
|
setSpinning(false);
|
|
172
154
|
onSpinEnd?.(items[index]);
|
|
173
155
|
});
|
|
174
156
|
};
|
|
175
157
|
|
|
176
|
-
// Update tracked rotation when animation completes
|
|
177
158
|
useEffect(() => {
|
|
178
159
|
const listener = rotateValue.addListener(({ value }) => {
|
|
179
160
|
rotationRef.current = value;
|
|
@@ -184,10 +165,8 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
184
165
|
};
|
|
185
166
|
}, [rotateValue]);
|
|
186
167
|
|
|
187
|
-
// Calculate angle for each segment
|
|
188
168
|
const anglePerItem = wheelItems.length > 0 ? 360 / wheelItems.length : 0;
|
|
189
169
|
|
|
190
|
-
// Create wheel segments
|
|
191
170
|
const generateWheelPaths = () => {
|
|
192
171
|
if (wheelItems.length === 0) return [];
|
|
193
172
|
return wheelItems.map((item, index) => {
|
|
@@ -215,17 +194,11 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
215
194
|
const textX = size / 2 + size * 0.32 * Math.cos(midRad);
|
|
216
195
|
const textY = size / 2 + size * 0.32 * Math.sin(midRad);
|
|
217
196
|
|
|
218
|
-
// decorationX and decorationY are calculated but not used in the provided JSX
|
|
219
|
-
// const decorationX = size / 2 + size * 0.43 * Math.cos(midRad);
|
|
220
|
-
// const decorationY = size / 2 + size * 0.43 * Math.sin(midRad);
|
|
221
|
-
|
|
222
197
|
return {
|
|
223
198
|
path: pathData,
|
|
224
199
|
item,
|
|
225
200
|
textX,
|
|
226
201
|
textY,
|
|
227
|
-
// decorationX,
|
|
228
|
-
// decorationY,
|
|
229
202
|
angle: (startAngle + endAngle) / 2,
|
|
230
203
|
};
|
|
231
204
|
});
|
|
@@ -244,9 +217,8 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
244
217
|
}, delay);
|
|
245
218
|
|
|
246
219
|
return () => clearTimeout(timeout);
|
|
247
|
-
}, [winner]);
|
|
220
|
+
}, [winner, spinning]);
|
|
248
221
|
|
|
249
|
-
// Animation interpolation for rotation
|
|
250
222
|
const rotate = rotateValue.interpolate({
|
|
251
223
|
inputRange: [0, 1],
|
|
252
224
|
outputRange: ["0deg", "360deg"],
|
|
@@ -257,7 +229,6 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
257
229
|
return (
|
|
258
230
|
<View style={[styles.container, containerStyle]}>
|
|
259
231
|
<View style={{ width: size, height: size }}>
|
|
260
|
-
{/* The wheel */}
|
|
261
232
|
<Animated.View
|
|
262
233
|
style={[
|
|
263
234
|
styles.wheelContainer,
|
|
@@ -271,7 +242,7 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
271
242
|
>
|
|
272
243
|
<Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
|
|
273
244
|
<G>
|
|
274
|
-
{wheelPaths.map(({ path, item, textX, textY, angle }
|
|
245
|
+
{wheelPaths.map(({ path, item, textX, textY, angle }) => {
|
|
275
246
|
return (
|
|
276
247
|
<React.Fragment key={item.id}>
|
|
277
248
|
<Path
|
|
@@ -281,8 +252,6 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
281
252
|
? colors[Math.floor(Math.random() * colors.length)]
|
|
282
253
|
: item.color
|
|
283
254
|
}
|
|
284
|
-
// stroke="#FA8072"
|
|
285
|
-
// strokeWidth={1}
|
|
286
255
|
/>
|
|
287
256
|
<SvgText
|
|
288
257
|
x={textX}
|
|
@@ -292,7 +261,7 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
292
261
|
fontWeight={(wheelTextStyle?.fontWeight as any) || "bold"}
|
|
293
262
|
textAnchor="middle"
|
|
294
263
|
alignmentBaseline="central"
|
|
295
|
-
transform={`rotate(${angle + 180}, ${textX}, ${textY}
|
|
264
|
+
transform={`rotate(${angle + 180}, ${textX}, ${textY})`}
|
|
296
265
|
>
|
|
297
266
|
{item.label}
|
|
298
267
|
</SvgText>
|
|
@@ -314,14 +283,12 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
314
283
|
</Svg>
|
|
315
284
|
</Animated.View>
|
|
316
285
|
|
|
317
|
-
{/* The center circle */}
|
|
318
286
|
{centerComponent ? (
|
|
319
287
|
<View
|
|
320
288
|
style={{
|
|
321
289
|
position: "absolute",
|
|
322
290
|
top: "50%",
|
|
323
291
|
left: "50%",
|
|
324
|
-
// Center the component perfectly
|
|
325
292
|
transform: [
|
|
326
293
|
{ translateX: -(actualCenterSize / 2) },
|
|
327
294
|
{ translateY: -(actualCenterSize / 2) },
|
|
@@ -349,7 +316,6 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
349
316
|
/>
|
|
350
317
|
)}
|
|
351
318
|
|
|
352
|
-
{/* The pointer is a triangle on top */}
|
|
353
319
|
<View
|
|
354
320
|
style={[
|
|
355
321
|
styles.pointerPosition,
|
|
@@ -365,7 +331,6 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
365
331
|
/>
|
|
366
332
|
</View>
|
|
367
333
|
|
|
368
|
-
{/* Action Button */}
|
|
369
334
|
<View
|
|
370
335
|
style={{
|
|
371
336
|
position: "absolute",
|
|
@@ -384,15 +349,6 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
384
349
|
textStyle={[styles.actionButtonText, actionButtonTextStyle]}
|
|
385
350
|
{...actionButtonProps}
|
|
386
351
|
/>
|
|
387
|
-
{/* <TouchableOpacity
|
|
388
|
-
onPress={handleSpin}
|
|
389
|
-
disabled={spinning || !enabled || wheelItems.length === 0}
|
|
390
|
-
style={[styles.actionButton, actionButtonStyle]}
|
|
391
|
-
>
|
|
392
|
-
<Text style={[styles.actionButtonText, actionButtonTextStyle]}>
|
|
393
|
-
{spinButtonText}
|
|
394
|
-
</Text>
|
|
395
|
-
</TouchableOpacity> */}
|
|
396
352
|
</View>
|
|
397
353
|
</View>
|
|
398
354
|
</View>
|
|
@@ -404,7 +360,7 @@ const styles = StyleSheet.create({
|
|
|
404
360
|
alignItems: "center",
|
|
405
361
|
justifyContent: "center",
|
|
406
362
|
marginTop: 20,
|
|
407
|
-
marginBottom: 70,
|
|
363
|
+
marginBottom: 70,
|
|
408
364
|
},
|
|
409
365
|
wheelContainer: {
|
|
410
366
|
overflow: "hidden",
|