@holper/react-native-holper-storybook 0.6.101 → 0.7.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.
Files changed (210) hide show
  1. package/.expo/README.md +8 -0
  2. package/.nvmrc +1 -0
  3. package/.prettierignore +5 -0
  4. package/.storybook/index.jsx +11 -0
  5. package/.storybook/main.js +8 -0
  6. package/.storybook/preview.jsx +51 -0
  7. package/.storybook/storybook.requires.js +43 -0
  8. package/.yarn/releases/yarn-4.5.0.cjs +925 -0
  9. package/.yarnrc.yml +3 -0
  10. package/App.jsx +29 -0
  11. package/LICENSE +21 -0
  12. package/{readme.md → README.md} +18 -19
  13. package/app.config.js +77 -0
  14. package/assets/adaptive-icon.png +0 -0
  15. package/assets/favicon.png +0 -0
  16. package/assets/fonts/Poppins-Bold.ttf +0 -0
  17. package/assets/fonts/Poppins-Regular.ttf +0 -0
  18. package/assets/fonts/Poppins-SemiBold.ttf +0 -0
  19. package/assets/icon.png +0 -0
  20. package/assets/splash.png +0 -0
  21. package/babel.config.js +7 -0
  22. package/build.sh +11 -0
  23. package/components/Button/index.tsx +66 -0
  24. package/{lib/components/Button/style.js → components/Button/style.ts} +8 -7
  25. package/components/Card/index.tsx +33 -0
  26. package/{lib/components/Card/style.js → components/Card/style.ts} +5 -4
  27. package/{lib/components/ConfirmationModal/index.js → components/ConfirmationModal/index.tsx} +25 -79
  28. package/{lib/components/ConfirmationModal/style.js → components/ConfirmationModal/style.tsx} +14 -13
  29. package/{lib/components/Container/index.js → components/Container/index.tsx} +7 -28
  30. package/{lib/components/Container/style.js → components/Container/style.ts} +6 -5
  31. package/{lib/components/CustomChatView/index.js → components/CustomChatView/index.tsx} +22 -30
  32. package/{lib/components/CustomChatView/style.js → components/CustomChatView/style.ts} +1 -1
  33. package/components/DeckSwiper/index.tsx +90 -0
  34. package/{lib/components/DeckSwiper/style.js → components/DeckSwiper/style.ts} +13 -12
  35. package/components/DonutCountdown/index.tsx +86 -0
  36. package/components/DonutCountdown/style.ts +8 -0
  37. package/components/FloatingContainer/index.tsx +35 -0
  38. package/{lib/components/FloatingContainer/style.js → components/FloatingContainer/style.ts} +7 -6
  39. package/components/Footer/index.tsx +35 -0
  40. package/{lib/components/Footer/style.js → components/Footer/style.ts} +4 -3
  41. package/components/Header/index.tsx +21 -0
  42. package/{lib/components/Header/style.js → components/Header/style.ts} +4 -3
  43. package/{lib/components/ImagePicker/index.js → components/ImagePicker/index.tsx} +3 -12
  44. package/components/ImageResponsive/index.tsx +24 -0
  45. package/components/ImageResponsive/style.ts +9 -0
  46. package/components/ImageViewer/index.tsx +36 -0
  47. package/{lib/components/ImageViewer/style.js → components/ImageViewer/style.ts} +11 -10
  48. package/{lib/components/Input/index.js → components/Input/index.tsx} +6 -33
  49. package/{lib/components/Input/style.js → components/Input/style.ts} +7 -18
  50. package/{lib/components/InputPin/index.js → components/InputPin/index.tsx} +6 -13
  51. package/{lib/components/InputPin/style.js → components/InputPin/style.ts} +7 -6
  52. package/components/MenuItem/index.tsx +25 -0
  53. package/{lib/components/MenuItem/style.js → components/MenuItem/style.ts} +9 -7
  54. package/{lib/components/NavigationTitle/index.js → components/NavigationTitle/index.tsx} +9 -30
  55. package/{lib/components/NavigationTitle/style.js → components/NavigationTitle/style.ts} +12 -11
  56. package/components/Notification/index.tsx +44 -0
  57. package/{lib/components/Notification/style.js → components/Notification/style.ts} +13 -11
  58. package/components/PreventDoubleClick/index.tsx +28 -0
  59. package/components/Select/index.tsx +51 -0
  60. package/components/Select/style.ts +64 -0
  61. package/{lib/components/SwipeablePanel/index.js → components/SwipeablePanel/index.tsx} +58 -85
  62. package/{lib/components/SwipeablePanel/style.js → components/SwipeablePanel/style.ts} +15 -14
  63. package/components/Switch/index.tsx +30 -0
  64. package/components/TakePicture/confirmPictureModal.tsx +37 -0
  65. package/components/TakePicture/index.tsx +148 -0
  66. package/{lib/components/TakePicture/style.js → components/TakePicture/style.ts} +4 -4
  67. package/components/Text/index.tsx +33 -0
  68. package/{lib/components/Text/style.js → components/Text/style.ts} +4 -2
  69. package/{lib/components/Textarea/index.js → components/Textarea/index.tsx} +5 -24
  70. package/{lib/components/Textarea/style.js → components/Textarea/style.ts} +5 -4
  71. package/components/TimeOutButton/index.tsx +67 -0
  72. package/{lib/components/TimeOutButton/style.js → components/TimeOutButton/style.ts} +4 -3
  73. package/components/Toast/index.tsx +34 -0
  74. package/components/Toast/style.ts +12 -0
  75. package/{lib/components/UploadDocument/index.js → components/UploadDocument/index.tsx} +49 -105
  76. package/{lib/components/UploadDocument/style.js → components/UploadDocument/style.ts} +16 -15
  77. package/components/VirtualKeyboard/index.tsx +75 -0
  78. package/{lib/components/VirtualKeyboard/style.js → components/VirtualKeyboard/style.ts} +9 -8
  79. package/components/index.ts +29 -0
  80. package/{lib/configs/constants.js → configs/constants.ts} +50 -48
  81. package/configs/types.ts +326 -0
  82. package/eas.json +27 -0
  83. package/eslint.config.mjs +205 -0
  84. package/hooks/index.ts +2 -0
  85. package/{lib/hooks/useDebounce.js → hooks/useDebounce.tsx} +6 -4
  86. package/hooks/useLoadFonts.tsx +13 -0
  87. package/index.js +3 -2
  88. package/lib/components/Button/index.tsx +66 -0
  89. package/lib/components/Button/style.ts +111 -0
  90. package/lib/components/Card/index.tsx +33 -0
  91. package/lib/components/Card/style.ts +34 -0
  92. package/lib/components/ConfirmationModal/index.tsx +104 -0
  93. package/lib/components/ConfirmationModal/style.tsx +53 -0
  94. package/lib/components/Container/index.tsx +33 -0
  95. package/lib/components/Container/style.ts +13 -0
  96. package/lib/components/CustomChatView/index.tsx +65 -0
  97. package/lib/components/CustomChatView/style.ts +10 -0
  98. package/lib/components/DeckSwiper/index.tsx +90 -0
  99. package/lib/components/DeckSwiper/style.ts +59 -0
  100. package/lib/components/DonutCountdown/index.tsx +86 -0
  101. package/lib/components/DonutCountdown/style.ts +8 -0
  102. package/lib/components/FloatingContainer/index.tsx +35 -0
  103. package/lib/components/FloatingContainer/style.ts +25 -0
  104. package/lib/components/Footer/index.tsx +35 -0
  105. package/lib/components/Footer/style.ts +40 -0
  106. package/lib/components/Header/index.tsx +21 -0
  107. package/lib/components/Header/style.ts +34 -0
  108. package/lib/components/ImagePicker/index.tsx +18 -0
  109. package/lib/components/ImageResponsive/index.tsx +24 -0
  110. package/lib/components/ImageResponsive/style.ts +9 -0
  111. package/lib/components/ImageViewer/index.tsx +36 -0
  112. package/lib/components/ImageViewer/style.ts +38 -0
  113. package/lib/components/Input/index.tsx +62 -0
  114. package/lib/components/Input/style.ts +91 -0
  115. package/lib/components/InputPin/index.tsx +21 -0
  116. package/lib/components/InputPin/style.ts +22 -0
  117. package/lib/components/MenuItem/index.tsx +25 -0
  118. package/lib/components/MenuItem/style.ts +44 -0
  119. package/lib/components/NavigationTitle/index.tsx +53 -0
  120. package/lib/components/NavigationTitle/style.ts +49 -0
  121. package/lib/components/Notification/index.tsx +44 -0
  122. package/lib/components/Notification/style.ts +50 -0
  123. package/lib/components/PreventDoubleClick/index.tsx +28 -0
  124. package/lib/components/Select/index.tsx +51 -0
  125. package/lib/components/Select/style.ts +64 -0
  126. package/lib/components/SwipeablePanel/index.tsx +208 -0
  127. package/lib/components/SwipeablePanel/style.ts +81 -0
  128. package/lib/components/Switch/index.tsx +30 -0
  129. package/lib/components/TakePicture/confirmPictureModal.tsx +37 -0
  130. package/lib/components/TakePicture/index.tsx +148 -0
  131. package/lib/components/TakePicture/style.ts +95 -0
  132. package/lib/components/Text/index.tsx +33 -0
  133. package/lib/components/Text/style.ts +101 -0
  134. package/lib/components/Textarea/index.tsx +26 -0
  135. package/lib/components/Textarea/style.ts +38 -0
  136. package/lib/components/TimeOutButton/index.tsx +67 -0
  137. package/lib/components/TimeOutButton/style.ts +42 -0
  138. package/lib/components/Toast/index.tsx +34 -0
  139. package/lib/components/Toast/style.ts +12 -0
  140. package/lib/components/UploadDocument/index.tsx +179 -0
  141. package/lib/components/UploadDocument/style.ts +57 -0
  142. package/lib/components/VirtualKeyboard/index.tsx +75 -0
  143. package/lib/components/VirtualKeyboard/style.ts +25 -0
  144. package/lib/components/index.ts +29 -0
  145. package/lib/configs/constants.ts +273 -0
  146. package/lib/configs/types.ts +326 -0
  147. package/lib/hooks/index.ts +2 -0
  148. package/lib/hooks/useDebounce.tsx +24 -0
  149. package/lib/hooks/useLoadFonts.tsx +13 -0
  150. package/lib/index.js +3 -2
  151. package/metro.config.js +11 -0
  152. package/package.json +72 -63
  153. package/prettier.config.mjs +23 -0
  154. package/stories/Button.stories.tsx +181 -0
  155. package/stories/Card.stories.tsx +22 -0
  156. package/stories/Colors.stories.tsx +57 -0
  157. package/stories/ConfirmationModal.stories.tsx +142 -0
  158. package/stories/Container.stories.tsx +105 -0
  159. package/stories/DeckSwiper.stories.tsx +43 -0
  160. package/stories/DonutCountdown.stories.tsx +134 -0
  161. package/stories/FloatingContainer.stories.tsx +139 -0
  162. package/stories/Footer.stories.tsx +65 -0
  163. package/stories/Header.stories.tsx +37 -0
  164. package/stories/ImagePicker.stories.tsx +14 -0
  165. package/stories/ImageResponsive.stories.tsx +18 -0
  166. package/stories/ImageViewer.stories.tsx +24 -0
  167. package/stories/Input.stories.tsx +119 -0
  168. package/stories/InputPin.stories.tsx +40 -0
  169. package/stories/Menu.stories.tsx +53 -0
  170. package/stories/MenuItem.stories.tsx +30 -0
  171. package/stories/NavigationTitle.stories.tsx +51 -0
  172. package/stories/Notification.stories.tsx +58 -0
  173. package/stories/Select.stories.tsx +270 -0
  174. package/stories/SwipeablePanel.stories.tsx +360 -0
  175. package/stories/Switch.stories.tsx +36 -0
  176. package/stories/TakePicture.stories.tsx +59 -0
  177. package/stories/Text.stories.tsx +61 -0
  178. package/stories/Textarea.stories.tsx +48 -0
  179. package/stories/TimeOutButton.stories.tsx +55 -0
  180. package/stories/Toast.stories.tsx +37 -0
  181. package/stories/UploadDocument.stories.tsx +179 -0
  182. package/stories/VirtualKeyboard.stories.tsx +14 -0
  183. package/tsconfig.json +21 -0
  184. package/utilities/ScrollView.tsx +19 -0
  185. package/utilities/index.ts +2 -0
  186. package/utilities/utils.ts +29 -0
  187. package/lib/components/Button/index.js +0 -104
  188. package/lib/components/Card/index.js +0 -49
  189. package/lib/components/DeckSwiper/index.js +0 -118
  190. package/lib/components/FlashMessage/index.js +0 -81
  191. package/lib/components/FloatingContainer/index.js +0 -69
  192. package/lib/components/Footer/index.js +0 -61
  193. package/lib/components/Header/index.js +0 -45
  194. package/lib/components/ImageResponsive/index.js +0 -39
  195. package/lib/components/ImageResponsive/style.js +0 -7
  196. package/lib/components/ImageViewer/index.js +0 -62
  197. package/lib/components/MenuItem/index.js +0 -44
  198. package/lib/components/Notification/index.js +0 -80
  199. package/lib/components/PreventDoubleClick/index.js +0 -21
  200. package/lib/components/Select/index.js +0 -89
  201. package/lib/components/Select/style.js +0 -81
  202. package/lib/components/Switch/index.js +0 -57
  203. package/lib/components/TakePicture/confirmPictureModal.js +0 -64
  204. package/lib/components/TakePicture/index.js +0 -198
  205. package/lib/components/Text/index.js +0 -75
  206. package/lib/components/TimeOutButton/index.js +0 -104
  207. package/lib/components/VirtualKeyboard/index.js +0 -86
  208. package/lib/components/index.js +0 -28
  209. package/lib/configs/loadFonts.js +0 -11
  210. package/lib/hooks/index.js +0 -1
