@widergy/mobile-ui 1.14.6 → 1.15.1

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 (68) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/lib/components/Button/index.js +1 -1
  3. package/lib/components/UTBadge/index.js +2 -2
  4. package/lib/components/UTBadge/theme.js +9 -6
  5. package/lib/components/UTBaseInputField/README.md +45 -31
  6. package/lib/components/UTBaseInputField/components/ActionAdornment/index.js +5 -16
  7. package/lib/components/UTBaseInputField/components/BadgeAdornment/index.js +13 -0
  8. package/lib/components/UTBaseInputField/components/IconAdornment/constants.js +2 -0
  9. package/lib/components/UTBaseInputField/components/IconAdornment/index.js +20 -15
  10. package/lib/components/UTBaseInputField/components/IconAdornment/proptypes.js +20 -0
  11. package/lib/components/UTBaseInputField/components/IconAdornment/utils.js +7 -2
  12. package/lib/components/UTBaseInputField/constants.js +18 -3
  13. package/lib/components/UTBaseInputField/index.js +89 -88
  14. package/lib/components/UTBaseInputField/proptypes.js +60 -0
  15. package/lib/components/UTBaseInputField/theme.js +72 -32
  16. package/lib/components/UTBottomSheet/README.md +53 -0
  17. package/lib/components/UTBottomSheet/index.js +139 -0
  18. package/lib/components/UTBottomSheet/styles.js +46 -0
  19. package/lib/components/UTButton/constants.js +5 -14
  20. package/lib/components/UTButton/index.js +6 -22
  21. package/lib/components/UTButton/proptypes.js +29 -0
  22. package/lib/components/UTButton/theme.js +6 -5
  23. package/lib/components/UTCheckBox/README.md +4 -30
  24. package/lib/components/UTCheckBox/constants.js +4 -1
  25. package/lib/components/UTCheckBox/index.js +33 -22
  26. package/lib/components/UTCheckBox/proptypes.js +12 -3
  27. package/lib/components/UTCheckBox/styles.js +7 -0
  28. package/lib/components/UTCheckBox/theme.js +98 -54
  29. package/lib/components/UTCheckList/README.MD +14 -10
  30. package/lib/components/UTCheckList/constants.js +6 -1
  31. package/lib/components/UTCheckList/index.js +44 -66
  32. package/lib/components/UTCheckList/proptypes.js +48 -0
  33. package/lib/components/UTCheckList/styles.js +10 -5
  34. package/lib/components/UTCheckList/utils.js +5 -0
  35. package/lib/components/UTFieldLabel/index.js +4 -3
  36. package/lib/components/UTLabel/constants.js +11 -11
  37. package/lib/components/UTLabel/index.js +3 -17
  38. package/lib/components/UTLabel/proptypes.js +19 -0
  39. package/lib/components/UTLabel/theme.js +2 -2
  40. package/lib/components/UTMenu/index.js +1 -1
  41. package/lib/components/UTPasswordField/versions/V0/components/PasswordValidations/styles.js +1 -0
  42. package/lib/components/UTPasswordField/versions/V1/index.js +3 -2
  43. package/lib/components/UTPhoneInput/constants.js +303 -0
  44. package/lib/components/UTPhoneInput/index.js +296 -0
  45. package/lib/components/UTPhoneInput/styles.js +18 -0
  46. package/lib/components/UTSearchField/README.md +42 -0
  47. package/lib/components/UTSearchField/index.js +59 -0
  48. package/lib/components/UTSearchField/proptypes.js +28 -0
  49. package/lib/components/UTSelect/index.js +10 -97
  50. package/lib/components/UTSelect/{componentes → versions/V0/componentes}/MultipleItem/index.js +1 -1
  51. package/lib/components/UTSelect/versions/V0/index.js +103 -0
  52. package/lib/components/UTSelect/versions/V1/README.md +82 -0
  53. package/lib/components/UTSelect/versions/V1/index.js +171 -0
  54. package/lib/components/UTSelect/versions/V1/proptypes.js +45 -0
  55. package/lib/components/UTSelect/versions/V1/styles.js +18 -0
  56. package/lib/components/UTTextArea/index.js +4 -2
  57. package/lib/components/UTTextInput/versions/V0/components/BaseInput/index.js +3 -3
  58. package/lib/components/UTTextInput/versions/V1/README.md +36 -35
  59. package/lib/components/UTTextInput/versions/V1/components/TextInputField/index.js +24 -15
  60. package/lib/components/UTTextInput/versions/V1/constants.js +3 -5
  61. package/lib/components/UTTextInput/versions/V1/index.js +25 -20
  62. package/lib/components/UTTextInput/versions/V1/proptypes.js +25 -7
  63. package/lib/constants/inputs.js +4 -0
  64. package/lib/index.js +47 -51
  65. package/package.json +2 -2
  66. /package/lib/components/UTSelect/{componentes → versions/V0/componentes}/MultipleItem/styles.js +0 -0
  67. /package/lib/components/UTSelect/{proptypes.js → versions/V0/proptypes.js} +0 -0
  68. /package/lib/components/UTSelect/{styles.js → versions/V0/styles.js} +0 -0
