@chem-po/react-native 0.0.23 → 0.0.25

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 (64) hide show
  1. package/lib/commonjs/components/form/input/file/index.js +3 -1
  2. package/lib/commonjs/components/form/input/file/index.js.map +1 -1
  3. package/lib/commonjs/components/image/ImageViewModal.backup.js +285 -0
  4. package/lib/commonjs/components/image/ImageViewModal.backup.js.map +1 -0
  5. package/lib/commonjs/components/image/ImageViewModal.js +265 -0
  6. package/lib/commonjs/components/image/ImageViewModal.js.map +1 -0
  7. package/lib/commonjs/components/image/ImageViewModal.old.js +285 -0
  8. package/lib/commonjs/components/image/ImageViewModal.old.js.map +1 -0
  9. package/lib/commonjs/components/image/index.js +17 -0
  10. package/lib/commonjs/components/image/index.js.map +1 -0
  11. package/lib/commonjs/components/index.js +8 -8
  12. package/lib/commonjs/components/index.js.map +1 -1
  13. package/lib/commonjs/components/loading/LoadingImage.js +11 -6
  14. package/lib/commonjs/components/loading/LoadingImage.js.map +1 -1
  15. package/lib/module/components/form/input/file/index.js +3 -1
  16. package/lib/module/components/form/input/file/index.js.map +1 -1
  17. package/lib/module/components/image/ImageViewModal.backup.js +277 -0
  18. package/lib/module/components/image/ImageViewModal.backup.js.map +1 -0
  19. package/lib/module/components/image/ImageViewModal.js +257 -0
  20. package/lib/module/components/image/ImageViewModal.js.map +1 -0
  21. package/lib/module/components/image/ImageViewModal.old.js +277 -0
  22. package/lib/module/components/image/ImageViewModal.old.js.map +1 -0
  23. package/lib/module/components/image/index.js +2 -0
  24. package/lib/module/components/image/index.js.map +1 -0
  25. package/lib/module/components/index.js +1 -1
  26. package/lib/module/components/index.js.map +1 -1
  27. package/lib/module/components/loading/LoadingImage.js +11 -6
  28. package/lib/module/components/loading/LoadingImage.js.map +1 -1
  29. package/lib/typescript/components/form/input/file/index.d.ts +2 -1
  30. package/lib/typescript/components/form/input/file/index.d.ts.map +1 -1
  31. package/lib/typescript/components/image/ImageViewModal.backup.d.ts +9 -0
  32. package/lib/typescript/components/image/ImageViewModal.backup.d.ts.map +1 -0
  33. package/lib/typescript/components/image/ImageViewModal.d.ts +9 -0
  34. package/lib/typescript/components/image/ImageViewModal.d.ts.map +1 -0
  35. package/lib/typescript/components/image/ImageViewModal.old.d.ts +9 -0
  36. package/lib/typescript/components/image/ImageViewModal.old.d.ts.map +1 -0
  37. package/lib/typescript/components/image/index.d.ts +2 -0
  38. package/lib/typescript/components/image/index.d.ts.map +1 -0
  39. package/lib/typescript/components/index.d.ts +1 -1
  40. package/lib/typescript/components/index.d.ts.map +1 -1
  41. package/lib/typescript/components/loading/LoadingImage.d.ts +2 -2
  42. package/lib/typescript/components/loading/LoadingImage.d.ts.map +1 -1
  43. package/package.json +11 -10
  44. package/src/components/form/input/file/index.tsx +3 -0
  45. package/src/components/image/ImageViewModal.backup.tsx +261 -0
  46. package/src/components/image/ImageViewModal.old.tsx +261 -0
  47. package/src/components/image/ImageViewModal.tsx +254 -0
  48. package/src/components/image/index.ts +1 -0
  49. package/src/components/index.ts +1 -1
  50. package/src/components/loading/LoadingImage.tsx +10 -6
  51. package/lib/commonjs/components/overlay/ImageViewOverlay.js +0 -127
  52. package/lib/commonjs/components/overlay/ImageViewOverlay.js.map +0 -1
  53. package/lib/commonjs/components/overlay/index.js +0 -17
  54. package/lib/commonjs/components/overlay/index.js.map +0 -1
  55. package/lib/module/components/overlay/ImageViewOverlay.js +0 -119
  56. package/lib/module/components/overlay/ImageViewOverlay.js.map +0 -1
  57. package/lib/module/components/overlay/index.js +0 -2
  58. package/lib/module/components/overlay/index.js.map +0 -1
  59. package/lib/typescript/components/overlay/ImageViewOverlay.d.ts +0 -6
  60. package/lib/typescript/components/overlay/ImageViewOverlay.d.ts.map +0 -1
  61. package/lib/typescript/components/overlay/index.d.ts +0 -2
  62. package/lib/typescript/components/overlay/index.d.ts.map +0 -1
  63. package/src/components/overlay/ImageViewOverlay.tsx +0 -104
  64. package/src/components/overlay/index.ts +0 -1
