@widergy/mobile-ui 0.33.0 → 0.34.2

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 (28) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/lib/components/Capture/index.js +55 -0
  3. package/lib/components/Capture/propTypes.js +14 -0
  4. package/lib/components/Capture/styles.js +11 -0
  5. package/lib/components/Label/utils.js +4 -1
  6. package/lib/components/PhotoAlbum/components/AddAnotherPhotoButton/index.js +19 -0
  7. package/lib/components/PhotoAlbum/components/AddAnotherPhotoButton/propTypes.js +7 -0
  8. package/lib/components/PhotoAlbum/components/AddAnotherPhotoButton/styles.js +29 -0
  9. package/lib/components/PhotoAlbum/components/DeleteView/index.js +19 -0
  10. package/lib/components/PhotoAlbum/components/DeleteView/propTypes.js +6 -0
  11. package/lib/components/PhotoAlbum/components/DeleteView/styles.js +9 -0
  12. package/lib/components/PhotoAlbum/components/Photo/index.js +69 -0
  13. package/lib/components/PhotoAlbum/components/Photo/propTypes.js +10 -0
  14. package/lib/components/PhotoAlbum/components/Photo/styles.js +53 -0
  15. package/lib/components/PhotoAlbum/components/ReplaceView/index.js +18 -0
  16. package/lib/components/PhotoAlbum/components/ReplaceView/propTypes.js +6 -0
  17. package/lib/components/PhotoAlbum/components/ReplaceView/styles.js +15 -0
  18. package/lib/components/PhotoAlbum/components/SvgIconCheck/index.js +17 -0
  19. package/lib/components/PhotoAlbum/components/SvgIconCheck/propTypes.js +5 -0
  20. package/lib/components/PhotoAlbum/components/SvgIconCheck/styles.js +18 -0
  21. package/lib/components/PhotoAlbum/index.js +168 -0
  22. package/lib/components/PhotoAlbum/propTypes.js +17 -0
  23. package/lib/components/PhotoAlbum/styles.js +51 -0
  24. package/lib/components/RadioGroup/components/RadioButton/index.js +60 -30
  25. package/lib/components/RadioGroup/components/RadioButton/styles.js +6 -0
  26. package/lib/components/RadioGroup/index.js +2 -0
  27. package/lib/index.js +4 -0
  28. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ ## [0.34.2](https://github.com/widergy/mobile-ui/compare/v0.34.1...v0.34.2) (2022-05-06)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * modify radio button components and others ([#221](https://github.com/widergy/mobile-ui/issues/221)) ([530345a](https://github.com/widergy/mobile-ui/commit/530345a3cb103ce761a4d780544b72f101d6a5e8))
