@widergy/mobile-ui 1.27.0 → 1.28.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 (36) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/lib/components/CheckList/index.js +4 -0
  3. package/lib/components/Checkbox/index.js +4 -0
  4. package/lib/components/MultipleFilePicker/components/Picker/index.js +66 -74
  5. package/lib/components/MultipleFilePicker/components/Picker/styles.js +26 -34
  6. package/lib/components/MultipleFilePicker/components/UploadedFiles/index.js +27 -129
  7. package/lib/components/MultipleFilePicker/components/UploadedFiles/styles.js +8 -57
  8. package/lib/components/MultipleFilePicker/constants.js +0 -14
  9. package/lib/components/MultipleFilePicker/index.js +196 -147
  10. package/lib/components/MultipleFilePicker/propTypes.js +15 -11
  11. package/lib/components/MultipleFilePicker/styles.js +9 -0
  12. package/lib/components/MultipleFilePicker/utils.js +22 -51
  13. package/lib/components/UTBaseInputField/components/IconAdornment/utils.js +2 -3
  14. package/lib/components/UTCheckBox/constants.js +2 -0
  15. package/lib/components/UTCheckBox/index.js +25 -16
  16. package/lib/components/UTCheckBox/theme.js +1 -3
  17. package/lib/components/UTCheckList/constants.js +0 -2
  18. package/lib/components/UTCheckList/index.js +7 -6
  19. package/lib/components/UTCheckList/styles.js +2 -1
  20. package/lib/components/UTCheckList/utils.js +2 -2
  21. package/lib/components/UTFieldLabel/index.js +4 -3
  22. package/package.json +1 -1
  23. package/lib/components/MultipleFilePicker/components/Input/README.md +0 -77
  24. package/lib/components/MultipleFilePicker/components/Input/components/ShowPassword/constants.js +0 -2
  25. package/lib/components/MultipleFilePicker/components/Input/components/ShowPassword/index.js +0 -19
  26. package/lib/components/MultipleFilePicker/components/Input/components/ShowPassword/propTypes.js +0 -8
  27. package/lib/components/MultipleFilePicker/components/Input/components/ShowPassword/styles.js +0 -11
  28. package/lib/components/MultipleFilePicker/components/Input/components/Title/index.js +0 -78
  29. package/lib/components/MultipleFilePicker/components/Input/components/Title/propTypes.js +0 -14
  30. package/lib/components/MultipleFilePicker/components/Input/components/Title/styles.js +0 -42
  31. package/lib/components/MultipleFilePicker/components/Input/components/Underline/index.js +0 -80
  32. package/lib/components/MultipleFilePicker/components/Input/components/Underline/styles.js +0 -39
  33. package/lib/components/MultipleFilePicker/components/Input/constants.js +0 -2
  34. package/lib/components/MultipleFilePicker/components/Input/index.js +0 -299
  35. package/lib/components/MultipleFilePicker/components/Input/propTypes.js +0 -43
  36. package/lib/components/MultipleFilePicker/components/Input/styles.js +0 -47
@@ -1,168 +1,217 @@
1
- import React, { Component } from 'react';
2
- import { View } from 'react-native';
1
+ import { isArray, isEmpty } from 'lodash';
2
+ // eslint-disable-next-line import/no-unresolved
3
+ import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
4
+ // eslint-disable-next-line react-native/split-platform-components
5
+ import { View, PermissionsAndroid } from 'react-native';
3
6
  // eslint-disable-next-line import/no-unresolved
4
7
  import DocumentPicker from 'react-native-document-picker';
5
- import { isArray, isEmpty } from 'lodash';
8
+ import React, { useEffect, useState } from 'react';
6
9
 
10
+ import { IS_IOS } from '../../utils/platformUtils/constants';
7
11
  import { retrieveFile, blobToFile } from '../../utils/fileUtils.js';
12
+ import UTBottomSheet from '../UTBottomSheet';
13
+ import UTButton from '../UTButton';
8
14
 
