shakebug-react-native 2.4.15 → 2.4.16

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 (33) hide show
  1. package/README.md +6 -0
  2. package/android/src/main/java/com/shakebug/ConnectivityReceiver.java +12 -7
  3. package/android/src/main/java/com/shakebug/DrawingView.java +13 -3
  4. package/android/src/main/java/com/shakebug/RecordScreenModule.java +6 -3
  5. package/android/src/main/java/com/shakebug/ViewShot.java +1 -0
  6. package/ios/CustomScreenShot/ShakebugSDKCustomScreenCapture.m +6 -2
  7. package/ios/ScreenShot/ShakebugCapture.m +3 -1
  8. package/ios/SketchCanvas/DrawingView.m +14 -1
  9. package/package.json +1 -1
  10. package/shakebug-react-native-2.4.15.tgz +0 -0
  11. package/src/APIs/MatchKey.js +1 -1
  12. package/src/Assets/images/shake.png +0 -0
  13. package/src/Assets/images/undo.png +0 -0
  14. package/src/Assets/images/undo@2x.png +0 -0
  15. package/src/Assets/images/undo@3x.png +0 -0
  16. package/src/Componanats/CustomAlert.js +8 -4
  17. package/src/Componanats/Icons.js +278 -0
  18. package/src/Componanats/KeyboardAvoidingWrapper.js +31 -39
  19. package/src/Componanats/LoadingModal.js +7 -4
  20. package/src/Componanats/NavigationContext.js +8 -1
  21. package/src/Componanats/ReviewModal.js +18 -11
  22. package/src/Componanats/SafeAreaHelper.js +70 -0
  23. package/src/Componanats/ShakeFunction.js +655 -364
  24. package/src/Componanats/ShakebugBottomSheet.js +729 -0
  25. package/src/Componanats/Theme.js +96 -0
  26. package/src/Componanats/ZoomableImage.js +350 -0
  27. package/src/Componanats/localization.js +32 -3
  28. package/src/Screens/AddDetailsScreen.js +800 -439
  29. package/src/Screens/FirstScreen.js +950 -540
  30. package/src/Screens/Shakebug.js +78 -44
  31. package/src/Screens/TrimVideoScreen.js +40 -7
  32. package/src/index.tsx +16 -7
  33. package/shakebug-react-native-2.4.14.tgz +0 -0