@@ -0,0 +1,296 @@
1
+ import React, { PureComponent } from 'react';
2
+ import { View } from 'react-native';
3
+ import { bool, elementType, func, number, shape, string } from 'prop-types';
4
+
5
+ import UTBaseInputField from '../UTBaseInputField';
6
+ import UTFieldLabel from '../UTFieldLabel';
7
+ import UTLabel from '../UTLabel';
8
+ import UTValidation from '../UTValidation';
9
+ import { formatErrorToValidation } from '../UTValidation/utils';
10
+ import { LABEL_VARIANTS } from '../../constants/inputs';
11
+ import { COMPONENT_KEYS } from '../UTBaseInputField/constants';
12
+ import { validationDataProptypes } from '../UTValidation/constants';
13
+
14
+ import { AREA_CODES } from './constants';
15
+ import styles from './styles';
16
+
17
+ class UTPhoneInput extends PureComponent {
18
+ constructor(props) {
19
+ super(props);
20
+ this.state = {
21
+ areaCode: '',
22
+ bigFocus: false,
23
+ areaCodeError: '',
24
+ firstFocus: false,
25
+ isValidCode: false,
26
+ phoneNumber: '',
27
+ phoneRef: null,
28
+ secondFocus: false
29
+ };
30
+
31
+ this.handleFirstBlur = this.handleBlur('firstFocus');
32
+ this.handleSecondBlur = this.handleBlur('secondFocus');
33
+ this.handleFirstFocus = this.handleFocus('firstFocus');
34
+ this.handleSecondFocus = this.handleFocus('secondFocus');
35
+ }
36
+
37
+ componentDidMount() {
38
+ this.updateValue();
39
+ }
40
+
41
+ componentDidUpdate(prevProps) {
42
+ const { value } = this.props;
43
+ if (prevProps.value !== value) this.updateValue();
44
+ }
45
+
46
+ changeText = updateFunction => {
47
+ const { areaCode, phoneNumber } = this.state;
48
+ const { withAreaCode } = this.props;
49
+
50
+ if (withAreaCode && (areaCode || phoneNumber)) {
51
+ updateFunction(`${areaCode}-${phoneNumber}`);
52
+ } else if (!withAreaCode) {
53
+ updateFunction(phoneNumber);
54
+ } else {
55
+ updateFunction('');
56
+ }
57
+ };
58
+
59
+ getAreaCodeState = value => {
60
+ const {
61
+ translations: { areaCodeWithoutZeroError, invalidAreaCodeError }
62
+ } = this.props;
63
+ let newState = {};
64
+ if (value && value.slice(0, 1) === '0') {
65
+ newState = { areaCodeError: areaCodeWithoutZeroError };
66
+ } else {
67
+ const code = AREA_CODES.find(element => element.code === value);
68
+ newState = {
69
+ areaCodeError: value?.length && !code && invalidAreaCodeError,
70
+ isValidCode: !!code,
71
+ phoneNumber: ''
72
+ };
73
+ }
74
+
75
+ return { ...newState, areaCode: value };
76
+ };
77
+
78
+ handleBlur = keyname => async () => {
79
+ this.setState({
80
+ [keyname]: false
81
+ });
82
+
83
+ await new Promise(resolve => setTimeout(resolve, 150));
84
+
85
+ const { secondFocus, firstFocus, bigFocus } = this.state;
86
+ const { onBlur } = this.props;
87
+
88
+ if (!secondFocus && !firstFocus && bigFocus) {
89
+ this.changeText(onBlur);
90
+ this.setState({
91
+ bigFocus: false
92
+ });
93
+ }
94
+ };
95
+
96
+ handleChangeAreaCode = value => {
97
+ this.setState(this.getAreaCodeState(value), () => {
98
+ const { onChange } = this.props;
99
+ this.changeText(onChange);
100
+ });
101
+ };
102
+
103
+ handleChangePhone = value => {
104
+ this.setState({ phoneNumber: value }, () => {
105
+ const { onChange } = this.props;
106
+ this.changeText(onChange);
107
+ });
108
+ };
109
+
110
+ handleFocus = keyname => () => {
111
+ const { onFocus } = this.props;
112
+ const { bigFocus } = this.state;
113
+
114
+ if (!bigFocus) {
115
+ onFocus();
116
+ }
117
+
118
+ this.setState({
119
+ [keyname]: true,
120
+ bigFocus: true
121
+ });
122
+ };
123
+
124
+ handleSubmitEditing = () => {
125
+ const { phoneRef, areaCodeError } = this.state;
126
+ if (!areaCodeError) {
127
+ phoneRef.focus();
128
+ }
129
+ };
130
+
131
+ phoneInputRef = ref => this.setState({ phoneRef: ref });
132
+
133
+ updateValue = () => {
134
+ const { value, withAreaCode } = this.props;
135
+ if (value) {
136
+ if (withAreaCode) {
137
+ const phone = value.split('-');
138
+ if (phone.length === 2) {
139
+ const newAreaCodeState = this.getAreaCodeState(phone[0]);
140
+ this.setState({
141
+ ...newAreaCodeState,
142
+ phoneNumber: phone[1]
143
+ });
144
+ }
145
+ } else {
146
+ this.setState({ phoneNumber: value });
147
+ }
148
+ } else {
149
+ this.setState({
150
+ areaCode: '',
151
+ phoneNumber: '',
152
+ areaCodeError: '',
153
+ isValidCode: false
154
+ });
155
+ }
156
+ };
157
+
158
+ render() {
159
+ const {
160
+ areaCodePlaceholder,
161
+ countryCode,
162
+ editable,
163
+ formError,
164
+ helpText,
165
+ InputRef,
166
+ label,
167
+ labelVariant,
168
+ maxLength,
169
+ onSubmitEditing,
170
+ placeholder,
171
+ readOnly,
172
+ required,
173
+ RightIcon,
174
+ validations,
175
+ withAreaCode
176
+ } = this.props;
177
+ const { areaCode, areaCodeError, isValidCode, phoneNumber } = this.state;
178
+
179
+ const labelColorTheme = readOnly ? 'gray' : 'dark';
180
+
181
+ const validationErrors =
182
+ validations ||
183
+ (areaCodeError && formatErrorToValidation(areaCodeError)) ||
184
+ (formError && formatErrorToValidation(formError));
185
+
186
+ const hasError = validationErrors?.length > 0;
187
+
188
+ return (
189
+ <View style={styles.container}>
190
+ {label && (
191
+ <UTFieldLabel
192
+ colorTheme={labelColorTheme}
193
+ required={required}
194
+ variant={LABEL_VARIANTS[labelVariant]}
195
+ >
196
+ {label}
197
+ </UTFieldLabel>
198
+ )}
199
+ <View style={styles.inputsContainer}>
200
+ {withAreaCode ? (
201
+ <UTBaseInputField
202
+ alwaysShowPlaceholder
203
+ disabled={!editable || readOnly}
204
+ error={hasError}
205
+ leftAdornments={[]}
206
+ maxLength={4}
207
+ onBlur={this.handleFirstBlur}
208
+ onChange={this.handleChangeAreaCode}
209
+ onFocus={this.handleFirstFocus}
210
+ onSubmitEditing={this.handleSubmitEditing}
211
+ placeholder={areaCodePlaceholder}
212
+ ref={InputRef}
213
+ returnKeyType="next"
214
+ rightAdornments={[
215
+ { name: COMPONENT_KEYS.ICON, props: { Icon: RightIcon, changeOnError: true } }
216
+ ]}
217
+ style={{ container: styles.areaCode }}
218
+ type="number"
219
+ value={areaCode}
220
+ />
221
+ ) : null}
222
+ <View style={styles.phoneNumber}>
223
+ <UTBaseInputField
224
+ alwaysShowPlaceholder
225
+ disabled={(withAreaCode && !isValidCode) || !editable || readOnly}
226
+ error={hasError && !areaCodeError}
227
+ leftAdornments={
228
+ countryCode && !withAreaCode
229
+ ? [{ name: COMPONENT_KEYS.PREFIX, props: { text: countryCode } }]
230
+ : []
231
+ }
232
+ maxLength={withAreaCode ? maxLength - (areaCode?.length || 0) : maxLength}
233
+ onBlur={this.handleSecondBlur}
234
+ onChange={this.handleChangePhone}
235
+ onFocus={this.handleSecondFocus}
236
+ onSubmitEditing={onSubmitEditing}
237
+ placeholder={placeholder}
238
+ ref={this.phoneInputRef}
239
+ returnKeyType="done"
240
+ rightAdornments={[
241
+ { name: COMPONENT_KEYS.ICON, props: { Icon: RightIcon, changeOnError: true } }
242
+ ]}
243
+ type="number"
244
+ value={phoneNumber}
245
+ />
246
+ </View>
247
+ </View>
248
+ {helpText && (
249
+ <UTLabel colorTheme="gray" variant="small">
250
+ {helpText}
251
+ </UTLabel>
252
+ )}
253
+ {validationErrors && <UTValidation validationData={validationErrors} />}
254
+ </View>
255
+ );
256
+ }
257
+ }
258
+
259
+ UTPhoneInput.defaultProps = {
260
+ labelVariant: 'large',
261
+ maxLength: 10,
262
+ translations: {
263
+ areaCodeWithoutZeroError: 'Ingrese el código sin 0',
264
+ invalidAreaCodeError: 'Código de área inválido'
265
+ },
266
+ withAreaCode: true
267
+ };
268
+
269
+ UTPhoneInput.propTypes = {
270
+ areaCodePlaceholder: string,
271
+ countryCode: string,
272
+ editable: bool,
273
+ formError: string,
274
+ helpText: string,
275
+ InputRef: func,
276
+ label: string,
277
+ labelVariant: string,
278
+ maxLength: number,
279
+ onBlur: func,
280
+ onChange: func,
281
+ onFocus: func,
282
+ onSubmitEditing: func,
283
+ placeholder: string,
284
+ readOnly: bool,
285
+ required: bool,
286
+ RightIcon: elementType,
287
+ translations: shape({
288
+ areaCodeWithoutZeroError: string,
289
+ invalidAreaCodeError: string
290
+ }),
291
+ validations: validationDataProptypes,
292
+ value: string,
293
+ withAreaCode: bool
294
+ };
295
+
296
+ export default UTPhoneInput;
@@ -0,0 +1,18 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ areaCode: {
5
+ flex: 1
6
+ },
7
+ container: {
8
+ gap: 12
9
+ },
10
+ inputsContainer: {
11
+ alignItems: 'flex-start',
12
+ flexDirection: 'row',
13
+ gap: 8
14
+ },
15
+ phoneNumber: {
16
+ flex: 2
17
+ }
18
+ });
@@ -0,0 +1,42 @@
1
+ # UTSearchField
2
+
3
+ ## Description
4
+
5
+ `UTSearchField` is a customizable search field component that includes a search icon on the left and an optional clear button on the right.
6
+
7
+ ## Props
8
+
9
+ | Name | Type | Default | Description |
10
+ | --------------- | -------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------ |
11
+ | inputRef | func | | Reference to the input field. |
12
+ | input | shape({ value: string.isRequired, onChange: func.isRequired }) | { value: '', onChange: () => {} } | Input object containing the value and onChange handler. |
13
+ | onBlur | func | | Function to call when the input field loses focus. |
14
+ | onFocus | func | | Function to call when the input field gains focus. |
15
+ | onSubmitEditing | func | | Function to call when the input field is submitted. |
16
+ | placeholder | string | | Placeholder text for the input field. |
17
+ | returnKeyType | string | | Determines the return key type on the keyboard. |
18
+ | size | string | medium | Size of the input field. One of: `small`, `medium`, `large`. |
19
+ | style | object | | Style object to customize the input field. |
20
+ | type | string | | Type of input (e.g., 'text', 'password', 'email'). |
21
+ | variant | string | white | Variant of the input field. One of: `white`, `gray`. |
22
+
23
+ ## Example
24
+
25
+ ```jsx
26
+ import React, { useState } from 'react';
27
+ import { View, Text } from 'react-native';
28
+ import UTSearchField from './UTSearchField';
29
+
30
+ const UTSearchFieldExample = () => {
31
+ const [searchValue, setSearchValue] = useState('');
32
+
33
+ return (
34
+ <View style={{ padding: 20 }}>
35
+ <UTSearchField placeholder="Search..." value={searchValue} onChange={setSearchValue} />
36
+ <Text>Search Value: {searchValue}</Text>
37
+ </View>
38
+ );
39
+ };
40
+
41
+ export default UTSearchFieldExample;
42
+ ```
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+
3
+ import { COMPONENT_KEYS } from '../UTBaseInputField/constants';
4
+ import UTBaseInputField from '../UTBaseInputField';
5
+
6
+ import { defaultProps, propTypes } from './proptypes';
7
+
8
+ const UTSearchField = ({
9
+ disabled,
10
+ input,
11
+ inputRef,
12
+ onBlur,
13
+ onFocus,
14
+ onSubmitEditing,
15
+ placeholder,
16
+ returnKeyType,
17
+ size,
18
+ style,
19
+ type,
20
+ variant
21
+ }) => {
22
+ const clearText = () => {
23
+ input.onChange('');
24
+ };
25
+
26
+ const action = { Icon: 'IconX', onPress: clearText, size: 'small' };
27
+
28
+ const leftAdornments = [
29
+ { name: COMPONENT_KEYS.ICON, props: { Icon: 'IconSearch', changeOnFocus: true, shade: '02' } }
30
+ ];
31
+
32
+ const rightAdornments = input.value ? [{ name: COMPONENT_KEYS.ACTION, props: { action } }] : [];
33
+
34
+ return (
35
+ <UTBaseInputField
36
+ alwaysShowPlaceholder
37
+ disabled={disabled}
38
+ input={input}
39
+ inputSize={size}
40
+ leftAdornments={leftAdornments}
41
+ onBlur={onBlur}
42
+ onFocus={onFocus}
43
+ onSubmitEditing={onSubmitEditing}
44
+ placeholder={placeholder}
45
+ ref={inputRef}
46
+ returnKeyType={returnKeyType}
47
+ rightAdornments={rightAdornments}
48
+ style={{ container: style }}
49
+ type={type}
50
+ variant={variant}
51
+ />
52
+ );
53
+ };
54
+
55
+ UTSearchField.defaultProps = defaultProps;
56
+
57
+ UTSearchField.propTypes = propTypes;
58
+
59
+ export default UTSearchField;
@@ -0,0 +1,28 @@
1
+ import { func, oneOf, string, object, shape, instanceOf, oneOfType } from 'prop-types';
2
+
3
+ import { SIZES, VARIANT } from '../UTBaseInputField/constants';
4
+
5
+ export const defaultProps = {
6
+ input: {
7
+ value: [],
8
+ onChange: () => {}
9
+ },
10
+ variant: VARIANT.WHITE
11
+ };
12
+
13
+ export const propTypes = {
14
+ input: shape({
15
+ value: string,
16
+ onChange: func
17
+ }),
18
+ inputRef: oneOfType([func, instanceOf(Object)]),
19
+ onBlur: func,
20
+ onFocus: func,
21
+ onSubmitEditing: func,
22
+ placeholder: string,
23
+ returnKeyType: string,
24
+ size: oneOf(Object.values(SIZES)),
25
+ style: object,
26
+ type: string,
27
+ variant: oneOf(Object.values(VARIANT))
28
+ };
@@ -1,103 +1,16 @@
1
- import React, { useState, useMemo } from 'react';
2
- import { isEmpty } from '@widergy/web-utils/lib/array';
3
- import { View } from 'react-native';
1
+ import React from 'react';
2
+ import { string } from 'prop-types';
4
3
 