9
- import Picker from './components/Picker';
10
- import UploadedFiles from './components/UploadedFiles';
11
- import { UPLOAD_ICON, DEFAULT_MAX_SIZE } from './constants';
15
+ import { DEFAULT_MAX_SIZE } from './constants';
16
+ import { getInitialValuesFrom, isFileFormatInvalid, isFileSizeInvaid, isFileTypeInvalid } from './utils';
12
17
  import filePickerPropTypes from './propTypes';
13
- import {
14
- getInitialValuesFrom,
15
- isInvalidFileSize,
16
- onlyPDFAllowed,
17
- validateFileFormat,
18
- validateFileQuantity,
19
- validateFileType,
20
- validateOnlyPDFAllowed
21
- } from './utils';
22
-
23
- class MultipleFilePicker extends Component {
24
- constructor(props) {
25
- super(props);
26
- const { files } = props?.value || [];
27
-
28
- this.state = {
29
- uploadedFiles: isArray(files) ? getInitialValuesFrom(files) : [],
30
- rawFiles: isArray(files) ? files : []
31
- };
32
- }
33
-
34
- componentDidUpdate(_, prevState) {
35
- const { rawFiles } = this.state;
36
- const { onChange } = this.props;
37
-
38
- if (prevState.rawFiles !== rawFiles && onChange) {
39
- const payloadOnChange = isEmpty(rawFiles) ? null : { files: rawFiles };
40
- onChange(payloadOnChange);
41
- }
42
- }
43
-
44
- handleShowPicker = async () => {
45
- const {
46
- allowedTypes,
47
- onMaxSizeError,
48
- onError,
49
- maxFileByteSize,
50
- maxFiles,
51
- minFiles,
52
- avoidRetrieveFile,
53
- fileTypeError,
54
- allowedPDFUploadSizes,
55
- pdfFormatError
56
- } = this.props;
57
- try {
58
- const documents = await DocumentPicker.pick({
59
- allowMultiSelection: true,
60
- type: allowedTypes && !onlyPDFAllowed(allowedTypes) ? allowedTypes : DocumentPicker.types.allFiles
61
- });
62
- const { uploadedFiles } = this.state;
63
-
64
- const filesSelectedQuantity = uploadedFiles.length + documents.length;
65
- validateFileQuantity(filesSelectedQuantity, { maxFiles, minFiles }, fileTypeError);
66
-
67
- await Promise.all(
68
- documents.map(async document => {
69
- const hasFileBeenUploaded = uploadedFiles.some(fileAdded => fileAdded.name === document.name);
70
-
71
- if (!hasFileBeenUploaded) {
72
- validateOnlyPDFAllowed(document, allowedTypes, fileTypeError);
73
- validateFileType(document, allowedTypes, fileTypeError);
74
-
75
- const isValid = isInvalidFileSize(document, maxFileByteSize, onMaxSizeError);
76
- if (isValid) return;
18
+ import Picker from './components/Picker';
19
+ import styles from './styles';
20
+
21
+ const MultipleFilePicker = ({
22
+ allowedPDFUploadSizes,
23
+ allowedTypes,
24
+ disabled,
25
+ enabledInputs: { camera, files, gallery } = { files: true },
26
+ error,
27
+ filePlaceholder,
28
+ fileTypeError,
29
+ helpText,
30
+ maxFileByteSize = DEFAULT_MAX_SIZE,
31
+ maxFiles,
32
+ onChange,
33
+ onError: onError_,
34
+ onMaxSizeError: onMaxSizeError_,
35
+ pickerText,
36
+ style,
37
+ title,
38
+ value
39
+ }) => {
40
+ const { files: values } = value || {};
41
+
42
+ const [newFile, setNewFile] = useState(null);
43
+ const [uploadedFiles, setUploadedFiles] = useState(isArray(values) ? getInitialValuesFrom(values) : []);
44
+ const [rawFiles, setRawFiles] = useState(isArray(values) ? values : []);
45
+
46
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false);
47
+ const closeDrawer = () => setIsDrawerOpen(false);
48
+
49
+ const onError = errorMsg => {
50
+ onError_(errorMsg);
51
+ closeDrawer();
52
+ };
77
53
 
78
- const file =
79
- !avoidRetrieveFile && (await retrieveFile(document.uri, document.type, document.name));
54
+ const onMaxSizeError = () => {
55
+ onMaxSizeError_(maxFileByteSize);
56
+ closeDrawer();
57
+ };
80
58
 
81
- await validateFileFormat(file, document, allowedPDFUploadSizes, pdfFormatError);
59
+ useEffect(() => {
60
+ onChange?.(isEmpty(rawFiles) ? null : { files: rawFiles });
61
+ }, [rawFiles]);
82
62
 
83
- const fileToUpload = avoidRetrieveFile ? { document } : { file: blobToFile(file, document.type) };
63
+ useEffect(() => {
64
+ if (newFile) {
65
+ setUploadedFiles([...uploadedFiles, newFile.uploadFile]);
66
+ setRawFiles([...rawFiles, newFile.rawFile]);
67
+ }
68
+ }, [newFile]);
69
+
70
+ const onPickFiles = async () => {
71
+ const documents = await DocumentPicker.pick({
72
+ allowMultiSelection: true,
73
+ type: allowedTypes ?? DocumentPicker.types.allFiles
74
+ });
75
+
76
+ if (uploadedFiles.length + documents.length > maxFiles)
77
+ onError('La cantidad de archivos supera al máximo permitido');
78
+ else {
79
+ closeDrawer();
80
+ documents.forEach(async document => {
81
+ if (!uploadedFiles.some(({ name }) => name === document.name)) {
82
+ if (isFileTypeInvalid(document, allowedTypes, fileTypeError, onError)) return;
83
+ if (isFileSizeInvaid(document, maxFileByteSize, onMaxSizeError)) return;
84
+ const file = await retrieveFile(document.uri, document.type, document.name);
85
+ if (await isFileFormatInvalid(file, allowedPDFUploadSizes, onError)) return;
86
+ setNewFile({
87
+ uploadFile: { name: document.name, size: document.size },
88
+ rawFile: blobToFile(file, document.type)
89
+ });
90
+ }
91
+ });
92
+ }
93
+ };
84
94
 
85
- this.setState(prevState => ({
86
- uploadedFiles: [...prevState.uploadedFiles, { name: document.name, size: document.size }],
87
- rawFiles: [...prevState.rawFiles, fileToUpload]
88
- }));
89
- }
90
- })
91
- );
95
+ // eslint-disable-next-line consistent-return
96
+ const requestPermissionCamera = async () => {
97
+ try {
98
+ const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA);
99
+ return granted === PermissionsAndroid.RESULTS.GRANTED
100
+ ? launchCamera
101
+ : { errorCode: 'Son necesarios permisos para utilizar la cámara' };
92
102
  } catch (err) {
93
- if (!DocumentPicker.isCancel(err)) {
94
- onError(err.message);
95
- }
103
+ onError(err.message);
96
104
  }
97
105
  };
98
106
 
99
- handleDeleteFile = index => {
100
- const { onChange } = this.props;
101
- if (onChange) {
102
- onChange(null);
107
+ const handleShowImagePicker = sourceImage => {
108
+ if (sourceImage?.errorCode) {
109
+ onError(sourceImage.errorCode);
110
+ return;
103
111
  }
104
- this.setState(prevState => ({
105
- uploadedFiles: prevState.uploadedFiles.filter((a, i) => i !== index),
106
- rawFiles: prevState.rawFiles.filter((a, i) => i !== index)
107
- }));
112
+ sourceImage(
113
+ {
114
+ mediaType: 'photo',
115
+ selectionLimit: Math.max(maxFiles - uploadedFiles.length, 0)
116
+ },
117
+ async response => {
118
+ if (response.didCancel) return;
119
+
120
+ if (response.errorCode) {
121
+ onError(response.errorCode);
122
+ return;
123
+ }
124
+ closeDrawer();
125
+ response.assets.forEach(async asset => {
126
+ const file = await retrieveFile(asset.uri, asset.type);
127
+ if (!file) {
128
+ onError(response.errorCode);
129
+ return;
130
+ }
131
+ if (isFileTypeInvalid(file, allowedTypes, fileTypeError, onError)) return;
132
+ if (isFileSizeInvaid(file, maxFileByteSize, onMaxSizeError)) return;
133
+
134
+ setNewFile({
135
+ uploadFile: { name: file.data.name, size: file.data.size },
136
+ rawFile: blobToFile(file, asset.type)
137
+ });
138
+ });
139
+ }
140
+ );
108
141
  };
109
142
 
110
- render() {
111
- const {
112
- error,
113
- title,
114
- filePlaceholder,
115
- style,
116
- withMarkdownTitle,
117
- markdownStyles,
118
- disabled,
119
- helpText,
120
- pickerText,
121
- UploadIcon
122
- } = this.props;
123
- const { uploadedFiles } = this.state;
124
-
125
- return uploadedFiles.length !== 0 ? (
126
- <View style={style}>
127
- <UploadedFiles
128
- icon={UPLOAD_ICON}
129
- error={error}
130
- onAdd={this.handleShowPicker}
131
- onDelete={this.handleDeleteFile}
132
- uploadedFiles={uploadedFiles}
133
- filePlaceholder={filePlaceholder}
134
- title={title}
135
- withMarkdownTitle={withMarkdownTitle}
136
- markdownStyles={markdownStyles}
137
- disabled={disabled}
138
- pickerText={pickerText}
139
- helpText={helpText}
140
- />
141
- </View>
142
- ) : (
143
- <View style={style}>
144
- <Picker
145
- icon={UPLOAD_ICON}
146
- error={error}
147
- onAdd={this.handleShowPicker}
148
- onDelete={this.handleDeleteFile}
149
- uploadedFiles={uploadedFiles}
150
- filePlaceholder={filePlaceholder}
151
- title={title}
152
- withMarkdownTitle={withMarkdownTitle}
153
- markdownStyles={markdownStyles}
154
- disabled={disabled}
155
- pickerText={pickerText}
156
- helpText={helpText}
157
- UploadIcon={UploadIcon}
158
- />
159
- </View>
160
- );
161
- }
162
- }
143
+ const onPickCamera = async () =>
144
+ handleShowImagePicker(IS_IOS ? launchCamera : await requestPermissionCamera());
145
+
146
+ const onPickGallery = () => handleShowImagePicker(launchImageLibrary);
147
+
148
+ const handleDeleteFile = index => {
149
+ onChange?.(null);
150
+ setUploadedFiles(uploadedFiles.filter((_, i) => i !== index));
151
+ setRawFiles(rawFiles.filter((_, i) => i !== index));
152
+ };
153
+
154
+ const onAdd = () => {
155
+ if (Boolean(camera) + Boolean(files) + Boolean(gallery) > 1) setIsDrawerOpen(true);
156
+ else if (camera) onPickCamera();
157
+ else if (files) onPickFiles();
158
+ else if (gallery) onPickGallery();
159
+ };
163
160
 
164
- MultipleFilePicker.defaultProps = {
165
- maxFileByteSize: DEFAULT_MAX_SIZE
161
+ return (
162
+ <View style={style}>
163
+ <Picker
164
+ disabled={disabled}
165
+ error={error}
166
+ filePlaceholder={filePlaceholder}
167
+ helpText={helpText}
168
+ maxFiles={maxFiles}
169
+ onAdd={onAdd}
170
+ onDelete={handleDeleteFile}
171
+ pickerText={pickerText}
172
+ title={title}
173
+ uploadedFiles={uploadedFiles}
174
+ />
175
+ <UTBottomSheet onClose={closeDrawer} visible={isDrawerOpen}>
176
+ <View style={styles.actions}>
177
+ {[
178
+ {
179
+ Icon: 'IconCamera',
180
+ onPress: onPickCamera,
181
+ show: camera,
182
+ text: 'Cámara'
183
+ },
184
+ {
185
+ Icon: 'IconPhoto',
186
+ onPress: onPickGallery,
187
+ show: gallery,
188
+ text: 'Fotos'
189
+ },
190
+ {
191
+ Icon: 'IconFileArrowRight',
192
+ onPress: onPickFiles,
193
+ show: files,
194
+ text: 'Archivos'
195
+ }
196
+ ].map(
197
+ ({ Icon, onPress, show, text }) =>
198
+ show && (
199
+ <UTButton
200
+ colorTheme="secondary"
201
+ Icon={Icon}
202
+ key={text}
203
+ onPress={onPress}
204
+ size="large"
205
+ variant="shadow"
206
+ >
207
+ {text}
208
+ </UTButton>
209
+ )
210
+ )}
211
+ </View>
212
+ </UTBottomSheet>
213
+ </View>
214
+ );
166
215
  };
167
216
 
168
217
  MultipleFilePicker.propTypes = filePickerPropTypes;
@@ -1,17 +1,21 @@
1
- import { oneOfType, string, bool, func, number, arrayOf, shape } from 'prop-types';
1
+ import { string, bool, func, number, array, object } from 'prop-types';
2
2
 
3
3
  export default {
4
- error: oneOfType([string, bool]),
5
- onChange: func,
6
- allowedTypes: arrayOf(string),
4
+ allowedPDFUploadSizes: array,
5
+ allowedTypes: array,
6
+ disabled: bool,
7
+ enabledInputs: object,
8
+ error: string,
7
9
  filePlaceholder: string,
8
- title: string,
9
- onMaxSizeError: func,
10
+ fileTypeError: string,
11
+ helpText: string,
10
12
  maxFileByteSize: number,
13
+ maxFiles: number,
14
+ onChange: func,
11
15
  onError: func,
12
- fileTypeError: string,
13
- allowedPDFUploadSizes: arrayOf(
14
- shape({ name: string, heightInPt: number, widthInPt: number, tolerance: number })
15
- ),
16
- disabled: bool
16
+ onMaxSizeError: func,
17
+ pickerText: string,
18
+ style: object,
19
+ title: string,
20
+ value: object
17
21
  };
@@ -0,0 +1,9 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ actions: {
5
+ display: 'flex',
6
+ flexDirection: 'column',
7
+ gap: 8
8
+ }
9
+ });
@@ -1,10 +1,6 @@
1
1
  import { PDFDocument } from 'pdf-lib';
2
2
  import { isEmpty } from 'lodash';
3
3
 
4
- import { isImageByUri } from '../../utils/fileUtils.js';
5
-
6
- export const onlyPDFAllowed = allowedTypes => allowedTypes.length === 1 && allowedTypes[0].includes('pdf');
7
-
8
4
  const lengthMatches = (length1, length2, toleranceInPercentage) => {
9
5
  const delta = length1 * (toleranceInPercentage / 100);
10
6
  return Math.abs(length1 - length2) < delta;
@@ -32,7 +28,7 @@ const blobToBase64 = blob =>
32
28
  reader.readAsDataURL(blob);
33
29
  });