@@ -0,0 +1,729 @@
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ Modal,
6
+ TouchableOpacity,
7
+ TouchableWithoutFeedback,
8
+ Image,
9
+ StyleSheet,
10
+ Platform,
11
+ SafeAreaView,
12
+ Animated,
13
+ PanResponder,
14
+ } from 'react-native';
15
+ import { useTheme } from './Theme';
16
+ import { getLocalizedString } from './localization';
17
+ import { getBottomSpace, isIPhoneWithNotch } from './SafeAreaHelper';
18
+
19
+ const ShakebugBottomSheet = ({
20
+ visible,
21
+ onClose,
22
+ onReportIssue,
23
+ onRecordIssue,
24
+ onChooseMedia,
25
+ themeColor = '#2E2E2E',
26
+ isShakeDisabled = false,
27
+ onDisableShake,
28
+ onEnableShake,
29
+ screenshot = null,
30
+ }) => {
31
+ const resolvedColor = (themeColor && themeColor !== '#2E2E2E')
32
+ ? themeColor
33
+ : (global.ShakebugThemeColor || themeColor || '#2E2E2E');
34
+ const theme = useTheme(resolvedColor);
35
+ const bottomInset = getBottomSpace();
36
+ const [showConfirmModal, setShowConfirmModal] = useState(false);
37
+ const [isModalVisible, setIsModalVisible] = useState(visible);
38
+
39
+ const translateY = useRef(new Animated.Value(500)).current;
40
+ const backdropOpacity = useRef(new Animated.Value(0)).current;
41
+ const confirmOpacity = useRef(new Animated.Value(0)).current;
42
+ const isClosingRef = useRef(false);
43
+
44
+ useEffect(() => {
45
+ if (visible) {
46
+ setIsModalVisible(true);
47
+ isClosingRef.current = false;
48
+ translateY.setValue(500);
49
+ backdropOpacity.setValue(0);
50
+
51
+ Animated.parallel([
52
+ Animated.timing(backdropOpacity, {
53
+ toValue: 1,
54
+ duration: 240,
55
+ useNativeDriver: true,
56
+ }),
57
+ Animated.spring(translateY, {
58
+ toValue: 0,
59
+ bounciness: 3,
60
+ speed: 13,
61
+ useNativeDriver: true,
62
+ }),
63
+ ]).start();
64
+ } else if (isModalVisible && !isClosingRef.current) {
65
+ animateClose();
66
+ }
67
+ }, [visible]);
68
+
69
+ const animateClose = (callback) => {
70
+ if (isClosingRef.current) return;
71
+ isClosingRef.current = true;
72
+
73
+ Animated.parallel([
74
+ Animated.timing(backdropOpacity, {
75
+ toValue: 0,
76
+ duration: 200,
77
+ useNativeDriver: true,
78
+ }),
79
+ Animated.timing(translateY, {
80
+ toValue: 500,
81
+ duration: 220,
82
+ useNativeDriver: true,
83
+ }),
84
+ ]).start(() => {
85
+ setIsModalVisible(false);
86
+ isClosingRef.current = false;
87
+ setShowConfirmModal(false);
88
+ if (typeof callback === 'function') {
89
+ callback();
90
+ } else if (typeof onClose === 'function') {
91
+ onClose();
92
+ }
93
+ });
94
+ };
95
+
96
+ // Drag-to-dismiss gesture on the bottom sheet
97
+ const panResponder = useRef(
98
+ PanResponder.create({
99
+ onStartShouldSetPanResponder: () => false,
100
+ onMoveShouldSetPanResponder: (evt, gestureState) => {
101
+ if (showConfirmModal) return false;
102
+ // Respond to downward drag
103
+ return gestureState.dy > 6 && Math.abs(gestureState.dy) > Math.abs(gestureState.dx * 1.2);
104
+ },
105
+ onPanResponderMove: (evt, gestureState) => {
106
+ if (gestureState.dy > 0) {
107
+ translateY.setValue(gestureState.dy);
108
+ const progress = Math.max(0, Math.min(1, 1 - gestureState.dy / 350));
109
+ backdropOpacity.setValue(progress);
110
+ } else {
111
+ translateY.setValue(gestureState.dy * 0.15);
112
+ }
113
+ },
114
+ onPanResponderRelease: (evt, gestureState) => {
115
+ // If dragged down past 70px or flicked down with velocity
116
+ if (gestureState.dy > 70 || (gestureState.dy > 25 && gestureState.vy > 0.3)) {
117
+ animateClose(onClose);
118
+ } else {
119
+ Animated.parallel([
120
+ Animated.spring(translateY, {
121
+ toValue: 0,
122
+ bounciness: 4,
123
+ speed: 14,
124
+ useNativeDriver: true,
125
+ }),
126
+ Animated.spring(backdropOpacity, {
127
+ toValue: 1,
128
+ bounciness: 4,
129
+ speed: 14,
130
+ useNativeDriver: true,
131
+ }),
132
+ ]).start();
133
+ }
134
+ },
135
+ onPanResponderTerminate: () => {
136
+ Animated.parallel([
137
+ Animated.spring(translateY, {
138
+ toValue: 0,
139
+ bounciness: 4,
140
+ speed: 14,
141
+ useNativeDriver: true,
142
+ }),
143
+ Animated.spring(backdropOpacity, {
144
+ toValue: 1,
145
+ bounciness: 4,
146
+ speed: 14,
147
+ useNativeDriver: true,
148
+ }),
149
+ ]).start();
150
+ },
151
+ })
152
+ ).current;
153
+
154
+ // Drag-to-dismiss gesture on the bottom sheet
155
+
156
+ const openConfirmModal = () => {
157
+ setShowConfirmModal(true);
158
+ confirmOpacity.setValue(0);
159
+ Animated.timing(confirmOpacity, {
160
+ toValue: 1,
161
+ duration: 180,
162
+ useNativeDriver: true,
163
+ }).start();
164
+ };
165
+
166
+ const closeConfirmModal = (onDone) => {
167
+ Animated.timing(confirmOpacity, {
168
+ toValue: 0,
169
+ duration: 150,
170
+ useNativeDriver: true,
171
+ }).start(() => {
172
+ setShowConfirmModal(false);
173
+ if (onDone) onDone();
174
+ });
175
+ };
176
+
177
+ const handleToggleShakePress = () => {
178
+ if (isShakeDisabled) {
179
+ if (onEnableShake) {
180
+ onEnableShake();
181
+ }
182
+ } else {
183
+ openConfirmModal();
184
+ }
185
+ };
186
+
187
+ const handleConfirmDisable = () => {
188
+ closeConfirmModal(() => {
189
+ if (onDisableShake) {
190
+ onDisableShake();
191
+ }
192
+ animateClose(onClose);
193
+ });
194
+ };
195
+
196
+ const handleRequestClose = () => {
197
+ if (showConfirmModal) {
198
+ closeConfirmModal();
199
+ } else {
200
+ animateClose(onClose);
201
+ }
202
+ };
203
+
204
+ const handleAction = (actionFn) => {
205
+ animateClose(() => {
206
+ if (actionFn) actionFn();
207
+ });
208
+ };
209
+
210
+ if (!isModalVisible) return null;
211
+
212
+ return (
213
+ <Modal
214
+ transparent
215
+ visible={isModalVisible}
216
+ animationType="none"
217
+ onRequestClose={handleRequestClose}
218
+ statusBarTranslucent
219
+ >
220
+ <View style={styles.modalOverlay}>
221
+ {/* Subtle dark overlay over the live application screen */}
222
+ <Animated.View
223
+ pointerEvents="none"
224
+ style={[
225
+ styles.backdropFade,
226
+ { opacity: backdropOpacity },
227
+ ]}
228
+ />
229
+
230
+ {/* Tap outside to close (occupies full screen space above the bottom sheet) */}
231
+ <TouchableOpacity
232
+ activeOpacity={1}
233
+ style={styles.backdropTouchArea}
234
+ onPress={() => {
235
+ if (showConfirmModal) {
236
+ closeConfirmModal();
237
+ } else {
238
+ animateClose(onClose);
239
+ }
240
+ }}
241
+ />
242
+
243
+ {/* Animated sliding bottom sheet */}
244
+ <Animated.View
245
+ {...panResponder.panHandlers}
246
+ style={[
247
+ styles.sheetContainer,
248
+ {
249
+ backgroundColor: theme.sheetBg,
250
+ transform: [{ translateY }],
251
+ },
252
+ ]}
253
+ >
254
+ <View style={{ width: '100%' }}>
255
+ {/* Top Grab Handle */}
256
+ <View style={styles.handleContainer}>
257
+ <View
258
+ style={[
259
+ styles.handleBar,
260
+ { backgroundColor: theme.sheetHandle },
261
+ ]}
262
+ />
263
+ </View>
264
+
265
+ {/* Header Row: Phone Shake Icon + Text Info */}
266
+ <View style={styles.headerRow}>
267
+ <View style={styles.phoneIconContainer}>
268
+ <Image
269
+ source={require('../Assets/images/shake.png')}
270
+ style={styles.shakeIcon}
271
+ resizeMode="contain"
272
+ />
273
+ </View>
274
+
275
+ <View style={styles.headerTextCol}>
276
+ <Text style={[styles.shakeDetectedText, { color: resolvedColor }]}>
277
+ {getLocalizedString('ShakeDetected')}
278
+ </Text>
279
+ <Text style={[styles.titleText, { color: theme.titleColor }]}>
280
+ {getLocalizedString('SomethingNotWorking')}
281
+ </Text>
282
+ <Text style={[styles.subtitleText, { color: theme.textSecondary }]}>
283
+ {getLocalizedString('SavedScreenshot')}
284
+ </Text>
285
+ </View>
286
+ </View>
287
+
288
+ {/* Button 1: Report an issue (Primary Solid) */}
289
+ <TouchableOpacity
290
+ style={[styles.primaryButton, { backgroundColor: theme.sheetPrimaryBtnBg }]}
291
+ activeOpacity={0.85}
292
+ onPress={() => handleAction(onReportIssue)}
293
+ >
294
+ <Text style={[styles.primaryButtonText, { color: theme.sheetPrimaryBtnText }]}>
295
+ {getLocalizedString('ReportAnIssue')}
296
+ </Text>
297
+ </TouchableOpacity>
298
+
299
+ {/* Button 2: Record the issue instead (Outline with red record dot) */}
300
+ <TouchableOpacity
301
+ style={[
302
+ styles.outlineButton,
303
+ {
304
+ borderColor: theme.sheetButtonBorder,
305
+ backgroundColor: theme.sheetButtonBg,
306
+ },
307
+ ]}
308
+ activeOpacity={0.8}
309
+ onPress={() => handleAction(onRecordIssue)}
310
+ >
311
+ <View style={styles.recordDotOuter}>
312
+ <View style={styles.recordDotInner} />
313
+ </View>
314
+ <Text style={[styles.outlineButtonText, { color: theme.textSecondary }]}>
315
+ {getLocalizedString('RecordIssueInstead')}
316
+ </Text>
317
+ </TouchableOpacity>
318
+
319
+ {/* Button 3: Choose media (Outline with media icon) */}
320
+ <TouchableOpacity
321
+ style={[
322
+ styles.outlineButton,
323
+ {
324
+ borderColor: theme.sheetButtonBorder,
325
+ backgroundColor: theme.sheetButtonBg,
326
+ },
327
+ ]}
328
+ activeOpacity={0.8}
329
+ onPress={() => handleAction(onChooseMedia)}
330
+ >
331
+ <View style={styles.mediaIconWrapper}>
332
+ {/* Back card */}
333
+ <View
334
+ style={[
335
+ styles.mediaBackCard,
336
+ { borderColor: theme.isDark ? '#94a3b8' : '#475569' },
337
+ ]}
338
+ />
339
+ {/* Front card */}
340
+ <View
341
+ style={[
342
+ styles.mediaFrontCard,
343
+ {
344
+ borderColor: theme.isDark ? '#cbd5e1' : '#334155',
345
+ backgroundColor: theme.sheetButtonBg,
346
+ },
347
+ ]}
348
+ >
349
+ <View
350
+ style={[
351
+ styles.mediaIconDot,
352
+ { backgroundColor: theme.isDark ? '#cbd5e1' : '#334155' },
353
+ ]}
354
+ />
355
+ <View
356
+ style={[
357
+ styles.mediaIconHill,
358
+ { backgroundColor: theme.isDark ? '#cbd5e1' : '#334155' },
359
+ ]}
360
+ />
361
+ </View>
362
+ </View>
363
+ <Text style={[styles.outlineButtonText, { color: theme.textSecondary }]}>
364
+ {getLocalizedString('ChooseMedia')}
365
+ </Text>
366
+ </TouchableOpacity>
367
+
368
+ {/* Bottom Actions Row: Not now (left) & Turn off/on shake (right) */}
369
+ <View style={styles.bottomActionsRow}>
370
+ <TouchableOpacity
371
+ style={styles.bottomActionButton}
372
+ activeOpacity={0.6}
373
+ onPress={() => animateClose(onClose)}
374
+ >
375
+ <Text style={[styles.notNowText, { color: theme.isDark ? theme.textSecondary : '#64748b' }]}>
376
+ {getLocalizedString('NotNow')}
377
+ </Text>
378
+ </TouchableOpacity>
379
+
380
+ <TouchableOpacity
381
+ style={styles.bottomActionButton}
382
+ activeOpacity={0.6}
383
+ onPress={handleToggleShakePress}
384
+ >
385
+ <Text style={[styles.toggleShakeText, { color: theme.isDark ? theme.textSecondary : '#64748b' }]}>
386
+ {isShakeDisabled
387
+ ? getLocalizedString('TurnOnShake')
388
+ : getLocalizedString('TurnOffShake')}
389
+ </Text>
390
+ </TouchableOpacity>
391
+ </View>
392
+
393
+ {/* Bottom Safe Area Spacer */}
394
+ <View
395
+ style={{
396
+ height: Platform.OS === 'ios'
397
+ ? (isIPhoneWithNotch() ? 34 : 16)
398
+ : 24,
399
+ width: '100%',
400
+ backgroundColor: theme.sheetBg,
401
+ }}
402
+ />
403
+ </View>
404
+ </Animated.View>
405
+
406
+ {/* Custom Confirmation Modal for Disabling Shake */}
407
+ {showConfirmModal && (
408
+ <Animated.View style={[styles.confirmModalBackdrop, { opacity: confirmOpacity }]}>
409
+ <TouchableWithoutFeedback onPress={() => closeConfirmModal()}>
410
+ <View style={StyleSheet.absoluteFillObject} />
411
+ </TouchableWithoutFeedback>
412
+
413
+ <View
414
+ style={[
415
+ styles.confirmCard,
416
+ { backgroundColor: theme.confirmModalBg },
417
+ ]}
418
+ >
419
+ <Text
420
+ style={[
421
+ styles.confirmTitle,
422
+ { color: theme.confirmModalText },
423
+ ]}
424
+ >
425
+ {getLocalizedString('DisableShakeConfirm')}
426
+ </Text>
427
+
428
+ <View style={styles.confirmButtonRow}>
429
+ <TouchableOpacity
430
+ style={[
431
+ styles.confirmButton,
432
+ {
433
+ backgroundColor: theme.confirmButtonBg,
434
+ marginRight: 6,
435
+ },
436
+ ]}
437
+ activeOpacity={0.7}
438
+ onPress={() => closeConfirmModal()}
439
+ >
440
+ <Text
441
+ style={[
442
+ styles.confirmCancelText,
443
+ { color: theme.confirmCancelText },
444
+ ]}
445
+ >
446
+ {getLocalizedString('Cancel')}
447
+ </Text>
448
+ </TouchableOpacity>
449
+
450
+ <TouchableOpacity
451
+ style={[
452
+ styles.confirmButton,
453
+ {
454
+ backgroundColor: theme.confirmButtonBg,
455
+ marginLeft: 6,
456
+ },
457
+ ]}
458
+ activeOpacity={0.7}
459
+ onPress={handleConfirmDisable}
460
+ >
461
+ <Text
462
+ style={[
463
+ styles.confirmDisableText,
464
+ { color: theme.confirmDisableText },
465
+ ]}
466
+ >
467
+ {getLocalizedString('Disable')}
468
+ </Text>
469
+ </TouchableOpacity>
470
+ </View>
471
+ </View>
472
+ </Animated.View>
473
+ )}
474
+ </View>
475
+ </Modal>
476
+ );
477
+ };
478
+
479
+ const styles = StyleSheet.create({
480
+ modalOverlay: {
481
+ flex: 1,
482
+ width: '100%',
483
+ height: '100%',
484
+ justifyContent: 'flex-end',
485
+ backgroundColor: 'transparent',
486
+ position: 'relative',
487
+ },
488
+ backdropFade: {
489
+ ...StyleSheet.absoluteFillObject,
490
+ backgroundColor: 'rgba(0, 0, 0, 0.45)',
491
+ },
492
+ backdropTouchArea: {
493
+ flex: 1,
494
+ width: '100%',
495
+ },
496
+ sheetContainer: {
497
+ width: '100%',
498
+ borderTopLeftRadius: 24,
499
+ borderTopRightRadius: 24,
500
+ paddingHorizontal: 22,
501
+ paddingTop: 10,
502
+ paddingBottom: 8,
503
+ shadowColor: '#000',
504
+ shadowOffset: { width: 0, height: -3 },
505
+ shadowOpacity: 0.15,
506
+ shadowRadius: 10,
507
+ elevation: 16,
508
+ },
509
+ handleContainer: {
510
+ width: '100%',
511
+ paddingTop: 4,
512
+ paddingBottom: 16,
513
+ alignItems: 'center',
514
+ justifyContent: 'center',
515
+ },
516
+ handleBar: {
517
+ width: 44,
518
+ height: 4,
519
+ borderRadius: 2,
520
+ alignSelf: 'center',
521
+ },
522
+ headerRow: {
523
+ flexDirection: 'row',
524
+ alignItems: 'center',
525
+ marginBottom: 22,
526
+ },
527
+ phoneIconContainer: {
528
+ width: 56,
529
+ height: 50,
530
+ justifyContent: 'center',
531
+ alignItems: 'center',
532
+ marginRight: 12,
533
+ },
534
+ shakeIcon: {
535
+ width: 54,
536
+ height: 46,
537
+ },
538
+ headerTextCol: {
539
+ flex: 1,
540
+ justifyContent: 'center',
541
+ },
542
+ shakeDetectedText: {
543
+ fontSize: 13,
544
+ fontWeight: '700',
545
+ letterSpacing: 0.3,
546
+ marginBottom: 3,
547
+ },
548
+ titleText: {
549
+ fontSize: 21,
550
+ fontWeight: '800',
551
+ letterSpacing: -0.3,
552
+ marginBottom: 4,
553
+ },
554
+ subtitleText: {
555
+ fontSize: 13,
556
+ fontWeight: '400',
557
+ lineHeight: 18,
558
+ },
559
+ primaryButton: {
560
+ height: 48,
561
+ borderRadius: 24,
562
+ justifyContent: 'center',
563
+ alignItems: 'center',
564
+ marginBottom: 10,
565
+ shadowColor: '#000',
566
+ shadowOffset: { width: 0, height: 2 },
567
+ shadowOpacity: 0.2,
568
+ shadowRadius: 3,
569
+ elevation: 3,
570
+ },
571
+ primaryButtonText: {
572
+ fontSize: 15,
573
+ fontWeight: '700',
574
+ },
575
+ outlineButton: {
576
+ height: 48,
577
+ borderRadius: 24,
578
+ borderWidth: 1,
579
+ flexDirection: 'row',
580
+ justifyContent: 'center',
581
+ alignItems: 'center',
582
+ marginBottom: 10,
583
+ },
584
+ recordDotOuter: {
585
+ width: 16,
586
+ height: 16,
587
+ borderRadius: 8,
588
+ borderWidth: 2,
589
+ borderColor: '#ef4444',
590
+ justifyContent: 'center',
591
+ alignItems: 'center',
592
+ marginRight: 8,
593
+ },
594
+ recordDotInner: {
595
+ width: 8,
596
+ height: 8,
597
+ borderRadius: 4,
598
+ backgroundColor: '#ef4444',
599
+ },
600
+ mediaIconWrapper: {
601
+ width: 22,
602
+ height: 18,
603
+ marginRight: 8,
604
+ position: 'relative',
605
+ justifyContent: 'center',
606
+ alignItems: 'center',
607
+ },
608
+ mediaBackCard: {
609
+ position: 'absolute',
610
+ top: 0,
611
+ left: 2,
612
+ width: 16,
613
+ height: 14,
614
+ borderRadius: 3,
615
+ borderWidth: 1.5,
616
+ },
617
+ mediaFrontCard: {
618
+ position: 'absolute',
619
+ bottom: 0,
620
+ right: 1,
621
+ width: 17,
622
+ height: 14,
623
+ borderRadius: 3,
624
+ borderWidth: 1.5,
625
+ overflow: 'hidden',
626
+ },
627
+ mediaIconDot: {
628
+ position: 'absolute',
629
+ top: 2,
630
+ right: 2,
631
+ width: 3,
632
+ height: 3,
633
+ borderRadius: 1.5,
634
+ },
635
+ mediaIconHill: {
636
+ position: 'absolute',
637
+ bottom: -3,
638
+ left: 1,
639
+ width: 9,
640
+ height: 9,
641
+ borderRadius: 4.5,
642
+ },
643
+ outlineButtonText: {
644
+ fontSize: 15,
645
+ fontWeight: '700',
646
+ },
647
+ bottomActionsRow: {
648
+ flexDirection: 'row',
649
+ justifyContent: 'space-between',
650
+ alignItems: 'center',
651
+ marginTop: 10,
652
+ marginBottom: 6,
653
+ paddingHorizontal: 4,
654
+ },
655
+ bottomActionButton: {
656
+ paddingVertical: 12,
657
+ paddingHorizontal: 8,
658
+ },
659
+ notNowText: {
660
+ fontSize: 15,
661
+ fontWeight: '700',
662
+ },
663
+ toggleShakeText: {
664
+ fontSize: 15,
665
+ fontWeight: '700',
666
+ },
667
+ confirmModalBackdrop: {
668
+ position: 'absolute',
669
+ top: 0,
670
+ left: 0,
671
+ right: 0,
672
+ bottom: 0,
673
+ width: '100%',
674
+ height: '100%',
675
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
676
+ justifyContent: 'center',
677
+ alignItems: 'center',
678
+ paddingHorizontal: 28,
679
+ zIndex: 99999,
680
+ elevation: 9999,
681
+ },
682
+ confirmCard: {
683
+ width: '100%',
684
+ maxWidth: 320,
685
+ borderRadius: 24,
686
+ paddingHorizontal: 24,
687
+ paddingTop: 24,
688
+ paddingBottom: 20,
689
+ alignSelf: 'center',
690
+ alignItems: 'center',
691
+ justifyContent: 'center',
692
+ shadowColor: '#000',
693
+ shadowOffset: { width: 0, height: 6 },
694
+ shadowOpacity: 0.3,
695
+ shadowRadius: 12,
696
+ elevation: 12,
697
+ },
698
+ confirmTitle: {
699
+ fontSize: 16,
700
+ fontWeight: '600',
701
+ lineHeight: 22,
702
+ textAlign: 'center',
703
+ alignSelf: 'center',
704
+ marginBottom: 20,
705
+ },
706
+ confirmButtonRow: {
707
+ flexDirection: 'row',
708
+ width: '100%',
709
+ justifyContent: 'space-between',
710
+ alignItems: 'center',
711
+ },
712
+ confirmButton: {
713
+ flex: 1,
714
+ height: 44,
715
+ borderRadius: 22,
716
+ justifyContent: 'center',
717
+ alignItems: 'center',
718
+ },
719
+ confirmCancelText: {
720
+ fontSize: 16,
721
+ fontWeight: '700',
722
+ },
723
+ confirmDisableText: {
724
+ fontSize: 16,
725
+ fontWeight: '700',
726
+ },
727
+ });
728
+
729
+ export default ShakebugBottomSheet;