@@ -0,0 +1,261 @@
1
+ import { useScreen } from '@chem-po/react'
2
+ import { Ionicons } from '@expo/vector-icons'
3
+ import React, { useCallback, useMemo, useRef, useState } from 'react'
4
+ import { Animated, Image, Modal, StyleSheet, TouchableOpacity, View } from 'react-native'
5
+ import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler'
6
+ import { LoadingLogo } from '../loading/Loading'
7
+
8
+ interface ImageViewModalProps {
9
+ isOpen: boolean
10
+ onClose: () => void
11
+ src: string | null
12
+ }
13
+
14
+ export const ImageViewModal: React.FC<ImageViewModalProps> = ({ isOpen, onClose, src }) => {
15
+ const [loading, setLoading] = useState(true)
16
+ const screenWidth = useScreen(s => s.width)
17
+ const screenHeight = useScreen(s => s.height)
18
+ const [imageSize, setImageSize] = useState({ width: screenWidth / 2, height: screenHeight / 2 })
19
+
20
+ // Animated values for zoom and pan
21
+ const scale = useRef(new Animated.Value(1)).current
22
+ const translateX = useRef(new Animated.Value(0)).current
23
+ const translateY = useRef(new Animated.Value(0)).current
24
+
25
+ // Gesture state
26
+ const savedScale = useRef(1)
27
+ const savedTranslateX = useRef(0)
28
+ const savedTranslateY = useRef(0)
29
+ const currentScale = useRef(1)
30
+ const currentTranslateX = useRef(0)
31
+ const currentTranslateY = useRef(0)
32
+
33
+ const { height, width } = useMemo(() => {
34
+ if (loading) return imageSize
35
+ const ratio = imageSize.width / imageSize.height
36
+ let h = Math.min(imageSize.height, screenHeight * 0.9)
37
+ let w = h * ratio
38
+ if (w > screenWidth * 0.9) {
39
+ w = Math.min(imageSize.width, screenWidth * 0.9)
40
+ h = w / ratio
41
+ }
42
+ return { height: h, width: w }
43
+ }, [screenHeight, screenWidth, imageSize, loading])
44
+
45
+ const onLoadStart = useCallback(() => setLoading(true), [])
46
+ const onLoad = useCallback((e: any) => {
47
+ const { width: naturalWidth, height: naturalHeight } = e.nativeEvent.source
48
+ setImageSize({ width: naturalWidth, height: naturalHeight })
49
+ setLoading(false)
50
+ }, [])
51
+
52
+ // Reset zoom and pan when modal opens/closes
53
+ const resetTransform = useCallback(() => {
54
+ scale.setValue(1)
55
+ translateX.setValue(0)
56
+ translateY.setValue(0)
57
+ savedScale.current = 1
58
+ savedTranslateX.current = 0
59
+ savedTranslateY.current = 0
60
+ currentScale.current = 1
61
+ currentTranslateX.current = 0
62
+ currentTranslateY.current = 0
63
+ }, [scale, translateX, translateY])
64
+
65
+ // Reset when modal closes or src changes
66
+ React.useEffect(() => {
67
+ if (!isOpen || !src) {
68
+ resetTransform()
69
+ }
70
+ }, [isOpen, src, resetTransform])
71
+
72
+ // Pan gesture
73
+ const panGesture = Gesture.Pan()
74
+ .onUpdate(event => {
75
+ // Only allow panning if zoomed in
76
+ if (savedScale.current > 1) {
77
+ const newTranslateX = savedTranslateX.current + event.translationX
78
+ const newTranslateY = savedTranslateY.current + event.translationY
79
+
80
+ // Calculate bounds to prevent panning too far
81
+ const maxTranslateX = (width * savedScale.current - width) / 2
82
+ const maxTranslateY = (height * savedScale.current - height) / 2
83
+
84
+ const boundedTranslateX = Math.max(-maxTranslateX, Math.min(maxTranslateX, newTranslateX))
85
+ const boundedTranslateY = Math.max(-maxTranslateY, Math.min(maxTranslateY, newTranslateY))
86
+
87
+ translateX.setValue(boundedTranslateX)
88
+ translateY.setValue(boundedTranslateY)
89
+ currentTranslateX.current = boundedTranslateX
90
+ currentTranslateY.current = boundedTranslateY
91
+ }
92
+ })
93
+ .onEnd(() => {
94
+ savedTranslateX.current = currentTranslateX.current
95
+ savedTranslateY.current = currentTranslateY.current
96
+ })
97
+
98
+ // Pinch gesture
99
+ const pinchGesture = Gesture.Pinch()
100
+ .onUpdate(event => {
101
+ const newScale = savedScale.current * event.scale
102
+ // Limit zoom between 1x and 5x
103
+ const boundedScale = Math.max(1, Math.min(5, newScale))
104
+ scale.setValue(boundedScale)
105
+ currentScale.current = boundedScale
106
+
107
+ // If zooming out to 1x, reset position
108
+ if (boundedScale <= 1) {
109
+ translateX.setValue(0)
110
+ translateY.setValue(0)
111
+ currentTranslateX.current = 0
112
+ currentTranslateY.current = 0
113
+ }
114
+ })
115
+ .onEnd(() => {
116
+ savedScale.current = currentScale.current
117
+ // If scale is close to 1, snap back to 1
118
+ if (savedScale.current < 1.1) {
119
+ Animated.parallel([
120
+ Animated.spring(scale, { toValue: 1, useNativeDriver: true }),
121
+ Animated.spring(translateX, { toValue: 0, useNativeDriver: true }),
122
+ Animated.spring(translateY, { toValue: 0, useNativeDriver: true }),
123
+ ]).start()
124
+ savedScale.current = 1
125
+ savedTranslateX.current = 0
126
+ savedTranslateY.current = 0
127
+ currentScale.current = 1
128
+ currentTranslateX.current = 0
129
+ currentTranslateY.current = 0
130
+ } else {
131
+ savedTranslateX.current = currentTranslateX.current
132
+ savedTranslateY.current = currentTranslateY.current
133
+ }
134
+ })
135
+
136
+ // Double tap to zoom
137
+ const doubleTapGesture = Gesture.Tap()
138
+ .numberOfTaps(2)
139
+ .onEnd(() => {
140
+ if (savedScale.current > 1) {
141
+ // Zoom out
142
+ Animated.parallel([
143
+ Animated.spring(scale, { toValue: 1, useNativeDriver: true }),
144
+ Animated.spring(translateX, { toValue: 0, useNativeDriver: true }),
145
+ Animated.spring(translateY, { toValue: 0, useNativeDriver: true }),
146
+ ]).start()
147
+ savedScale.current = 1
148
+ savedTranslateX.current = 0
149
+ savedTranslateY.current = 0
150
+ currentScale.current = 1
151
+ currentTranslateX.current = 0
152
+ currentTranslateY.current = 0
153
+ } else {
154
+ // Zoom in to 2x
155
+ Animated.spring(scale, { toValue: 2, useNativeDriver: true }).start()
156
+ savedScale.current = 2
157
+ currentScale.current = 2
158
+ }
159
+ })
160
+
161
+ // Test simple single tap gesture
162
+
163
+ // Combine gestures - simplified approach
164
+ const combinedGestures = Gesture.Race(
165
+ doubleTapGesture,
166
+ Gesture.Simultaneous(panGesture, pinchGesture),
167
+ )
168
+
169
+ if (!isOpen) {
170
+ return null
171
+ }
172
+
173
+ return (
174
+ <Modal visible={isOpen} transparent animationType="fade" onRequestClose={onClose}>
175
+ <GestureHandlerRootView style={styles.gestureRoot}>
176
+ <View style={styles.modalOverlay}>
177
+ <TouchableOpacity
178
+ style={styles.backgroundTouchable}
179
+ activeOpacity={1}
180
+ onPress={onClose}
181
+ />
182
+ <View style={styles.contentContainer}>
183
+ <GestureDetector gesture={combinedGestures}>
184
+ <Animated.View
185
+ style={[
186
+ styles.imageContainer,
187
+ {
188
+ width,
189
+ height,
190
+ opacity: loading ? 0 : 1,
191
+ transform: [{ scale }, { translateX }, { translateY }],
192
+ },
193
+ ]}>
194
+ <Image
195
+ source={src ? { uri: src } : undefined}
196
+ style={styles.image}
197
+ onLoadStart={onLoadStart}
198
+ onLoad={onLoad}
199
+ resizeMode="contain"
200
+ />
201
+ </Animated.View>
202
+ </GestureDetector>
203
+
204
+ <TouchableOpacity style={styles.closeButton} onPress={onClose}>
205
+ <Ionicons name="close" size={24} color="white" />
206
+ </TouchableOpacity>
207
+
208
+ {loading || !src ? (
209
+ <View style={styles.loadingContainer}>
210
+ <LoadingLogo isLoading={loading} size={70} />
211
+ </View>
212
+ ) : null}
213
+ </View>
214
+ </View>
215
+ </GestureHandlerRootView>
216
+ </Modal>
217
+ )
218
+ }
219
+
220
+ const styles = StyleSheet.create({
221
+ gestureRoot: {
222
+ flex: 1,
223
+ },
224
+ modalOverlay: {
225
+ flex: 1,
226
+ backgroundColor: 'rgba(0, 0, 0, 0.7)',
227
+ },
228
+ backgroundTouchable: {
229
+ ...StyleSheet.absoluteFillObject,
230
+ },
231
+ contentContainer: {
232
+ flex: 1,
233
+ justifyContent: 'center',
234
+ alignItems: 'center',
235
+ padding: 16,
236
+ },
237
+ imageContainer: {
238
+ overflow: 'hidden',
239
+ borderRadius: 4,
240
+ },
241
+ image: {
242
+ width: '100%',
243
+ height: '100%',
244
+ },
245
+ closeButton: {
246
+ position: 'absolute',
247
+ top: 16,
248
+ right: 16,
249
+ width: 40,
250
+ height: 40,
251
+ borderRadius: 20,
252
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
253
+ justifyContent: 'center',
254
+ alignItems: 'center',
255
+ },
256
+ loadingContainer: {
257
+ ...StyleSheet.absoluteFillObject,
258
+ justifyContent: 'center',
259
+ alignItems: 'center',
260
+ },
261
+ })
@@ -0,0 +1,261 @@
1
+ import { useScreen } from '@chem-po/react'
2
+ import { Ionicons } from '@expo/vector-icons'
3
+ import React, { useCallback, useMemo, useRef, useState } from 'react'
4
+ import { Animated, Image, Modal, StyleSheet, TouchableOpacity, View } from 'react-native'
5
+ import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler'
6
+ import { LoadingLogo } from '../loading/Loading'
7
+
8
+ interface ImageViewModalProps {
9
+ isOpen: boolean
10
+ onClose: () => void
11
+ src: string | null
12
+ }
13
+
14
+ export const ImageViewModal: React.FC<ImageViewModalProps> = ({ isOpen, onClose, src }) => {
15
+ const [loading, setLoading] = useState(true)
16
+ const screenWidth = useScreen(s => s.width)
17
+ const screenHeight = useScreen(s => s.height)
18
+ const [imageSize, setImageSize] = useState({ width: screenWidth / 2, height: screenHeight / 2 })
19
+
20
+ // Animated values for zoom and pan
21
+ const scale = useRef(new Animated.Value(1)).current
22
+ const translateX = useRef(new Animated.Value(0)).current
23
+ const translateY = useRef(new Animated.Value(0)).current
24
+
25
+ // Gesture state
26
+ const savedScale = useRef(1)
27
+ const savedTranslateX = useRef(0)
28
+ const savedTranslateY = useRef(0)
29
+ const currentScale = useRef(1)
30
+ const currentTranslateX = useRef(0)
31
+ const currentTranslateY = useRef(0)
32
+
33
+ const { height, width } = useMemo(() => {
34
+ if (loading) return imageSize
35
+ const ratio = imageSize.width / imageSize.height
36
+ let h = Math.min(imageSize.height, screenHeight * 0.9)
37
+ let w = h * ratio
38
+ if (w > screenWidth * 0.9) {
39
+ w = Math.min(imageSize.width, screenWidth * 0.9)
40
+ h = w / ratio
41
+ }
42
+ return { height: h, width: w }
43
+ }, [screenHeight, screenWidth, imageSize, loading])
44
+
45
+ const onLoadStart = useCallback(() => setLoading(true), [])
46
+ const onLoad = useCallback((e: any) => {
47
+ const { width: naturalWidth, height: naturalHeight } = e.nativeEvent.source
48
+ setImageSize({ width: naturalWidth, height: naturalHeight })
49
+ setLoading(false)
50
+ }, [])
51
+
52
+ // Reset zoom and pan when modal opens/closes
53
+ const resetTransform = useCallback(() => {
54
+ scale.setValue(1)
55
+ translateX.setValue(0)
56
+ translateY.setValue(0)
57
+ savedScale.current = 1
58
+ savedTranslateX.current = 0
59
+ savedTranslateY.current = 0
60
+ currentScale.current = 1
61
+ currentTranslateX.current = 0
62
+ currentTranslateY.current = 0
63
+ }, [scale, translateX, translateY])
64
+
65
+ // Reset when modal closes or src changes
66
+ React.useEffect(() => {
67
+ if (!isOpen || !src) {
68
+ resetTransform()
69
+ }
70
+ }, [isOpen, src, resetTransform])
71
+
72
+ // Pan gesture
73
+ const panGesture = Gesture.Pan()
74
+ .onUpdate(event => {
75
+ // Only allow panning if zoomed in
76
+ if (savedScale.current > 1) {
77
+ const newTranslateX = savedTranslateX.current + event.translationX
78
+ const newTranslateY = savedTranslateY.current + event.translationY
79
+
80
+ // Calculate bounds to prevent panning too far
81
+ const maxTranslateX = (width * savedScale.current - width) / 2
82
+ const maxTranslateY = (height * savedScale.current - height) / 2
83
+
84
+ const boundedTranslateX = Math.max(-maxTranslateX, Math.min(maxTranslateX, newTranslateX))
85
+ const boundedTranslateY = Math.max(-maxTranslateY, Math.min(maxTranslateY, newTranslateY))
86
+
87
+ translateX.setValue(boundedTranslateX)
88
+ translateY.setValue(boundedTranslateY)
89
+ currentTranslateX.current = boundedTranslateX
90
+ currentTranslateY.current = boundedTranslateY
91
+ }
92
+ })
93
+ .onEnd(() => {
94
+ savedTranslateX.current = currentTranslateX.current
95
+ savedTranslateY.current = currentTranslateY.current
96
+ })
97
+
98
+ // Pinch gesture
99
+ const pinchGesture = Gesture.Pinch()
100
+ .onUpdate(event => {
101
+ const newScale = savedScale.current * event.scale
102
+ // Limit zoom between 1x and 5x
103
+ const boundedScale = Math.max(1, Math.min(5, newScale))
104
+ scale.setValue(boundedScale)
105
+ currentScale.current = boundedScale
106
+
107
+ // If zooming out to 1x, reset position
108
+ if (boundedScale <= 1) {
109
+ translateX.setValue(0)
110
+ translateY.setValue(0)
111
+ currentTranslateX.current = 0
112
+ currentTranslateY.current = 0
113
+ }
114
+ })
115
+ .onEnd(() => {
116
+ savedScale.current = currentScale.current
117
+ // If scale is close to 1, snap back to 1
118
+ if (savedScale.current < 1.1) {
119
+ Animated.parallel([
120
+ Animated.spring(scale, { toValue: 1, useNativeDriver: true }),
121
+ Animated.spring(translateX, { toValue: 0, useNativeDriver: true }),
122
+ Animated.spring(translateY, { toValue: 0, useNativeDriver: true }),
123
+ ]).start()
124
+ savedScale.current = 1
125
+ savedTranslateX.current = 0
126
+ savedTranslateY.current = 0
127
+ currentScale.current = 1
128
+ currentTranslateX.current = 0
129
+ currentTranslateY.current = 0
130
+ } else {
131
+ savedTranslateX.current = currentTranslateX.current
132
+ savedTranslateY.current = currentTranslateY.current
133
+ }
134
+ })
135
+
136
+ // Double tap to zoom
137
+ const doubleTapGesture = Gesture.Tap()
138
+ .numberOfTaps(2)
139
+ .onEnd(() => {
140
+ if (savedScale.current > 1) {
141
+ // Zoom out
142
+ Animated.parallel([
143
+ Animated.spring(scale, { toValue: 1, useNativeDriver: true }),
144
+ Animated.spring(translateX, { toValue: 0, useNativeDriver: true }),
145
+ Animated.spring(translateY, { toValue: 0, useNativeDriver: true }),
146
+ ]).start()
147
+ savedScale.current = 1
148
+ savedTranslateX.current = 0
149
+ savedTranslateY.current = 0
150
+ currentScale.current = 1
151
+ currentTranslateX.current = 0
152
+ currentTranslateY.current = 0
153
+ } else {
154
+ // Zoom in to 2x
155
+ Animated.spring(scale, { toValue: 2, useNativeDriver: true }).start()
156
+ savedScale.current = 2
157
+ currentScale.current = 2
158
+ }
159
+ })
160
+
161
+ // Test simple single tap gesture
162
+
163
+ // Combine gestures - simplified approach
164
+ const combinedGestures = Gesture.Race(
165
+ doubleTapGesture,
166
+ Gesture.Simultaneous(panGesture, pinchGesture),
167
+ )
168
+
169
+ if (!isOpen) {
170
+ return null
171
+ }
172
+
173
+ return (
174
+ <Modal visible={isOpen} transparent animationType="fade" onRequestClose={onClose}>
175
+ <GestureHandlerRootView style={styles.gestureRoot}>
176
+ <View style={styles.modalOverlay}>
177
+ <TouchableOpacity
178
+ style={styles.backgroundTouchable}
179
+ activeOpacity={1}
180
+ onPress={onClose}
181
+ />
182
+ <View style={styles.contentContainer}>
183
+ <GestureDetector gesture={combinedGestures}>
184
+ <Animated.View
185
+ style={[
186
+ styles.imageContainer,
187
+ {
188
+ width,
189
+ height,
190
+ opacity: loading ? 0 : 1,
191
+ transform: [{ scale }, { translateX }, { translateY }],
192
+ },
193
+ ]}>
194
+ <Image
195
+ source={src ? { uri: src } : undefined}
196
+ style={styles.image}
197
+ onLoadStart={onLoadStart}
198
+ onLoad={onLoad}
199
+ resizeMode="contain"
200
+ />
201
+ </Animated.View>
202
+ </GestureDetector>
203
+
204
+ <TouchableOpacity style={styles.closeButton} onPress={onClose}>
205
+ <Ionicons name="close" size={24} color="white" />
206
+ </TouchableOpacity>
207
+
208
+ {loading || !src ? (
209
+ <View style={styles.loadingContainer}>
210
+ <LoadingLogo isLoading={loading} size={70} />
211
+ </View>
212
+ ) : null}
213
+ </View>
214
+ </View>
215
+ </GestureHandlerRootView>
216
+ </Modal>
217
+ )
218
+ }
219
+
220
+ const styles = StyleSheet.create({
221
+ gestureRoot: {
222
+ flex: 1,
223
+ },
224
+ modalOverlay: {
225
+ flex: 1,
226
+ backgroundColor: 'rgba(0, 0, 0, 0.7)',
227
+ },
228
+ backgroundTouchable: {
229
+ ...StyleSheet.absoluteFillObject,
230
+ },
231
+ contentContainer: {
232
+ flex: 1,
233
+ justifyContent: 'center',
234
+ alignItems: 'center',
235
+ padding: 16,
236
+ },
237
+ imageContainer: {
238
+ overflow: 'hidden',
239
+ borderRadius: 4,
240
+ },
241
+ image: {
242
+ width: '100%',
243
+ height: '100%',
244
+ },
245
+ closeButton: {
246
+ position: 'absolute',
247
+ top: 16,
248
+ right: 16,
249
+ width: 40,
250
+ height: 40,
251
+ borderRadius: 20,
252
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
253
+ justifyContent: 'center',
254
+ alignItems: 'center',
255
+ },
256
+ loadingContainer: {
257
+ ...StyleSheet.absoluteFillObject,
258
+ justifyContent: 'center',
259
+ alignItems: 'center',
260
+ },
261
+ })