34
30
 
35
- export const pdfAspectRatioValidation = async (file, allowedPDFUploadSizes) => {
31
+ const pdfAspectRatioValidation = async (file, allowedPDFUploadSizes) => {
36
32
  const base64 = await blobToBase64(file);
37
33
  const pdf = await PDFDocument.load(base64);
38
34
  const pages = pdf.getPages();
@@ -43,58 +39,33 @@ export const pdfAspectRatioValidation = async (file, allowedPDFUploadSizes) => {
43
39
  });
44
40
  };
45
41
 
46
- export const validateFileQuantity = (fieldQuantity, { maxFiles, minFiles }, fileTypeError) => {
47
- if (fieldQuantity > maxFiles) {
48
- throw new Error(fileTypeError || 'La cantidad de archivos supera al máximo permitido');
49
- }
50
- if (fieldQuantity < minFiles) {
51
- throw new Error(fileTypeError || 'La cantidad de archivos es menor al mínimo permitido');
52
- }
53
- };
54
-
55
- const isPDF = document => document.type.includes('pdf');
56
- const isImage = document => document.type.includes('image');
57
-
58
- export const validateOnlyPDFAllowed = (document, allowedTypes, fileTypeError) => {
59
- const condition = onlyPDFAllowed(allowedTypes) && !isPDF(document);
60
- if (condition) {
61
- throw new Error(fileTypeError || 'El tipo de archivo debe ser PDF.');
62
- }
63
- };
64
-
65
- export const validateFileType = (document, allowedTypes, fileTypeError) => {
66
- const isInvalidImage = !isImage(document) && !isImageByUri(document.uri);
67
- const condition = allowedTypes && isInvalidImage && !isPDF(document);
68
- if (condition) {
69
- throw new Error(fileTypeError || 'Tipo de archivo inválido.');
70
- }
42
+ export const isFileTypeInvalid = (document, allowedTypes, fileTypeError, onError) => {
43
+ const isInvalid = !(
44
+ allowedTypes.includes(document.type) ||
45
+ (document.type.includes('image') && allowedTypes.includes('image/*'))
46
+ );
47
+ if (isInvalid) onError(fileTypeError || 'Tipo de archivo inválido.');
48
+ return isInvalid;
71
49
  };
72
50
 
73
- export const isInvalidFileSize = (document, maxFileByteSize, onMaxSizeError) => {
51
+ export const isFileSizeInvaid = (document, maxFileByteSize, onError) => {
74
52
  const isInvalid = maxFileByteSize && document.size > maxFileByteSize;
75
- if (isInvalid) {
76
- if (onMaxSizeError) {
77
- onMaxSizeError(document.size, maxFileByteSize);
78
- } else {
79
- throw new Error(`El archivo debe ser menor a ${maxFileByteSize}`);
80
- }
81
- }
53
+ if (isInvalid) onError(`El archivo debe ser menor a ${maxFileByteSize}`);
82
54
  return isInvalid;
83
55
  };
84
56
 
85
- export const validateFileFormat = async (file, document, allowedPDFUploadSizes, pdfFormatError) => {
86
- const isInvalid = file && isPDF(document) && !isEmpty(allowedPDFUploadSizes);
87
- if (isInvalid) {
88
- const isWrongFormat = await pdfAspectRatioValidation(file, allowedPDFUploadSizes);
89
- if (isWrongFormat) {
90
- throw new Error(
91
- pdfFormatError ||
92
- `El formato de archivo es inválido. (Válidos: ${allowedPDFUploadSizes
93
- ?.map(aspectRatio => aspectRatio.name)
94
- .join(' - ')})`
95
- );
96
- }
97
- }
57
+ export const isFileFormatInvalid = async (file, allowedPDFUploadSizes, onError) => {
58
+ const isInvalid =
59
+ file.type.includes('pdf') &&
60
+ !isEmpty(allowedPDFUploadSizes) &&
61
+ (await pdfAspectRatioValidation(file, allowedPDFUploadSizes));
62
+ if (isInvalid)
63
+ onError(
64
+ `El formato de archivo es inválido. (Válidos: ${allowedPDFUploadSizes
65
+ ?.map(aspectRatio => aspectRatio.name)
66
+ .join(' - ')})`
67
+ );
68
+ return isInvalid;
98
69
  };
99
70
 
100
71
  export const getInitialValuesFrom = files =>
@@ -1,7 +1,6 @@
1
- export const getIconColorProps = (changeOnError, changeOnFocus, colorTheme, error, focused, shade) => {
2
- return changeOnError && error
1
+ export const getIconColorProps = (changeOnError, changeOnFocus, colorTheme, error, focused, shade) =>
2
+ changeOnError && error
3
3
  ? { colorTheme: 'error', shade: '04' }
4
4
  : changeOnFocus && focused
5
5
  ? { colorTheme: 'accent', shade: '04' }
6
6
  : { colorTheme: colorTheme || 'gray', shade };
7
- };
@@ -5,3 +5,5 @@ export const SPACING = {
5
5
  SMALL: 'small',
6
6
  LARGE: 'large'
7
7
  };
8
+
9
+ export const BUTTON_VARIANT = 'button';
@@ -5,23 +5,24 @@ import { useTheme } from '../../theming';
5
5
  import UTFieldLabel from '../UTFieldLabel';
6
6
  import UTIcon from '../UTIcon';
7
7
 
8
- import { CHECKED_ICON, INDETERMINATE_ICON } from './constants';
8
+ import { BUTTON_VARIANT, CHECKED_ICON, INDETERMINATE_ICON } from './constants';
9
9
  import { propTypes, defaultProps } from './proptypes';
10
10
  import { retrieveStyle } from './theme';
11
11
  import styles from './styles';
12
12
 
13
13
  const UTCheckBox = ({
14
- checked,
14
+ value,
15
+ onChange,
15
16
  disabled,
16
17
  indeterminate,
17
18
  isSimple,
18
- onPress,
19
19
  required,
20
20
  reversed,
21
21
  spacing,
22
22
  style,
23
23
  title,
24
- variant
24
+ variant,
25
+ withMarkdown
25
26
  }) => {
26
27
  const theme = useTheme();
27
28
  const [pressed, setPressed] = useState(false);
@@ -29,7 +30,7 @@ const UTCheckBox = ({
29
30
  const { containerStyles, iconContainerStyles, boxStyles, pressableStyles, titleStyles } = useMemo(
30
31
  () =>
31
32
  retrieveStyle({
32
- checked,
33
+ checked: value,
33
34
  disabled,
34
35
  indeterminate,
35
36
  pressed,
@@ -39,33 +40,36 @@ const UTCheckBox = ({
39
40
  theme,
40
41
  variant
41
42
  }),
42
- [checked, disabled, indeterminate, reversed, spacing, style, theme, variant, pressed]
43
+ [value, disabled, indeterminate, reversed, spacing, style, theme, variant, pressed]
43
44
  );
44
45
 
45
46
  const iconName = useMemo(
46
- () => (indeterminate ? INDETERMINATE_ICON : checked ? CHECKED_ICON : ''),
47
- [indeterminate, checked]
47
+ () => (indeterminate ? INDETERMINATE_ICON : value ? CHECKED_ICON : ''),
48
+ [indeterminate, value]
48
49
  );
49
50
 
50
51
  const handlePressIn = useCallback(() => setPressed(true), []);
51
52
  const handlePressOut = useCallback(() => setPressed(false), []);
52
53
 
54
+ const handlePress = useCallback(() => {
55
+ if (!disabled && onChange) {
56
+ onChange(!value);
57
+ }
58
+ }, [disabled, onChange, value]);
59
+
60
+ const shouldHighlightLabel = value && variant === BUTTON_VARIANT;
61
+
53
62
  return (
54
63
  <Pressable
55
64
  style={pressableStyles}
56
65
  disabled={disabled}
57
- onPress={onPress}
66
+ onPress={handlePress}
58
67
  onPressIn={handlePressIn}
59
68
  onPressOut={handlePressOut}
60
69
  >
61
70
  <View style={containerStyles}>
62
71
  {isSimple ? (
63
- <UTIcon
64
- name="IconCheck"
65
- shade="04"
66
- colorTheme="accent"
67
- style={checked ? undefined : styles.hidden}
68
- />
72
+ <UTIcon name="IconCheck" shade="04" colorTheme="accent" style={value ? undefined : styles.hidden} />
69
73
  ) : (
70
74
  <View style={boxStyles}>
71
75
  <View style={iconContainerStyles}>
@@ -73,7 +77,12 @@ const UTCheckBox = ({
73
77
  </View>
74
78
  </View>
75
79
  )}
76
- <UTFieldLabel colorTheme={checked ? 'accent' : 'dark'} required={required} style={titleStyles}>
80
+ <UTFieldLabel
81
+ colorTheme={shouldHighlightLabel ? 'accent' : 'dark'}
82
+ required={required}
83
+ style={titleStyles}
84
+ withMarkdown={withMarkdown}
85
+ >
77
86
  {title}
78
87
  </UTFieldLabel>
79
88
  </View>
@@ -1,6 +1,4 @@
1
- import { BUTTON_VARIANT } from '../UTCheckList/constants';
2
-
3
- import { SPACING } from './constants';
1
+ import { BUTTON_VARIANT, SPACING } from './constants';
4
2
 
5
3
  const NORMAL_SPACING = 16;
6
4
  const SMALL_SPACING = 8;
@@ -2,5 +2,3 @@ export const SPACING = {
2
2
  SMALL: 'small',
3
3
  LARGE: 'large'
4
4
  };
5
-
6
- export const BUTTON_VARIANT = 'button';