@@ -1,21 +1,23 @@
1
- import React, { useState, useRef, useEffect } from 'react';
2
- import PropTypes from 'prop-types';
1
+ import { Ionicons } from '@expo/vector-icons';
2
+ import Constants from 'expo-constants';
3
+ import { useEffect, useRef, useState } from 'react';
3
4
  import {
4
- View,
5
- ScrollView,
6
5
  Animated,
7
6
  Dimensions,
8
7
  PanResponder,
9
- TouchableWithoutFeedback,
10
8
  Platform,
9
+ ScrollView,
11
10
  TouchableOpacity,
11
+ TouchableWithoutFeedback,
12
+ View,
12
13
  } from 'react-native';
13
- import { getStatusBarHeight } from 'react-native-status-bar-height';
14
- import Ionicons from 'react-native-vector-icons/Ionicons';
15
- import { CountdownCircleTimer } from 'react-native-countdown-circle-timer';
14
+
16
15
  import { Colors } from '../../configs/constants';
16
+ import DonutCountdown from '../DonutCountdown';
17
17
  import style from './style';
18
18
 
19
+ import type { SwipeablePanelProps } from '../../configs/types';
20
+
19
21
  const { height: screenHeight } = Dimensions.get('window');
20
22
 
21
23
  const STATUS = {
@@ -25,7 +27,7 @@ const STATUS = {
25
27
 
26
28
  const calcMarginTop = () => {
27
29
  if (Platform.OS === 'ios') {
28
- return getStatusBarHeight(true) === 44 ? 10 : -50;
30
+ return Constants.statusBarHeight === 44 ? 10 : -50;
29
31
  } else {
30
32
  return -50;
31
33
  }
@@ -41,16 +43,43 @@ const SwipeablePanel = ({
41
43
  onClose,
42
44
  avoidScroll,
43
45
  children,
44
- }) => {
46
+ }: SwipeablePanelProps) => {
45
47
  const LARGE_PANEL_HEIGHT = screenHeight - offset - calcMarginTop(); // This is the margin top
46
48
  const MEDIUM_PANEL_HEIGHT = 400; // Fixed height
47
49
 
48
50
  const [closeButtonClicked, setCloseButtonClicked] = useState(false);
49
51
  const [status, setStatus] = useState(STATUS.LARGE);
50
52
  const [animatedValueY, setAnimatedValueY] = useState(LARGE_PANEL_HEIGHT);
51
- const pan = useRef(
52
- new Animated.ValueXY({ x: 0, y: LARGE_PANEL_HEIGHT })
53
- ).current;
53
+ const pan = useRef(new Animated.ValueXY({ x: 0, y: LARGE_PANEL_HEIGHT })).current;
54
+
55
+ const _animateTo = (newStatus = 0, firstAnimate?: boolean) => {
56
+ if (!firstAnimate && lockPanel) {
57
+ return;
58
+ }
59
+
60
+ if (status === newStatus) {
61
+ return;
62
+ }
63
+
64
+ let newY = 0;
65
+
66
+ if (newStatus === STATUS.MEDIUM) {
67
+ newY = MEDIUM_PANEL_HEIGHT;
68
+ } else if (newStatus === STATUS.LARGE) {
69
+ newY = LARGE_PANEL_HEIGHT;
70
+ }
71
+
72
+ setStatus(newStatus);
73
+
74
+ Animated.spring(pan, {
75
+ toValue: { x: 0, y: newY },
76
+ tension: 80,
77
+ friction: 25,
78
+ useNativeDriver: true,
79
+ restDisplacementThreshold: 10,
80
+ restSpeedThreshold: 10,
81
+ }).start();
82
+ };
54
83
 
55
84
  useEffect(() => {
56
85
  pan.y.addListener(({ value }) => setAnimatedValueY(value));
@@ -58,6 +87,7 @@ const SwipeablePanel = ({
58
87
  if (autoMaximize) {
59
88
  setTimeout(() => _animateTo(STATUS.MEDIUM), 2000);
60
89
  }
90
+ // eslint-disable-next-line react-hooks/exhaustive-deps
61
91
  }, [offset, autoMaximize]);
62
92
 
63
93
  const panResponder = useRef(
@@ -76,10 +106,8 @@ const SwipeablePanel = ({
76
106
  pan.setValue({ x: 0, y: 0 });
77
107
  },
78
108
  onPanResponderMove: (evt, gestureState) => {
79
- if (
80
- status === STATUS.MEDIUM &&
81
- Math.abs(pan.y._value) <= pan.y._offset
82
- ) {
109
+ // @ts-expect-error omit ._value and ._offset
110
+ if (status === STATUS.MEDIUM && Math.abs(pan.y._value) <= pan.y._offset) {
83
111
  pan.setValue({
84
112
  x: 0,
85
113
  y: gestureState.dy,
@@ -100,35 +128,6 @@ const SwipeablePanel = ({
100
128
  })
101
129
  ).current;
102
130
 
103
- const _animateTo = (newStatus = 0, firstAnimate) => {
104
- if (!firstAnimate && lockPanel) {
105
- return;
106
- }
107
-
108
- if (status === newStatus) {
109
- return;
110
- }
111
-
112
- let newY = 0;
113
-
114
- if (newStatus === STATUS.MEDIUM) {
115
- newY = MEDIUM_PANEL_HEIGHT;
116
- } else if (newStatus === STATUS.LARGE) {
117
- newY = LARGE_PANEL_HEIGHT;
118
- }
119
-
120
- setStatus(newStatus);
121
-
122
- Animated.spring(pan, {
123
- toValue: { x: 0, y: newY },
124
- tension: 80,
125
- friction: 25,
126
- useNativeDriver: true,
127
- restDisplacementThreshold: 10,
128
- restSpeedThreshold: 10,
129
- }).start();
130
- };
131
-
132
131
  const renderContent = () => (
133
132
  <TouchableWithoutFeedback onPress={() => _animateTo(STATUS.MEDIUM)}>
134
133
  <View style={style.contentContainer}>{children}</View>
@@ -137,9 +136,7 @@ const SwipeablePanel = ({
137
136
 
138
137
  return (
139
138
  <Animated.View style={style.background}>
140
- <TouchableWithoutFeedback
141
- onPress={() => (maximized ? null : _animateTo(STATUS.LARGE))}
142
- >
139
+ <TouchableWithoutFeedback onPress={() => (maximized ? null : _animateTo(STATUS.LARGE))}>
143
140
  <View style={style.backgroundLayer} />
144
141
  </TouchableWithoutFeedback>
145
142
  <Animated.View
@@ -161,34 +158,32 @@ const SwipeablePanel = ({
161
158
  <TouchableOpacity
162
159
  onPress={() => {
163
160
  setCloseButtonClicked(true);
164
- onClose();
161
+ if (onClose) {
162
+ onClose();
163
+ }
165
164
  }}
166
165
  style={style.closeButton}
167
166
  >
168
- <Ionicons name='close-outline' size={20} color={Colors.darkblue} />
167
+ <Ionicons name="close-outline" size={20} color={Colors.darkblue} />
169
168
  </TouchableOpacity>
170
169
  )}
171
170
 
172
171
  {closeAfterSeconds > 0 && (
173
172
  <View style={style.autoClose}>
174
- <CountdownCircleTimer
175
- isPlaying={true}
173
+ <DonutCountdown
176
174
  duration={closeAfterSeconds}
177
- colors={Colors.green}
175
+ color={Colors.green}
178
176
  onComplete={() => {
179
177
  if (!closeButtonClicked) {
180
- onClose();
178
+ if (onClose) {
179
+ onClose();
180
+ }
181
181
  }
182
182
  }}
183
- size={40}
183
+ radius={16}
184
184
  strokeWidth={4}
185
- >
186
- {({ remainingTime, animatedColor }) => (
187
- <Animated.Text style={{ color: animatedColor, fontSize: 14 }}>
188
- {remainingTime}
189
- </Animated.Text>
190
- )}
191
- </CountdownCircleTimer>
185
+ textSize="small"
186
+ />
192
187
  </View>
193
188
  )}
194
189
 
@@ -210,26 +205,4 @@ const SwipeablePanel = ({
210
205
  );
211
206
  };
212
207
 
213
- SwipeablePanel.defaultProps = {
214
- offset: 0,
215
- maximized: false,
216
- lockPanel: false,
217
- autoMaximize: false,
218
- closeButton: false,
219
- avoidScroll: false,
220
- closeAfterSeconds: 0,
221
- onClose: () => {},
222
- };
223
-
224
- SwipeablePanel.propTypes = {
225
- offset: PropTypes.number,
226
- maximized: PropTypes.bool,
227
- lockPanel: PropTypes.bool,
228
- autoMaximize: PropTypes.bool,
229
- closeAfterSeconds: PropTypes.number,
230
- closeButton: PropTypes.bool,
231
- avoidScroll: PropTypes.bool,
232
- onClose: PropTypes.func,
233
- };
234
-
235
208
  export default SwipeablePanel;
@@ -1,9 +1,10 @@
1
- import {Dimensions} from 'react-native';
2
- import {Colors} from '../../configs/constants';
1
+ import { Dimensions, StyleSheet } from 'react-native';
3
2
 
4
- const {width} = Dimensions.get('window');
3
+ import { Colors } from '../../configs/constants';
5
4
 
6
- export default {
5
+ const { width } = Dimensions.get('window');
6
+
7
+ export default StyleSheet.create({
7
8
  background: {
8
9
  position: 'relative',
9
10
  width,
@@ -11,11 +12,11 @@ export default {
11
12
  flex: 1,
12
13
  justifyContent: 'center',
13
14
  alignItems: 'center',
14
- overflow: 'hidden'
15
+ overflow: 'hidden',
15
16
  },
16
17
  backgroundLayer: {
17
18
  width,
18
- flex: 1
19
+ flex: 1,
19
20
  },
20
21
  panel: {
21
22
  position: 'absolute',
@@ -41,25 +42,25 @@ export default {
41
42
  elevation: 1,
42
43
  zIndex: 2,
43
44
  paddingHorizontal: 20,
44
- paddingBottom: 20
45
+ paddingBottom: 20,
45
46
  },
46
47
  barContainer: {
47
48
  height: 50,
48
49
  justifyContent: 'center',
49
- alignItems: 'center'
50
+ alignItems: 'center',
50
51
  },
51
52
  bar: {
52
53
  backgroundColor: Colors.lightblue,
53
54
  height: 5,
54
55
  width: width * 0.12,
55
- borderRadius: 5
56
+ borderRadius: 5,
56
57
  },
57
58
  content: {
58
- paddingHorizontal: 20
59
+ paddingHorizontal: 20,
59
60
  },
60
61
  contentContainer: {
61
62
  width: '100%',
62
- flex: 1
63
+ flex: 1,
63
64
  },
64
65
  closeButton: {
65
66
  position: 'absolute',
@@ -70,11 +71,11 @@ export default {
70
71
  borderRadius: 15,
71
72
  backgroundColor: Colors.lightblue,
72
73
  alignItems: 'center',
73
- justifyContent: 'center'
74
+ justifyContent: 'center',
74
75
  },
75
76
  autoClose: {
76
77
  position: 'absolute',
77
78
  left: 10,
78
- top: 10
79
+ top: 10,
79
80
  },
80
- };
81
+ });
@@ -0,0 +1,30 @@
1
+ import { Platform, Switch as RNSwitch } from 'react-native';
2
+
3
+ import { Colors } from '../../configs/constants';
4
+
5
+ import type { SwitchProps } from '../../configs/types';
6
+
7
+ const Switch = ({ value, size = 'medium', ...props }: SwitchProps) => (
8
+ <RNSwitch
9
+ trackColor={{
10
+ false: Colors.lightblue,
11
+ true: Colors.lightblue,
12
+ }}
13
+ thumbColor={value ? Colors.green : Colors.midblue}
14
+ ios_backgroundColor={Colors.white}
15
+ value={value}
16
+ style={{
17
+ transform: [
18
+ {
19
+ scaleX: size === 'small' ? (Platform.OS === 'ios' ? 0.5 : 0.7) : Platform.OS === 'ios' ? 0.7 : 0.9,
20
+ },
21
+ {
22
+ scaleY: size === 'small' ? (Platform.OS === 'ios' ? 0.5 : 0.7) : Platform.OS === 'ios' ? 0.7 : 0.9,
23
+ },
24
+ ],
25
+ }}
26
+ {...props}
27
+ />
28
+ );
29
+
30
+ export default Switch;
@@ -0,0 +1,37 @@
1
+ import { Modal, TouchableOpacity, View } from 'react-native';
2
+
3
+ import ImageResponsive from '../ImageResponsive';
4
+ import Text from '../Text';
5
+ import style from './style';
6
+
7
+ import type { ConfirmPictureModalProps } from '../../configs/types';
8
+
9
+ export const ConfirmPictureModal = ({
10
+ avatar,
11
+ visible,
12
+ onRepeatPhoto,
13
+ onUsePhoto,
14
+ image,
15
+ repeatPictureText,
16
+ usePictureText,
17
+ }: ConfirmPictureModalProps) => (
18
+ <Modal animationType="slide" transparent={false} visible={visible} onRequestClose={() => {}}>
19
+ <View style={style.cameraTakenImageContainer}>
20
+ <ImageResponsive
21
+ source={
22
+ image && typeof image === 'object' && 'uri' in image ? { uri: image.uri } : image === null ? undefined : image
23
+ }
24
+ style={avatar ? style.cameraTakenImage : style.cameraContainer}
25
+ />
26
+
27
+ <View style={style.cameraRetakePhoto}>
28
+ <TouchableOpacity onPress={onRepeatPhoto}>
29
+ <Text style={style.cameraRetakePhotoText}>{repeatPictureText}</Text>
30
+ </TouchableOpacity>
31
+ <TouchableOpacity onPress={onUsePhoto}>
32
+ <Text style={style.cameraRetakePhotoText}>{usePictureText}</Text>
33
+ </TouchableOpacity>
34
+ </View>
35
+ </View>
36
+ </Modal>
37
+ );
@@ -0,0 +1,148 @@
1
+ import type { CameraType } from 'expo-camera';
2
+
3
+ import { Ionicons } from '@expo/vector-icons';
4
+ import { CameraView, useCameraPermissions } from 'expo-camera';
5
+ import * as ImageManipulator from 'expo-image-manipulator';
6
+ import { useRef, useState } from 'react';
7
+ import { ActivityIndicator, Modal, TouchableOpacity, View } from 'react-native';
8
+ import { Circle, Defs, Mask, Rect, Svg } from 'react-native-svg';
9
+
10
+ import { Colors } from '../../configs/constants';
11
+ import Button from '../Button';
12
+ import Container from '../Container';
13
+ import Text from '../Text';
14
+ import { ConfirmPictureModal } from './confirmPictureModal';
15
+ import style from './style';
16
+
17
+ import type { TakePictureProps } from '../../configs/types';
18
+
19
+ const DESIRED_RATIO = '16:9';
20
+
21
+ const SvgCircle = () => (
22
+ <Svg height="100%" width="100%">
23
+ <Defs>
24
+ <Mask id="mask" x="0" y="0" height="100%" width="100%">
25
+ <Rect height="100%" width="100%" fill={Colors.white} />
26
+ <Circle r="29%" cx="50%" cy="50%" fill={Colors.darkgray} />
27
+ </Mask>
28
+ </Defs>
29
+ <Rect height="100%" width="100%" fill="rgba(0, 0, 0, 0.8)" mask="url(#mask)" fill-opacity="0" />
30
+ </Svg>
31
+ );
32
+
33
+ const TakePicture = ({
34
+ visible,
35
+ onClose,
36
+ avatar,
37
+ cameraErrorMessage,
38
+ requestPermissionsMessage,
39
+ processingPictureMessage,
40
+ repeatPictureText,
41
+ usePictureText,
42
+ }: TakePictureProps) => {
43
+ const [permission, requestPermission] = useCameraPermissions();
44
+ const [type, setType] = useState<CameraType>('back');
45
+ const [image, setImage] = useState<ImageManipulator.ImageResult | null>(null);
46
+ const [takingPicture, setTakingPicture] = useState<boolean>(false);
47
+ const camera = useRef<CameraView>(null);
48
+
49
+ const flipCamera = () => {
50
+ setType((current) => (current === 'back' ? 'front' : 'back'));
51
+ };
52
+
53
+ const takePicture = async () => {
54
+ if (camera.current) {
55
+ setTakingPicture(true);
56
+ const tempImage = await camera.current.takePictureAsync({ quality: 1.0 });
57
+
58
+ if (avatar) {
59
+ const avatarImage = await ImageManipulator.manipulateAsync(
60
+ tempImage.uri,
61
+ [
62
+ {
63
+ crop: {
64
+ originX: 0,
65
+ originY: (tempImage.height - tempImage.width) / 2,
66
+ width: tempImage.width,
67
+ height: tempImage.width,
68
+ },
69
+ },
70
+ ],
71
+ { compress: 1.0, format: ImageManipulator.SaveFormat.PNG }
72
+ );
73
+
74
+ setImage(avatarImage);
75
+ setTakingPicture(false);
76
+ } else {
77
+ setImage(tempImage);
78
+ setTakingPicture(false);
79
+ }
80
+ }
81
+ };
82
+
83
+ const repeatPhoto = () => {
84
+ setImage(null);
85
+ };
86
+
87
+ const usePhoto = () => {
88
+ if (image) {
89
+ onClose(typeof image === 'object' ? image.uri : image);
90
+ setImage(null);
91
+ }
92
+ };
93
+
94
+ const closeModal = () => {
95
+ setImage(null);
96
+ onClose();
97
+ };
98
+
99
+ if (!permission?.granted) {
100
+ return (
101
+ <View style={style.cameraPermissionsContainer}>
102
+ <Text color="red">{cameraErrorMessage}</Text>
103
+ <Button onPress={requestPermission} variant="inverted">
104
+ <Text color="white">{requestPermissionsMessage}</Text>
105
+ </Button>
106
+ </View>
107
+ );
108
+ }
109
+
110
+ return (
111
+ <Modal animationType="slide" transparent={false} visible={visible} onRequestClose={() => onClose()}>
112
+ <Container style={style.cameraContainer}>
113
+ <CameraView ref={camera} style={style.cameraContainer} facing={type} ratio={DESIRED_RATIO}>
114
+ {avatar && <SvgCircle />}
115
+
116
+ <View style={style.cameraFlipContainer}>
117
+ <TouchableOpacity onPress={closeModal} style={style.closeIcon}>
118
+ <Ionicons name="close-outline" color={Colors.darkblue} size={24} />
119
+ </TouchableOpacity>
120
+ <TouchableOpacity style={style.cameraFlipBtn} onPress={flipCamera}>
121
+ <Ionicons name="camera-reverse-outline" style={style.cameraFlipIcon} color={Colors.white} size={40} />
122
+ </TouchableOpacity>
123
+ <TouchableOpacity style={style.cameraRecordBtn} onPress={takePicture}>
124
+ <Ionicons name="radio-button-on-outline" color={Colors.red} size={60} />
125
+ </TouchableOpacity>
126
+ </View>
127
+ </CameraView>
128
+
129
+ {takingPicture && (
130
+ <View style={style.cameraTakingPictureOverlay}>
131
+ <ActivityIndicator color={Colors.darkblue} />
132
+ <Text color="white">{processingPictureMessage} ...</Text>
133
+ </View>
134
+ )}
135
+ <ConfirmPictureModal
136
+ visible={image !== null}
137
+ image={image}
138
+ repeatPictureText={repeatPictureText}
139
+ usePictureText={usePictureText}
140
+ onRepeatPhoto={repeatPhoto}
141
+ onUsePhoto={usePhoto}
142
+ />
143
+ </Container>
144
+ </Modal>
145
+ );
146
+ };
147
+
148
+ export default TakePicture;
@@ -1,9 +1,10 @@
1
- import { StyleSheet, Dimensions } from 'react-native';
1
+ import { Dimensions, StyleSheet } from 'react-native';
2
+
2
3
  import { Colors } from '../../configs/constants';
3
4
 
4
5
  const { width } = Dimensions.get('window');
5
6
 
6
- export default {
7
+ export default StyleSheet.create({
7
8
  cameraContainer: {
8
9
  flex: 1,
9
10
  ...StyleSheet.absoluteFillObject,
@@ -25,7 +26,6 @@ export default {
25
26
  flex: 1,
26
27
  backgroundColor: Colors.transparent,
27
28
  flexDirection: 'row',
28
- position: 'relative',
29
29
  marginBottom: 20,
30
30
  ...StyleSheet.absoluteFillObject,
31
31
  },
@@ -92,4 +92,4 @@ export default {
92
92
  justifyContent: 'center',
93
93
  alignItems: 'center',
94
94
  },
95
- };
95
+ });
@@ -0,0 +1,33 @@
1
+ import { Text as RNText } from 'react-native';
2
+
3
+ import style from './style';
4
+
5
+ import type { TextProps } from '../../configs/types';
6
+
7
+ const Text = ({
8
+ variant = 'default',
9
+ size = 'medium',
10
+ color = 'dark',
11
+ weight = 'regular',
12
+ align = 'left',
13
+ style: customStyle = {},
14
+ children,
15
+ ...props
16
+ }: TextProps) => (
17
+ <RNText
18
+ style={[
19
+ style[variant as keyof typeof style],
20
+ style[size as keyof typeof style],
21
+ style[color as keyof typeof style],
22
+ style[weight as keyof typeof style],
23
+ style[align as keyof typeof style],
24
+ { ...customStyle },
25
+ ]}
26
+ allowFontScaling={false}
27
+ {...props}
28
+ >
29
+ {children}
30
+ </RNText>
31
+ );
32
+
33
+ export default Text;
@@ -1,6 +1,8 @@
1
+ import { StyleSheet } from 'react-native';
2
+
1
3
  import { Colors } from '../../configs/constants';
2
4
 
3
- export default {
5
+ export default StyleSheet.create({
4
6
  // colors
5
7
  dark: {
6
8
  color: Colors.darkblue,
@@ -96,4 +98,4 @@ export default {
96
98
  justify: {
97
99
  textAlign: 'justify',
98
100
  },
99
- };
101
+ });
@@ -1,16 +1,11 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
1
  import { TextInput } from 'react-native';
2
+
4
3
  import { Colors } from '../../configs/constants';
5
4
  import style from './style';
6
5
 
7
- const Textarea = ({
8
- variant = 'default',
9
- disabled,
10
- numberOfLines = 4,
11
- fitToContainer,
12
- ...props
13
- }) => (
6
+ import type { TextareaProps } from '../../configs/types';
7
+
8
+ const Textarea = ({ variant = 'default', disabled, numberOfLines = 4, fitToContainer, ...props }: TextareaProps) => (
14
9
  <TextInput
15
10
  style={[
16
11
  style.textarea,
@@ -22,24 +17,10 @@ const Textarea = ({
22
17
  multiline
23
18
  editable={!disabled}
24
19
  numberOfLines={numberOfLines}
25
- textAlignVertical='top'
20
+ textAlignVertical="top"
26
21
  placeholderTextColor={Colors.midblue}
27
22
  {...props}
28
23
  />
29
24
  );
30
25
 
31
- Textarea.defaultProps = {
32
- variant: 'default',
33
- disabled: false,
34
- fitToContainer: false,
35
- numberOfLines: 4,
36
- };
37
-
38
- Textarea.propTypes = {
39
- variant: PropTypes.oneOf(['default', 'completed', 'error']),
40
- disabled: PropTypes.bool,
41
- fitToContainer: PropTypes.bool,
42
- numberOfLines: PropTypes.number,
43
- };
44
-
45
26
  export default Textarea;
@@ -1,9 +1,10 @@
1
- import { Dimensions } from 'react-native';
2
- import { Colors, borderRadius } from '../../configs/constants';
1
+ import { Dimensions, StyleSheet } from 'react-native';
2
+
3
+ import { borderRadius, Colors } from '../../configs/constants';
3
4
 
4
5
  const { width } = Dimensions.get('window');
5
6
 
6
- export default {
7
+ export default StyleSheet.create({
7
8
  textarea: {
8
9
  borderRadius,
9
10
  borderWidth: 1,
@@ -34,4 +35,4 @@ export default {
34
35
  disabled: {
35
36
  opacity: 0.5,
36
37
  },
37
- };
38
+ });