7
+
8
+ ## [0.34.1](https://github.com/widergy/mobile-ui/compare/v0.34.0...v0.34.1) (2022-04-26)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * undefined is not a function ([#219](https://github.com/widergy/mobile-ui/issues/219)) ([ca80c4d](https://github.com/widergy/mobile-ui/commit/ca80c4d6b90176376f980234be432da87f6ed5ff))
14
+
15
+ # [0.34.0](https://github.com/widergy/mobile-ui/compare/v0.33.0...v0.34.0) (2022-04-11)
16
+
17
+
18
+ ### Features
19
+
20
+ * photo album and capture component added ([08f0749](https://github.com/widergy/mobile-ui/commit/08f07498f274b36bfc2a3be901527bd73f338a7a))
21
+
1
22
  # [0.33.0](https://github.com/widergy/mobile-ui/compare/v0.32.4...v0.33.0) (2022-03-25)
2
23
 
3
24
 
@@ -0,0 +1,55 @@
1
+ import React, { Fragment } from 'react';
2
+
3
+ import Label from '../Label';
4
+ import PhotoAlbum from '../PhotoAlbum';
5
+
6
+ import styles from './styles';
7
+ import propTypes from './propTypes';
8
+
9
+ const Capture = ({
10
+ label,
11
+ helpText,
12
+ maxImages,
13
+ images,
14
+ selectedImages,
15
+ setSelectedImages,
16
+ deletePhoto,
17
+ onPressAddAnotherPhoto,
18
+ onUnknownCameraError,
19
+ selectedMode,
20
+ sourceCameraImage,
21
+ sourceEditImage,
22
+ messageErrorPermissionCamera
23
+ }) => {
24
+ const isOnlyOnePicture = maxImages === 1 && images.length === 1;
25
+ const isItPossibleToAddAnotherPhoto = isOnlyOnePicture ? false : images.length <= maxImages;
26
+
27
+ return (
28
+ <Fragment>
29
+ {!!label && (
30
+ <Label semiBold big style={styles.paddingText}>
31
+ {label}
32
+ </Label>
33
+ )}
34
+ <PhotoAlbum
35
+ images={images}
36
+ selectedImages={selectedImages}
37
+ setSelectedImages={setSelectedImages}
38
+ deletePhoto={deletePhoto}
39
+ isItPossibleToAddAnotherPhoto={isItPossibleToAddAnotherPhoto}
40
+ onPressAddAnotherPhoto={onPressAddAnotherPhoto}
41
+ onUnknownCameraError={onUnknownCameraError}
42
+ selectedMode={selectedMode}
43
+ numberOfPhotosInTheAlbumHasExceeded={images.length === maxImages}
44
+ isOnlyOnePicture={isOnlyOnePicture}
45
+ sourceCameraImage={sourceCameraImage}
46
+ sourceEditImage={sourceEditImage}
47
+ messageErrorPermissionCamera={messageErrorPermissionCamera}
48
+ />
49
+ {!!helpText && <Label style={styles.paddingText}>{helpText}</Label>}
50
+ </Fragment>
51
+ );
52
+ };
53
+ Capture.propTypes = propTypes;
54
+
55
+ export default Capture;
@@ -0,0 +1,14 @@
1
+ import { bool, string, func, array, number } from 'prop-types';
2
+
3
+ export default {
4
+ label: string,
5
+ helpText: string,
6
+ maxImages: number,
7
+ images: array,
8
+ selectedImages: array,
9
+ setSelectedImages: func,
10
+ deletePhoto: func,
11
+ onPressAddAnotherPhoto: func,
12
+ onUnknownCameraError: func,
13
+ selectedMode: bool
14
+ };
@@ -0,0 +1,11 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { moderateHorizontalScale } from '../../utils/scaleUtils';
4
+
5
+ const styles = StyleSheet.create({
6
+ paddingText: {
7
+ paddingLeft: moderateHorizontalScale(5)
8
+ }
9
+ });
10
+
11
+ export default styles;
@@ -48,4 +48,7 @@ export const formatStyles = (useMarkdown, styles, newMarkdownStyles = {}) => {
48
48
  };
49
49
 
50
50
  export const markdownFormat = content =>
51
- content?.replace(/(<\s*br\s*\/?>|\n)/gi, '\n\n').replace(/(<\s*hr\s*\/?>)/gi, '\n\n---') || null;
51
+ content
52
+ ?.toString()
53
+ .replace(/(<\s*br\s*\/?>|\n)/gi, '\n\n')
54
+ .replace(/(<\s*hr\s*\/?>)/gi, '\n\n---') || null;
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { Image, TouchableOpacity } from 'react-native';
3
+
4
+ import styles from './styles';
5
+ import propTypes from './propTypes';
6
+
7
+ const AddAnotherPhotoButton = ({ sourceCameraImage, onPress, disabled }) => (
8
+ <TouchableOpacity
9
+ onPress={onPress}
10
+ style={[styles.container, disabled && styles.disabledContainer]}
11
+ disabled={disabled}
12
+ >
13
+ <Image source={sourceCameraImage} style={[styles.image, disabled && styles.imageDisabled]} />
14
+ </TouchableOpacity>
15
+ );
16
+
17
+ AddAnotherPhotoButton.propTypes = propTypes;
18
+
19
+ export default AddAnotherPhotoButton;
@@ -0,0 +1,7 @@
1
+ import { bool, func, any } from 'prop-types';
2
+
3
+ export default {
4
+ source: any,
5
+ onPress: func,
6
+ disabled: bool
7
+ };
@@ -0,0 +1,29 @@
1
+ import { Dimensions, StyleSheet } from 'react-native';
2
+
3
+ import { moderateVerticalScale, moderateHorizontalScale } from '../../../../utils/scaleUtils';
4
+
5
+ const IMAGE_SIZE = (Dimensions.get('window').width - 30) * 0.333333 - 10;
6
+ const styles = StyleSheet.create({
7
+ container: {
8
+ width: IMAGE_SIZE,
9
+ height: IMAGE_SIZE,
10
+ paddingHorizontal: moderateHorizontalScale(10),
11
+ borderRadius: 5,
12
+ marginBottom: moderateVerticalScale(10),
13
+ backgroundColor: '#F7F8F9',
14
+ justifyContent: 'center',
15
+ alignItems: 'center'
16
+ },
17
+ disabledContainer: {
18
+ backgroundColor: 'rgba(247, 248, 249, 0.5)'
19
+ },
20
+ image: {
21
+ width: moderateHorizontalScale(48),
22
+ height: moderateHorizontalScale(48)
23
+ },
24
+ imageDisabled: {
25
+ opacity: 0.5
26
+ }
27
+ });
28
+
29
+ export default styles;
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ import Icon from '../../../Icon';
5
+ import Label from '../../../Label';
6
+
7
+ import styles from './styles';
8
+ import propTypes from './propTypes';
9
+
10
+ const DeleteView = ({ label, color }) => (
11
+ <View style={styles.buttonContainer}>
12
+ <Icon name="trash-2" type="feather" size={20} color={color} />
13
+ <Label color={color}>{label}</Label>
14
+ </View>
15
+ );
16
+
17
+ DeleteView.propTypes = propTypes;
18
+
19
+ export default DeleteView;
@@ -0,0 +1,6 @@
1
+ import { bool, string, oneOfType } from 'prop-types';
2
+
3
+ export default {
4
+ color: oneOfType([bool, string]),
5
+ label: string
6
+ };
@@ -0,0 +1,9 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ const styles = StyleSheet.create({
4
+ buttonContainer: {
5
+ alignItems: 'center'
6
+ }
7
+ });
8
+
9
+ export default styles;
@@ -0,0 +1,69 @@
1
+ import React, { useState } from 'react';
2
+ import { View, Image, TouchableOpacity, Modal, ImageBackground } from 'react-native';
3
+
4
+ import SvgIconCheck from '../SvgIconCheck';
5
+ import Icon from '../../../Icon';
6
+ import DeleteView from '../DeleteView';
7
+
8
+ import styles from './styles';
9
+ import propTypes from './propTypes';
10
+
11
+ const Photo = ({ image, onError, onLongPressImage, selectedImages, deletePhoto, isSelectedMode }) => {
12
+ const uri = image.uri ?? image;
13
+ const [fullScreenPhotoModalVisible, setFullScreenPhotoModalVisible] = useState(false);
14
+
15
+ const wasTheImagePressed = selectedImages.includes(uri);
16
+
17
+ const deletePhotoInModal = () => {
18
+ setFullScreenPhotoModalVisible(false);
19
+ deletePhoto(uri);
20
+ };
21
+ return (
22
+ <View>
23
+ <TouchableOpacity
24
+ onPress={() => {
25
+ if (isSelectedMode) {
26
+ onLongPressImage(uri);
27
+ } else {
28
+ setFullScreenPhotoModalVisible(true);
29
+ }
30
+ }}
31
+ onLongPress={() => {
32
+ onLongPressImage(uri);
33
+ }}
34
+ >
35
+ {wasTheImagePressed ? (
36
+ <ImageBackground borderRadius={5} source={{ uri }} style={styles.image}>
37
+ <SvgIconCheck size={24} />
38
+ </ImageBackground>
39
+ ) : (
40
+ <Image onError={onError} source={{ uri }} style={styles.image} />
41
+ )}
42
+ </TouchableOpacity>
43
+ <Modal animationType="fade" visible={fullScreenPhotoModalVisible}>
44
+ <View style={styles.modalContainer}>
45
+ <View style={styles.headerContainerModal}>
46
+ <TouchableOpacity
47
+ onPress={() => {
48
+ setFullScreenPhotoModalVisible(!fullScreenPhotoModalVisible);
49
+ }}
50
+ style={styles.backButtonHeaderModal}
51
+ >
52
+ <Icon name="arrowleft" type="antdesign" size={24} color="white" />
53
+ </TouchableOpacity>
54
+ </View>
55
+ <Image onError={onError} source={{ uri }} style={styles.imageFullScreen} />
56
+ {deletePhoto && (
57
+ <TouchableOpacity onPress={deletePhotoInModal} style={styles.footerContainerModal}>
58
+ <DeleteView label="Eliminar" color="white" />
59
+ </TouchableOpacity>
60
+ )}
61
+ </View>
62
+ </Modal>
63
+ </View>
64
+ );
65
+ };
66
+
67
+ Photo.propTypes = propTypes;
68
+
69
+ export default Photo;
@@ -0,0 +1,10 @@
1
+ import { bool, func, array, any } from 'prop-types';
2
+
3
+ export default {
4
+ image: any,
5
+ onError: func,
6
+ onLongPressImage: func,
7
+ selectedImages: array,
8
+ deletePhoto: func,
9
+ isSelectedMode: bool
10
+ };
@@ -0,0 +1,53 @@
1
+ import { Dimensions, StyleSheet } from 'react-native';
2
+
3
+ import { moderateVerticalScale, moderateHorizontalScale } from '../../../../utils/scaleUtils';
4
+
5
+ const IMAGE_SIZE = (Dimensions.get('window').width - 30) * 0.333333 - 10;
6
+ const styles = StyleSheet.create({
7
+ image: {
8
+ width: IMAGE_SIZE,
9
+ height: IMAGE_SIZE,
10
+ borderRadius: 5,
11
+ marginBottom: moderateVerticalScale(10)
12
+ },
13
+ imageFullScreen: {
14
+ flex: 1,
15
+ width: '100%',
16
+ height: '100%',
17
+ resizeMode: 'cover'
18
+ },
19
+ selectedImageIcon: {
20
+ position: 'absolute',
21
+ alignItems: 'flex-start'
22
+ },
23
+ modalContainer: {
24
+ flex: 1,
25
+ justifyContent: 'space-between'
26
+ },
27
+ headerContainerModal: {
28
+ flexBasis: moderateHorizontalScale(54),
29
+ backgroundColor: '#3A3A3A',
30
+ flexDirection: 'row',
31
+ justifyContent: 'space-between',
32
+ alignItems: 'center',
33
+ paddingLeft: moderateHorizontalScale(15)
34
+ },
35
+ backButtonHeaderModal: {
36
+ width: moderateHorizontalScale(38),
37
+ height: moderateVerticalScale(38),
38
+ borderRadius: 50,
39
+ justifyContent: 'center',
40
+ alignItems: 'center'
41
+ },
42
+ footerContainerModal: {
43
+ flexBasis: moderateHorizontalScale(57),
44
+ backgroundColor: '#3A3A3A',
45
+ justifyContent: 'center',
46
+ alignItems: 'center'
47
+ },
48
+ buttonContainerFooterModal: {
49
+ alignItems: 'center'
50
+ }
51
+ });
52
+
53
+ export default styles;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { View, Image } from 'react-native';
3
+
4
+ import Label from '../../../Label';
5
+
6
+ import styles from './styles';
7
+ import propTypes from './propTypes';
8
+
9
+ const ReplaceView = ({ label, color, sourceEditImage }) => (
10
+ <View style={styles.buttonContainer}>
11
+ <Image source={sourceEditImage} style={styles.image} />
12
+ <Label color={color}>{label}</Label>
13
+ </View>
14
+ );
15
+
16
+ ReplaceView.propTypes = propTypes;
17
+
18
+ export default ReplaceView;
@@ -0,0 +1,6 @@
1
+ import { bool, string, oneOfType } from 'prop-types';
2
+
3
+ export default {
4
+ color: oneOfType([bool, string]),
5
+ label: string
6
+ };
@@ -0,0 +1,15 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { moderateHorizontalScale, moderateVerticalScale } from '../../../../utils/scaleUtils';
4
+
5
+ const styles = StyleSheet.create({
6
+ buttonContainer: {
7
+ alignItems: 'center'
8
+ },
9
+ image: {
10
+ width: moderateHorizontalScale(24),
11
+ height: moderateVerticalScale(24)
12
+ }
13
+ });
14
+
15
+ export default styles;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ import Icon from '../../../Icon';
5
+
6
+ import { styles, colorIcon } from './styles';
7
+ import propTypes from './propTypes';
8
+
9
+ const SvgIconCheck = ({ size }) => (
10
+ <View style={styles(size).backgroundIcon}>
11
+ <Icon color={colorIcon} name="check" size={16} />
12
+ </View>
13
+ );
14
+
15
+ SvgIconCheck.propTypes = propTypes;
16
+
17
+ export default SvgIconCheck;
@@ -0,0 +1,5 @@
1
+ import { number } from 'prop-types';
2
+
3
+ export default {
4
+ size: number
5
+ };
@@ -0,0 +1,18 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import { moderateVerticalScale } from '../../../../utils/scaleUtils';
4
+
5
+ export const styles = size =>
6
+ StyleSheet.create({
7
+ backgroundIcon: {
8
+ margin: moderateVerticalScale(10),
9
+ alignItems: 'center',
10
+ justifyContent: 'center',
11
+ backgroundColor: '#4D98FA',
12
+ borderRadius: 1000,
13
+ width: size,
14
+ height: size
15
+ }
16
+ });
17
+
18
+ export const colorIcon = 'white';
@@ -0,0 +1,168 @@
1
+ import React, { Fragment, useEffect, useState } from 'react';
2
+ // eslint-disable-next-line react-native/split-platform-components
3
+ import { View, TouchableOpacity, PermissionsAndroid } from 'react-native';
4
+ // eslint-disable-next-line import/no-unresolved
5
+ import { launchCamera } from 'react-native-image-picker';
6
+
7
+ import Label from '../Label';
8
+ import Portal from '../Portal';
9
+
10
+ import AddAnotherPhotoButton from './components/AddAnotherPhotoButton';
11
+ import DeleteView from './components/DeleteView';
12
+ import ReplaceView from './components/ReplaceView';
13
+ import Photo from './components/Photo';
14
+ import styles from './styles';
15
+ import propTypes from './propTypes';
16
+
17
+ const PhotoAlbum = ({
18
+ images,
19
+ selectedImages,
20
+ setSelectedImages,
21
+ deletePhoto,
22
+ selectedMode,
23
+ isItPossibleToAddAnotherPhoto,
24
+ onPressAddAnotherPhoto,
25
+ onError,
26
+ title,
27
+ subTitle,
28
+ onUnknownCameraError,
29
+ numberOfPhotosInTheAlbumHasExceeded,
30
+ isOnlyOnePicture,
31
+ sourceCameraImage,
32
+ sourceEditImage,
33
+ messageErrorPermissionCamera
34
+ }) => {
35
+ const requestPermission = async () => {
36
+ const permissionsResponse = await PermissionsAndroid.requestMultiple([
37
+ PermissionsAndroid.PERMISSIONS.CAMERA,
38
+ PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
39
+ ]);
40
+
41
+ const granted =
42
+ permissionsResponse[PermissionsAndroid.PERMISSIONS.CAMERA] === 'granted' &&
43
+ permissionsResponse[PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE] === 'granted';
44
+
45
+ if (!granted) {
46
+ throw messageErrorPermissionCamera;
47
+ }
48
+ };
49
+
50
+ const [isSelectedMode, setIsSelectedMode] = useState(false);
51
+ const onLongPressImage = uri => {
52
+ if (selectedImages.includes(uri)) {
53
+ setSelectedImages(selectedImages.filter(aPicUri => aPicUri !== uri));
54
+ } else {
55
+ setSelectedImages([...selectedImages, uri]);
56
+ }
57
+ };
58
+ const deleteSelectedPhotos = () => {
59
+ deletePhoto();
60
+ };
61
+
62
+ const openCamera = async () => {
63
+ await requestPermission();
64
+
65
+ const response = await launchCamera({});
66
+ const { didCancel, errorCode, errorMessage, assets } = response;
67
+ if (didCancel || errorCode) {
68
+ if (errorCode) {
69
+ onUnknownCameraError(`[${errorCode}] : ${errorMessage}`);
70
+ }
71
+ } else {
72
+ const { uri } = assets[0];
73
+ onPressAddAnotherPhoto({ newImage: { uri }, numberOfPhotosInTheAlbumHasExceeded });
74
+ }
75
+ };
76
+
77
+ const isDivisibleInModuleOfThree = () => {
78
+ const numberOfObjectsInView = isItPossibleToAddAnotherPhoto ? images.length + 1 : images.length;
79
+ return numberOfObjectsInView % 3 !== 0;
80
+ };
81
+
82
+ const cameraOnPress = () =>
83
+ openCamera().catch(error => {
84
+ if (typeof error === 'string') {
85
+ onError(error);
86
+ } else {
87
+ onUnknownCameraError(error);
88
+ }
89
+ });
90
+
91
+ const onPressAddAnotherPhotoButton = deleteSelectedImages => {
92
+ if (deleteSelectedImages) {
93
+ setSelectedImages([]);
94
+ }
95
+ cameraOnPress();
96
+ };
97
+
98
+ useEffect(() => {
99
+ if (selectedImages.length > 0) {
100
+ setIsSelectedMode(true);
101
+ } else {
102
+ setIsSelectedMode(false);
103
+ }
104
+ }, [selectedImages]);
105
+
106
+ return (
107
+ <Fragment>
108
+ {title && (
109
+ <Label big semiBold color="#666666" style={styles.title}>
110
+ {title}
111
+ </Label>
112
+ )}
113
+ {subTitle && (
114
+ <Label color="#3A3A3A" style={styles.subTitle}>
115
+ {subTitle}
116
+ </Label>
117
+ )}
118
+ <View style={styles.container}>
119
+ {images.length !== 0 &&
120
+ images.map(image => (
121
+ <Photo
122
+ key={image.uri ?? image}
123
+ image={image}
124
+ onLongPressImage={onLongPressImage}
125
+ selectedImages={selectedImages}
126
+ deletePhoto={deletePhoto}
127
+ isSelectedMode={isSelectedMode}
128
+ onError={onError}
129
+ />
130
+ ))}
131
+ {isItPossibleToAddAnotherPhoto && (
132
+ <AddAnotherPhotoButton
133
+ onPress={onPressAddAnotherPhotoButton}
134
+ disabled={numberOfPhotosInTheAlbumHasExceeded}
135
+ sourceCameraImage={sourceCameraImage}
136
+ />
137
+ )}
138
+ {isDivisibleInModuleOfThree() && <View style={styles.image} />}
139
+ {selectedMode && isSelectedMode && (
140
+ <Portal>
141
+ <View style={styles.selectedModeContainer}>
142
+ <View style={styles.selectionLabelContainer}>
143
+ <Label color="white">{`${selectedImages.length} selección`}</Label>
144
+ </View>
145
+ <View style={styles.buttonsContainer}>
146
+ {isOnlyOnePicture && (
147
+ <TouchableOpacity
148
+ onPress={() => onPressAddAnotherPhotoButton(numberOfPhotosInTheAlbumHasExceeded)}
149
+ style={styles.deleteSelectedPhotos}
150
+ >
151
+ <ReplaceView label="Remplazar" color="#3A3A3A" sourceEditImage={sourceEditImage} />
152
+ </TouchableOpacity>
153
+ )}
154
+ <TouchableOpacity onPress={deleteSelectedPhotos} style={styles.deleteSelectedPhotos}>
155
+ <DeleteView label="Eliminar" color="#3A3A3A" />
156
+ </TouchableOpacity>
157
+ </View>
158
+ </View>
159
+ </Portal>
160
+ )}
161
+ </View>
162
+ </Fragment>
163
+ );
164
+ };
165
+
166
+ PhotoAlbum.propTypes = propTypes;
167
+
168
+ export default PhotoAlbum;
@@ -0,0 +1,17 @@
1
+ import { bool, string, func, array } from 'prop-types';
2
+
3
+ export default {
4
+ images: array,
5
+ selectedImages: array,
6
+ setSelectedImages: func,
7
+ deletePhoto: func,
8
+ selectedMode: bool,
9
+ isItPossibleToAddAnotherPhoto: bool,
10
+ onPressAddAnotherPhoto: func,
11
+ onError: func,
12
+ title: string,
13
+ subTitle: string,
14
+ onUnknownCameraError: func,
15
+ numberOfPhotosInTheAlbumHasExceeded: bool,
16
+ isOnlyOnePicture: bool
17
+ };
@@ -0,0 +1,51 @@
1
+ import { Dimensions, StyleSheet } from 'react-native';
2
+
3
+ import { moderateHorizontalScale, moderateVerticalScale, WINDOW_WIDTH } from '../../utils/scaleUtils';
4
+
5
+ const IMAGE_SIZE = (Dimensions.get('window').width - 30) * 0.333333 - 10;
6
+ const styles = StyleSheet.create({
7
+ container: {
8
+ flexDirection: 'row',
9
+ flexWrap: 'wrap',
10
+ justifyContent: 'space-between',
11
+ paddingHorizontal: moderateHorizontalScale(5)
12
+ },
13
+ selectedModeContainer: {
14
+ width: WINDOW_WIDTH,
15
+ position: 'absolute',
16
+ bottom: 0
17
+ },
18
+ selectionLabelContainer: {
19
+ height: moderateVerticalScale(27),
20
+ alignItems: 'center',
21
+ backgroundColor: '#4D98FA'
22
+ },
23
+ buttonsContainer: {
24
+ flexDirection: 'row',
25
+ alignItems: 'center',
26
+ justifyContent: 'space-around',
27
+ backgroundColor: '#E4E6EA',
28
+ paddingHorizontal: 60
29
+ },
30
+ deleteSelectedPhotos: {
31
+ height: moderateVerticalScale(58),
32
+ justifyContent: 'center'
33
+ },
34
+ title: {
35
+ marginBottom: moderateVerticalScale(10),
36
+ paddingHorizontal: moderateHorizontalScale(5)
37
+ },
38
+ subTitle: {
39
+ marginBottom: moderateVerticalScale(5),
40
+ paddingHorizontal: moderateHorizontalScale(5)
41
+ },
42
+ image: {
43
+ width: IMAGE_SIZE,
44
+ height: IMAGE_SIZE,
45
+ borderRadius: 5,
46
+ marginBottom: moderateVerticalScale(10),
47
+ paddingHorizontal: moderateHorizontalScale(10)
48
+ }
49
+ });
50
+
51
+ export default styles;
@@ -1,7 +1,8 @@
1
- import React, { Component } from 'react';
1
+ import React, { Component, Fragment } from 'react';
2
2
  import { View, ViewPropTypes } from 'react-native';
3
3
  import PropTypes from 'prop-types';
4
4
 
5
+ import SeparatorBar from '../../../SeparatorBar';
5
6
  import Touchable from '../../../Touchable';
6
7
  import Icon from '../../../Icon';
7
8
  import Label from '../../../Label';
@@ -18,37 +19,64 @@ class RadioButton extends Component {
18
19
  // TODO: labelComponent is a patch to allow to use tooltips next to radio button label.Change this when mobile-ui has its own tooltip component
19
20
 
20
21
  render() {
21
- const { status, style, label, labelValue, sublabel, theme, labelComponent } = this.props;
22
+ const {
23
+ status,
24
+ style,
25
+ label,
26
+ labelValue,
27
+ sublabel,
28
+ theme,
29
+ labelComponent,
30
+ descriptionComponent,
31
+ showSeparatorBar
32
+ } = this.props;
22
33
  return (
23
- <Touchable onPress={this.handlePress}>
24
- <View style={[styles.container, style]}>
25
- <Icon
26
- name={status ? RADIO_CHECKED_ICON : RADIO_UNCHECKED_ICON}
27
- color={status ? theme.colors.primary : theme.colors.disabled}
28
- style={styles.iconSpacing}
29
- />
30
- <View style={styles.labelsContainer}>
31
- <View>
32
- <View style={[styles.label, labelComponent && styles.labelComponent]}>
33
- <Label small bold={status} primary={status}>
34
- {label}
35
- </Label>
36
- {labelComponent}
34
+ <Fragment>
35
+ <Touchable onPress={this.handlePress}>
36
+ <View style={[styles.container, style]}>
37
+ {descriptionComponent ? (
38
+ <View style={styles.descriptionComponentContainer}>
39
+ {descriptionComponent}
40
+ <Icon
41
+ name={status ? RADIO_CHECKED_ICON : RADIO_UNCHECKED_ICON}
42
+ color={theme.colors.primary}
43
+ style={styles.iconSpacing}
44
+ size={20}
45
+ />
37
46
  </View>
38
- {(sublabel || sublabel === 0) && (
39
- <Label disabled xsmall bold={status}>
40
- {sublabel}
41
- </Label>
42
- )}
43
- </View>
47
+ ) : (
48
+ <Fragment>
49
+ <Icon
50
+ name={status ? RADIO_CHECKED_ICON : RADIO_UNCHECKED_ICON}
51
+ color={status ? theme.colors.primary : theme.colors.disabled}
52
+ style={styles.iconSpacing}
53
+ />
54
+ <View style={styles.labelsContainer}>
55
+ <View>
56
+ <View style={[styles.label, labelComponent && styles.labelComponent]}>
57
+ <Label small bold={status} primary={status}>
58
+ {label}
59
+ </Label>
60
+ {labelComponent}
61
+ </View>
62
+ {(sublabel || sublabel === 0) && (
63
+ <Label disabled xsmall bold={status}>
64
+ {sublabel}
65
+ </Label>
66
+ )}
67
+ </View>
68
+ </View>
69
+ {labelValue && (
70
+ <Label bold={status} primary={status} small>
71
+ {labelValue}
72
+ </Label>
73
+ )}
74
+ </Fragment>
75
+ )}
44
76
  </View>
45
- {labelValue && (
46
- <Label bold={status} primary={status} small>
47
- {labelValue}
48
- </Label>
49
- )}
50
- </View>
51
- </Touchable>
77
+ </Touchable>
78
+ {showSeparatorBar && <SeparatorBar />}
79
+ </Fragment>
52
80
  );
53
81
  }
54
82
  }
@@ -65,7 +93,9 @@ RadioButton.propTypes = {
65
93
  sublabel: PropTypes.string
66
94
  }),
67
95
  theme: themeType,
68
- labelComponent: PropTypes.node
96
+ labelComponent: PropTypes.node,
97
+ descriptionComponent: PropTypes.node,
98
+ showSeparatorBar: PropTypes.bool
69
99
  };
