related-ui-components 1.8.5 → 1.8.6
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/commonjs/components/Wheel/Wheel.js +110 -170
- package/lib/commonjs/components/Wheel/Wheel.js.map +1 -1
- package/lib/module/components/Wheel/Wheel.js +111 -172
- package/lib/module/components/Wheel/Wheel.js.map +1 -1
- package/lib/typescript/commonjs/components/Wheel/Wheel.d.ts +1 -1
- package/lib/typescript/commonjs/components/Wheel/Wheel.d.ts.map +1 -1
- package/lib/typescript/module/components/Wheel/Wheel.d.ts +1 -1
- package/lib/typescript/module/components/Wheel/Wheel.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Wheel/Wheel.tsx +157 -231
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useState,
|
|
3
|
-
useRef,
|
|
4
|
-
useEffect,
|
|
5
|
-
useMemo, // Added useMemo for wheelPaths
|
|
6
|
-
} from "react";
|
|
1
|
+
import React, { useState, useRef, useEffect } from "react";
|
|
7
2
|
import {
|
|
8
3
|
View,
|
|
9
4
|
StyleSheet,
|
|
@@ -20,37 +15,15 @@ export interface SpinWheelItem {
|
|
|
20
15
|
id: string | number;
|
|
21
16
|
label: string;
|
|
22
17
|
value?: any;
|
|
23
|
-
color: string;
|
|
18
|
+
color: string;
|
|
24
19
|
textColor?: string;
|
|
25
20
|
}
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"#
|
|
30
|
-
"#
|
|
31
|
-
"#
|
|
32
|
-
"#008000",
|
|
33
|
-
"#0000FF",
|
|
34
|
-
"#800080",
|
|
35
|
-
"#FFC0CB",
|
|
36
|
-
"#00FFFF",
|
|
37
|
-
"#FF00FF",
|
|
38
|
-
"#00FF00",
|
|
39
|
-
"#4B0082",
|
|
40
|
-
"#EE82EE",
|
|
41
|
-
"#40E0D0",
|
|
42
|
-
"#FFD700",
|
|
43
|
-
"#C0C0C0",
|
|
44
|
-
"#FFDAB9",
|
|
45
|
-
"#E6E6FA",
|
|
46
|
-
"#008080",
|
|
47
|
-
"#FF7F50",
|
|
48
|
-
"#DC143C",
|
|
49
|
-
"#87CEEB",
|
|
50
|
-
"#7FFF00",
|
|
51
|
-
"#CCCCFF",
|
|
52
|
-
"#FF6347",
|
|
53
|
-
"#FA8072",
|
|
22
|
+
const colors = [
|
|
23
|
+
"#FF0000", "#FFA500", "#FFFF00", "#008000", "#0000FF", "#800080",
|
|
24
|
+
"#FFC0CB", "#00FFFF", "#FF00FF", "#00FF00", "#4B0082", "#EE82EE",
|
|
25
|
+
"#40E0D0", "#FFD700", "#C0C0C0", "#FFDAB9", "#E6E6FA", "#008080",
|
|
26
|
+
"#FF7F50", "#DC143C", "#87CEEB", "#7FFF00", "#CCCCFF", "#FF6347", "#FA8072"
|
|
54
27
|
];
|
|
55
28
|
|
|
56
29
|
interface SpinWheelProps {
|
|
@@ -70,7 +43,7 @@ interface SpinWheelProps {
|
|
|
70
43
|
wheelTextColor?: string;
|
|
71
44
|
knobColor?: string;
|
|
72
45
|
centerComponent?: React.ReactNode;
|
|
73
|
-
|
|
46
|
+
winner?: SpinWheelItem | null; // Winner to spin to
|
|
74
47
|
}
|
|
75
48
|
|
|
76
49
|
const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
@@ -89,33 +62,27 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
89
62
|
actionButtonStyle,
|
|
90
63
|
actionButtonTextStyle,
|
|
91
64
|
wheelTextColor = "#FFFFFF",
|
|
92
|
-
|
|
93
|
-
predeterminedWinnerId = null, // Default to null
|
|
65
|
+
winner,
|
|
94
66
|
}) => {
|
|
95
|
-
const wheelItems =
|
|
96
|
-
() => (items && items.length > 0 ? items : []),
|
|
97
|
-
[items]
|
|
98
|
-
);
|
|
99
|
-
|
|
67
|
+
const wheelItems = items.length > 0 ? items : [];
|
|
100
68
|
const [spinning, setSpinning] = useState(false);
|
|
101
|
-
const [
|
|
69
|
+
const [internalWinner, setInternalWinner] = useState<SpinWheelItem | null>(null);
|
|
102
70
|
const rotateValue = useRef(new Animated.Value(0)).current;
|
|
103
|
-
const rotationRef = useRef(0);
|
|
71
|
+
const rotationRef = useRef(0);
|
|
104
72
|
|
|
105
73
|
useEffect(() => {
|
|
106
|
-
const
|
|
74
|
+
const listener = rotateValue.addListener(({ value }) => {
|
|
107
75
|
rotationRef.current = value;
|
|
108
76
|
});
|
|
109
77
|
return () => {
|
|
110
|
-
rotateValue.removeListener(
|
|
78
|
+
rotateValue.removeListener(listener);
|
|
111
79
|
};
|
|
112
80
|
}, [rotateValue]);
|
|
113
81
|
|
|
114
|
-
const anglePerItem =
|
|
115
|
-
wheelItems.length > 0 ? 360 / wheelItems.length : 0;
|
|
82
|
+
const anglePerItem = 360 / wheelItems.length;
|
|
116
83
|
|
|
117
|
-
|
|
118
|
-
|
|
84
|
+
// Generate wheel paths and text positions
|
|
85
|
+
const generateWheelPaths = () => {
|
|
119
86
|
return wheelItems.map((item, index) => {
|
|
120
87
|
const startAngle = index * anglePerItem;
|
|
121
88
|
const endAngle = (index + 1) * anglePerItem;
|
|
@@ -125,15 +92,14 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
125
92
|
const y1 = size / 2 + (size / 2) * Math.sin(startRad);
|
|
126
93
|
const x2 = size / 2 + (size / 2) * Math.cos(endRad);
|
|
127
94
|
const y2 = size / 2 + (size / 2) * Math.sin(endRad);
|
|
128
|
-
const largeArcFlag =
|
|
95
|
+
const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
|
|
129
96
|
const pathData = [
|
|
130
97
|
`M ${size / 2} ${size / 2}`,
|
|
131
98
|
`L ${x1} ${y1}`,
|
|
132
99
|
`A ${size / 2} ${size / 2} 0 ${largeArcFlag} 1 ${x2} ${y2}`,
|
|
133
100
|
"Z",
|
|
134
101
|
].join(" ");
|
|
135
|
-
const
|
|
136
|
-
const midRad = (midAngle * Math.PI) / 180;
|
|
102
|
+
const midRad = ((startAngle + endAngle) / 2) * (Math.PI / 180);
|
|
137
103
|
const textX = size / 2 + size * 0.32 * Math.cos(midRad);
|
|
138
104
|
const textY = size / 2 + size * 0.32 * Math.sin(midRad);
|
|
139
105
|
return {
|
|
@@ -141,136 +107,75 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
141
107
|
item,
|
|
142
108
|
textX,
|
|
143
109
|
textY,
|
|
144
|
-
angle:
|
|
145
|
-
color: item.color || defaultColors[index % defaultColors.length],
|
|
110
|
+
angle: (startAngle + endAngle) / 2,
|
|
146
111
|
};
|
|
147
112
|
});
|
|
148
|
-
}
|
|
113
|
+
};
|
|
149
114
|
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
115
|
+
const wheelPaths = generateWheelPaths();
|
|
116
|
+
|
|
117
|
+
// Helper: get index of a SpinWheelItem
|
|
118
|
+
const getItemIndex = (target: SpinWheelItem) =>
|
|
119
|
+
wheelItems.findIndex((item) => item.id === target.id);
|
|
154
120
|
|
|
121
|
+
// Helper: spin to a given index
|
|
122
|
+
const spinToIndex = (targetIndex: number, callbackItem: SpinWheelItem) => {
|
|
155
123
|
setSpinning(true);
|
|
156
124
|
onSpinStart?.();
|
|
157
125
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
let targetWinnerItem: SpinWheelItem | null = null;
|
|
163
|
-
|
|
164
|
-
if (currentWinnerId != null) {
|
|
165
|
-
const foundItem = wheelItems.find((item) => item.id === currentWinnerId);
|
|
166
|
-
if (foundItem) {
|
|
167
|
-
targetWinnerItem = foundItem;
|
|
168
|
-
} else {
|
|
169
|
-
console.warn(
|
|
170
|
-
`SpinWheel: Predetermined winner with id "${currentWinnerId}" not found. Spinning randomly.`
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (targetWinnerItem) {
|
|
176
|
-
winnerToAnnounce = targetWinnerItem;
|
|
177
|
-
const winnerIndex = wheelItems.indexOf(targetWinnerItem);
|
|
178
|
-
|
|
179
|
-
// Calculate the middle angle of the target segment within the wheel's coordinate system
|
|
180
|
-
const targetSegmentMidAngle_deg = (winnerIndex + 0.5) * anglePerItem;
|
|
181
|
-
|
|
182
|
-
// The pointer is at 270 degrees (top). We want the targetSegmentMidAngle_deg
|
|
183
|
-
// to align with this pointer.
|
|
184
|
-
// If the wheel rotates by R, a point A on wheel is at (A+R)%360.
|
|
185
|
-
// So, (targetSegmentMidAngle_deg + R) % 360 = 270.
|
|
186
|
-
// R % 360 = (270 - targetSegmentMidAngle_deg + 360*k) % 360.
|
|
187
|
-
// This R % 360 is the target orientation for the wheel's 0-degree mark.
|
|
188
|
-
const targetWheelOrientation_deg =
|
|
189
|
-
(270 - targetSegmentMidAngle_deg + 360 * 10) % 360; // *10 to ensure positive
|
|
190
|
-
|
|
191
|
-
const currentWheelOrientation_deg = (rotationRef.current * 360) % 360;
|
|
126
|
+
// The pointer is at 270deg (top), so we want the winner to land there.
|
|
127
|
+
// The center of the segment is at: (index + 0.5) * anglePerItem
|
|
128
|
+
const winnerAngle =
|
|
129
|
+
360 - ((targetIndex + 0.5) * anglePerItem - 270);
|
|
192
130
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const numFullRotations = 3 + Math.floor(Math.random() * 3); // 3 to 5 full spins
|
|
198
|
-
const totalAdditionalRotation_deg =
|
|
199
|
-
numFullRotations * 360 + rotationToTarget_deg;
|
|
200
|
-
|
|
201
|
-
targetAnimationToValue =
|
|
202
|
-
rotationRef.current + totalAdditionalRotation_deg / 360;
|
|
203
|
-
} else {
|
|
204
|
-
// Fallback to original random spin logic
|
|
205
|
-
const randomSpins = 3 + Math.random() * 2; // 3-5 full rotations
|
|
206
|
-
const randomAngleOffset = Math.random() * 360;
|
|
207
|
-
const totalRandomRotation_deg = 360 * randomSpins + randomAngleOffset;
|
|
208
|
-
targetAnimationToValue =
|
|
209
|
-
rotationRef.current + totalRandomRotation_deg / 360;
|
|
210
|
-
}
|
|
131
|
+
// Add extra spins for effect
|
|
132
|
+
const extraSpins = 3;
|
|
133
|
+
const currentRotation = rotationRef.current * 360;
|
|
134
|
+
const targetRotation = currentRotation + extraSpins * 360 + winnerAngle;
|
|
211
135
|
|
|
212
136
|
Animated.timing(rotateValue, {
|
|
213
|
-
toValue:
|
|
137
|
+
toValue: targetRotation / 360,
|
|
214
138
|
duration: spinDuration,
|
|
215
139
|
easing: Easing.out(Easing.cubic),
|
|
216
140
|
useNativeDriver: true,
|
|
217
141
|
}).start(() => {
|
|
218
142
|
setSpinning(false);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
setWinnerState(winnerToAnnounce);
|
|
222
|
-
onSpinEnd?.(winnerToAnnounce);
|
|
223
|
-
} else {
|
|
224
|
-
// Calculate winner from random spin based on final rotation
|
|
225
|
-
const finalRotationDegrees = rotationRef.current * 360;
|
|
226
|
-
const pointerFixedAt_deg = 270; // Pointer is at the top
|
|
227
|
-
|
|
228
|
-
// Determine which original angle on the wheel is now under the pointer
|
|
229
|
-
const angleUnderPointer_orig =
|
|
230
|
-
(pointerFixedAt_deg - finalRotationDegrees + 360 * 10) % 360; // *10 for positive
|
|
231
|
-
|
|
232
|
-
let winningSegmentIndex = Math.floor(
|
|
233
|
-
angleUnderPointer_orig / anglePerItem
|
|
234
|
-
);
|
|
235
|
-
// Ensure index is within bounds
|
|
236
|
-
winningSegmentIndex = Math.max(
|
|
237
|
-
0,
|
|
238
|
-
Math.min(wheelItems.length - 1, winningSegmentIndex)
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
const calculatedWinner = wheelItems[winningSegmentIndex];
|
|
242
|
-
|
|
243
|
-
if (calculatedWinner) {
|
|
244
|
-
setWinnerState(calculatedWinner);
|
|
245
|
-
onSpinEnd?.(calculatedWinner);
|
|
246
|
-
} else if (wheelItems.length > 0) {
|
|
247
|
-
// Fallback, should not happen if items exist and calculation is correct
|
|
248
|
-
console.error(
|
|
249
|
-
"SpinWheel: Could not determine winner from random spin. Falling back to first item."
|
|
250
|
-
);
|
|
251
|
-
setWinnerState(wheelItems[0]);
|
|
252
|
-
onSpinEnd?.(wheelItems[0]);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
143
|
+
setInternalWinner(callbackItem);
|
|
144
|
+
onSpinEnd?.(callbackItem);
|
|
255
145
|
});
|
|
256
146
|
};
|
|
257
147
|
|
|
258
|
-
|
|
148
|
+
// If winner prop changes, spin to it
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
if (!winner || spinning) return;
|
|
151
|
+
const winnerIndex = getItemIndex(winner);
|
|
152
|
+
if (winnerIndex === -1) return;
|
|
153
|
+
spinToIndex(winnerIndex, winner);
|
|
154
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
155
|
+
}, [winner]);
|
|
156
|
+
|
|
157
|
+
// Handle random spin (if no winner is set)
|
|
158
|
+
const handleSpin = () => {
|
|
159
|
+
if (spinning || !enabled) return;
|
|
160
|
+
// If winner prop is set, ignore button (or you can allow override)
|
|
161
|
+
if (winner) return;
|
|
162
|
+
|
|
163
|
+
// Pick a random winner
|
|
164
|
+
const randomIndex = Math.floor(Math.random() * wheelItems.length);
|
|
165
|
+
const randomWinner = wheelItems[randomIndex];
|
|
166
|
+
spinToIndex(randomIndex, randomWinner);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Animation interpolation for rotation
|
|
170
|
+
const rotate = rotateValue.interpolate({
|
|
259
171
|
inputRange: [0, 1],
|
|
260
172
|
outputRange: ["0deg", "360deg"],
|
|
261
173
|
});
|
|
262
174
|
|
|
263
|
-
if (wheelItems.length === 0) {
|
|
264
|
-
return (
|
|
265
|
-
<View style={[styles.container, containerStyle, { height: size }]}>
|
|
266
|
-
<Text>No items to display in the wheel.</Text>
|
|
267
|
-
</View>
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
175
|
return (
|
|
272
176
|
<View style={[styles.container, containerStyle]}>
|
|
273
|
-
<View style={{ width: size, height: size
|
|
177
|
+
<View style={{ width: size, height: size }}>
|
|
178
|
+
{/* The wheel */}
|
|
274
179
|
<Animated.View
|
|
275
180
|
style={[
|
|
276
181
|
styles.wheelContainer,
|
|
@@ -278,66 +183,96 @@ const SpinWheel: React.FC<SpinWheelProps> = ({
|
|
|
278
183
|
width: size,
|
|
279
184
|
height: size,
|
|
280
185
|
borderRadius: size / 2,
|
|
281
|
-
transform: [{ rotate
|
|
186
|
+
transform: [{ rotate }],
|
|
282
187
|
},
|
|
283
188
|
]}
|
|
284
189
|
>
|
|
285
190
|
<Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
|
|
286
191
|
<G>
|
|
287
|
-
{wheelPaths.map(
|
|
288
|
-
|
|
289
|
-
<
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
192
|
+
{wheelPaths.map(
|
|
193
|
+
({ path, item, textX, textY, angle }, index) => (
|
|
194
|
+
<React.Fragment key={item.id}>
|
|
195
|
+
<Path
|
|
196
|
+
d={path}
|
|
197
|
+
fill={
|
|
198
|
+
!item.color
|
|
199
|
+
? colors[index % colors.length]
|
|
200
|
+
: item.color
|
|
201
|
+
}
|
|
202
|
+
stroke="#000000"
|
|
203
|
+
strokeWidth={1}
|
|
204
|
+
/>
|
|
205
|
+
<SvgText
|
|
206
|
+
x={textX}
|
|
207
|
+
y={textY}
|
|
208
|
+
fill={item.textColor || wheelTextColor}
|
|
209
|
+
fontSize={wheelTextStyle?.fontSize || 14}
|
|
210
|
+
fontWeight={wheelTextStyle?.fontWeight || "bold"}
|
|
211
|
+
textAnchor="middle"
|
|
212
|
+
alignmentBaseline="central"
|
|
213
|
+
transform={`rotate(${angle + 180}, ${textX}, ${textY})`}
|
|
214
|
+
>
|
|
215
|
+
{item.label}
|
|
216
|
+
</SvgText>
|
|
217
|
+
</React.Fragment>
|
|
218
|
+
)
|
|
219
|
+
)}
|
|
304
220
|
</G>
|
|
305
221
|
</Svg>
|
|
306
222
|
</Animated.View>
|
|
307
223
|
|
|
308
|
-
{
|
|
309
|
-
|
|
310
|
-
|
|
224
|
+
{/* The center circle */}
|
|
225
|
+
<View
|
|
226
|
+
style={[
|
|
227
|
+
styles.wheelCenter,
|
|
228
|
+
{
|
|
229
|
+
width: size / 5,
|
|
230
|
+
height: size / 5,
|
|
231
|
+
transform: [
|
|
232
|
+
{ translateX: -size / 10 },
|
|
233
|
+
{ translateY: -size / 10 },
|
|
234
|
+
],
|
|
235
|
+
borderRadius: size / 5,
|
|
236
|
+
},
|
|
237
|
+
centerStyle,
|
|
238
|
+
]}
|
|
239
|
+
>
|
|
240
|
+
{/** Optional: custom center component */}
|
|
241
|
+
</View>
|
|
242
|
+
|
|
243
|
+
{/* The pointer is a triangle on top */}
|
|
244
|
+
<View style={styles.pointerPosition}>
|
|
311
245
|
<View
|
|
312
246
|
style={[
|
|
313
|
-
styles.
|
|
314
|
-
{
|
|
315
|
-
|
|
316
|
-
height: size / 5,
|
|
317
|
-
borderRadius: size / 10, // Should be half of width/height
|
|
318
|
-
// Centering is now handled by absolute positioning from parent
|
|
319
|
-
},
|
|
320
|
-
centerStyle,
|
|
247
|
+
styles.pointer,
|
|
248
|
+
{ borderBottomColor: knobColor },
|
|
249
|
+
knobStyle,
|
|
321
250
|
]}
|
|
322
251
|
/>
|
|
323
|
-
|
|
252
|
+
</View>
|
|
324
253
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
254
|
+
{/* Action Button */}
|
|
255
|
+
<View
|
|
256
|
+
style={{
|
|
257
|
+
position: "absolute",
|
|
258
|
+
width: "100%",
|
|
259
|
+
alignItems: "center",
|
|
260
|
+
justifyContent: "center",
|
|
261
|
+
bottom: -70,
|
|
262
|
+
zIndex: 2,
|
|
263
|
+
}}
|
|
264
|
+
>
|
|
265
|
+
<TouchableOpacity
|
|
266
|
+
onPress={handleSpin}
|
|
267
|
+
disabled={spinning || !enabled || !!winner}
|
|
268
|
+
style={[styles.actionButton, actionButtonStyle]}
|
|
269
|
+
>
|
|
270
|
+
<Text style={[styles.actionButtonText, actionButtonTextStyle]}>
|
|
271
|
+
{spinButtonText}
|
|
272
|
+
</Text>
|
|
273
|
+
</TouchableOpacity>
|
|
329
274
|
</View>
|
|
330
275
|
</View>
|
|
331
|
-
|
|
332
|
-
<TouchableOpacity
|
|
333
|
-
onPress={handleSpin}
|
|
334
|
-
disabled={spinning || !enabled}
|
|
335
|
-
style={[styles.actionButton, actionButtonStyle]}
|
|
336
|
-
>
|
|
337
|
-
<Text style={[styles.actionButtonText, actionButtonTextStyle]}>
|
|
338
|
-
{spinButtonText}
|
|
339
|
-
</Text>
|
|
340
|
-
</TouchableOpacity>
|
|
341
276
|
</View>
|
|
342
277
|
);
|
|
343
278
|
};
|
|
@@ -346,58 +281,49 @@ const styles = StyleSheet.create({
|
|
|
346
281
|
container: {
|
|
347
282
|
alignItems: "center",
|
|
348
283
|
justifyContent: "center",
|
|
349
|
-
|
|
284
|
+
marginTop: 20,
|
|
285
|
+
marginBottom: 70,
|
|
350
286
|
},
|
|
351
287
|
wheelContainer: {
|
|
352
288
|
overflow: "hidden",
|
|
353
|
-
backgroundColor: "transparent",
|
|
354
|
-
alignItems: "center",
|
|
355
|
-
justifyContent: "center",
|
|
356
|
-
},
|
|
357
|
-
centerComponentWrapper: { // For custom center component
|
|
358
|
-
position: 'absolute',
|
|
359
|
-
zIndex: 2,
|
|
289
|
+
backgroundColor: "transparent",
|
|
360
290
|
},
|
|
361
|
-
wheelCenter: {
|
|
291
|
+
wheelCenter: {
|
|
362
292
|
position: "absolute",
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
293
|
+
top: "50%",
|
|
294
|
+
left: "50%",
|
|
295
|
+
backgroundColor: "#000000",
|
|
296
|
+
borderWidth: 1,
|
|
297
|
+
borderColor: "#333333",
|
|
298
|
+
zIndex: 1,
|
|
367
299
|
},
|
|
368
|
-
|
|
300
|
+
pointerPosition: {
|
|
369
301
|
position: "absolute",
|
|
370
|
-
top: -5, // Adjust to make pointer sit nicely on the edge
|
|
371
302
|
left: "50%",
|
|
372
|
-
transform: [{ translateX: -10 }
|
|
373
|
-
zIndex:
|
|
303
|
+
transform: [{ translateX: -10 }, { rotate: "180deg" }],
|
|
304
|
+
zIndex: 2,
|
|
374
305
|
},
|
|
375
306
|
pointer: {
|
|
376
307
|
width: 0,
|
|
377
308
|
height: 0,
|
|
378
309
|
backgroundColor: "transparent",
|
|
379
310
|
borderStyle: "solid",
|
|
380
|
-
borderLeftWidth: 10,
|
|
381
|
-
borderRightWidth: 10,
|
|
382
|
-
borderBottomWidth:
|
|
311
|
+
borderLeftWidth: 10,
|
|
312
|
+
borderRightWidth: 10,
|
|
313
|
+
borderBottomWidth: 15,
|
|
383
314
|
borderLeftColor: "transparent",
|
|
384
315
|
borderRightColor: "transparent",
|
|
385
|
-
|
|
316
|
+
borderBottomColor: "#D81E5B",
|
|
386
317
|
},
|
|
387
318
|
actionButton: {
|
|
388
|
-
marginTop: 30, // Space between wheel and button
|
|
389
319
|
paddingHorizontal: 30,
|
|
390
320
|
paddingVertical: 12,
|
|
391
321
|
borderRadius: 25,
|
|
392
|
-
backgroundColor: "#4CAF50", // Example button color
|
|
393
322
|
shadowColor: "#000",
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
shadowRadius: 3.84,
|
|
397
|
-
elevation: 5,
|
|
323
|
+
shadowRadius: 3,
|
|
324
|
+
backgroundColor: "grey",
|
|
398
325
|
},
|
|
399
326
|
actionButtonText: {
|
|
400
|
-
color: "#FFFFFF",
|
|
401
327
|
fontWeight: "bold",
|
|
402
328
|
fontSize: 16,
|
|
403
329
|
},
|