5
- import Label from '../Label';
6
- import UTMenu from '../UTMenu';
7
- import UTTextInput from '../UTTextInput';
4
+ import V0 from './versions/V0';
5
+ import V1 from './versions/V1';
8
6
 
9
- import MultipleItem from './componentes/MultipleItem';
10
- import styles from './styles';
11
- import UTSelectTypes from './proptypes';
12
-
13
- const UTSelect = ({
14
- options = [],
15
- value,
16
- onChange,
17
- error,
18
- UTMenuProps,
19
- label,
20
- styles: propStyles,
21
- variant,
22
- disabled,
23
- UTTextInputProps,
24
- isMultiple,
25
- verticalOffset = 5,
26
- title,
27
- titleProps,
28
- changeOnClose
29
- }) => {
30
- const [focused, setFocused] = useState(false);
31
-
32
- const selectedOption = useMemo(
33
- () => (!isMultiple ? options.find(option => option.value === value) : value || []),
34
- [isMultiple, options, value]
35
- );
36
-
37
- const handleChange = option => {
38
- if (!changeOnClose) onChange(option.value);
39
- };
40
-
41
- const handleChangeMultiple = newValue => {
42
- const newValues = !selectedOption?.find?.(elem => elem === newValue.value)
43
- ? [...(selectedOption || []), newValue.value]
44
- : selectedOption?.filter(elem => elem !== newValue.value);
45
-
46
- const finalValue = isEmpty(newValues) ? null : newValues;
47
- if (!changeOnClose) {
48
- onChange(finalValue);
49
- }
50
- };
51
-
52
- const handleOpen = () => setFocused(true);
53
- // eslint-disable-next-line consistent-return
54
- const handleClose = () => {
55
- setFocused(false);
56
- if (changeOnClose) {
57
- return isMultiple
58
- ? onChange(selectedOption)
59
- : onChange(options.find(_option => _option.id === selectedOption.id).value);
60
- }
61
- };
62
-
63
- return (
64
- <View style={[styles.container, propStyles]}>
65
- {title && (
66
- <Label medium primary {...titleProps}>
67
- {title}
68
- </Label>
69
- )}
70
- <UTMenu
71
- options={options}
72
- selectedOption={isMultiple ? selectedOption : selectedOption?.id}
73
- fullWidth
74
- verticalOffset={verticalOffset}
75
- disabled={disabled}
76
- onPress={isMultiple ? handleChangeMultiple : handleChange}
77
- onOpen={handleOpen}
78
- onClose={handleClose}
79
- withoutOpacity
80
- MenuOptionComponent={isMultiple && MultipleItem}
81
- isMultiple={isMultiple}
82
- {...UTMenuProps}
83
- >
84
- <UTTextInput
85
- variant={variant}
86
- value={isMultiple ? value?.join(', ') || '' : selectedOption?.label || selectedOption?.value || ''}
87
- error={error}
88
- label={label}
89
- select
90
- controlledFocus={focused}
91
- disabled={disabled}
92
- version="V0"
93
- RightIcon={{ type: 'font-awesome', name: 'caret-down' }}
94
- {...UTTextInputProps}
95
- />
96
- </UTMenu>
97
- </View>
98
- );
7
+ const UTSelect = ({ version = 'V0', ...props }) => {
8
+ const Component = { V0, V1 }[version];
9
+ return <Component {...props} />;
99
10
  };
100
11
 
101
- UTSelect.propTypes = UTSelectTypes;
12
+ UTSelect.propTypes = {
13
+ version: string
14
+ };
102
15
 
103
16
  export default UTSelect;
@@ -2,7 +2,7 @@
2
2
  import { any, bool, func, shape, string } from 'prop-types';
3
3
  import React, { memo } from 'react';
4
4
 
5
- import Checkbox from '../../../Checkbox';
5
+ import Checkbox from '../../../../../Checkbox';
6
6
 
7
7
  import styles from './styles';
8
8
 
@@ -0,0 +1,103 @@
1
+ import React, { useState, useMemo } from 'react';
2
+ import { isEmpty } from '@widergy/web-utils/lib/array';
3
+ import { View } from 'react-native';
4
+
5
+ import Label from '../../../Label';
6
+ import UTMenu from '../../../UTMenu';
7
+ import UTTextInput from '../../../UTTextInput';
8
+
9
+ import MultipleItem from './componentes/MultipleItem';
10
+ import styles from './styles';
11
+ import UTSelectTypes from './proptypes';
12
+
13
+ const UTSelect = ({
14
+ options = [],
15
+ value,
16
+ onChange,
17
+ error,
18
+ UTMenuProps,
19
+ label,
20
+ styles: propStyles,
21
+ variant,
22
+ disabled,
23
+ UTTextInputProps,
24
+ isMultiple,
25
+ verticalOffset = 5,
26
+ title,
27
+ titleProps,
28
+ changeOnClose
29
+ }) => {
30
+ const [focused, setFocused] = useState(false);
31
+
32
+ const selectedOption = useMemo(
33
+ () => (!isMultiple ? options.find(option => option.value === value) : value || []),
34
+ [isMultiple, options, value]
35
+ );
36
+
37
+ const handleChange = option => {
38
+ if (!changeOnClose) onChange(option.value);
39
+ };
40
+
41
+ const handleChangeMultiple = newValue => {
42
+ const newValues = !selectedOption?.find?.(elem => elem === newValue.value)
43
+ ? [...(selectedOption || []), newValue.value]
44
+ : selectedOption?.filter(elem => elem !== newValue.value);
45
+
46
+ const finalValue = isEmpty(newValues) ? null : newValues;
47
+ if (!changeOnClose) {
48
+ onChange(finalValue);
49
+ }
50
+ };
51
+
52
+ const handleOpen = () => setFocused(true);
53
+ // eslint-disable-next-line consistent-return
54
+ const handleClose = () => {
55
+ setFocused(false);
56
+ if (changeOnClose) {
57
+ return isMultiple
58
+ ? onChange(selectedOption)
59
+ : onChange(options.find(_option => _option.id === selectedOption.id).value);
60
+ }
61
+ };
62
+
63
+ return (
64
+ <View style={[styles.container, propStyles]}>
65
+ {title && (
66
+ <Label medium primary {...titleProps}>
67
+ {title}
68
+ </Label>
69
+ )}
70
+ <UTMenu
71
+ options={options}
72
+ selectedOption={isMultiple ? selectedOption : selectedOption?.id}
73
+ fullWidth
74
+ verticalOffset={verticalOffset}
75
+ disabled={disabled}
76
+ onPress={isMultiple ? handleChangeMultiple : handleChange}
77
+ onOpen={handleOpen}
78
+ onClose={handleClose}
79
+ withoutOpacity
80
+ MenuOptionComponent={isMultiple && MultipleItem}
81
+ isMultiple={isMultiple}
82
+ {...UTMenuProps}
83
+ >
84
+ <UTTextInput
85
+ variant={variant}
86
+ value={isMultiple ? value?.join(', ') || '' : selectedOption?.label || selectedOption?.value || ''}
87
+ error={error}
88
+ label={label}
89
+ select
90
+ controlledFocus={focused}
91
+ disabled={disabled}
92
+ version="V0"
93
+ RightIcon={{ type: 'font-awesome', name: 'caret-down' }}
94
+ {...UTTextInputProps}
95
+ />
96
+ </UTMenu>
97
+ </View>
98
+ );
99
+ };
100
+
101
+ UTSelect.propTypes = UTSelectTypes;
102
+
103
+ export default UTSelect;