70
100
 
71
101
  export default withTheme(RadioButton);
@@ -23,5 +23,11 @@ export default StyleSheet.create({
23
23
  },
24
24
  labelComponent: {
25
25
  width: '90%'
26
+ },
27
+ descriptionComponentContainer: {
28
+ justifyContent: 'space-between',
29
+ flexDirection: 'row',
30
+ alignItems: 'center',
31
+ width: '100%'
26
32
  }
27
33
  });
@@ -26,6 +26,8 @@ class RadioGroup extends Component {
26
26
  sublabel={option.sublabel}
27
27
  onPress={this.handleOptionSelected}
28
28
  status={selectedOption === option[keyField]}
29
+ descriptionComponent={option?.Component}
30
+ showSeparatorBar={option?.showSeparatorBar}
29
31
  {...radioProps}
30
32
  />
31
33
  );
package/lib/index.js CHANGED
@@ -69,3 +69,7 @@ export { default as withLoading } from './components/WithLoading';
69
69
  // Hooks
70
70
  export { default as useEffectOnlyOnUpdates } from './hooks/useEffectOnlyOnUpdates';
71
71
  export { default as useTogglableState } from './hooks/useTogglableState';
72
+
73
+ // Photo
74
+ export { default as PhotoAlbum } from './components/PhotoAlbum';
75
+ export { default as Capture } from './components/Capture';
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@widergy/mobile-ui",
3
3
  "description": "Widergy Mobile Components",
4
4
  "author": "widergy",
5
- "version": "0.33.0",
5
+ "version": "0.34.2",
6
6
  "repository": "https://github.com/widergy/mobile-ui.git",
7
7
  "main": "lib/index.js",
8
8
  "files": [