@widergy/mobile-ui 1.31.2 → 1.31.3

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [1.31.3](https://github.com/widergy/mobile-ui/compare/v1.31.2...v1.31.3) (2024-11-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * [EVE-4328] UTRating ([#384](https://github.com/widergy/mobile-ui/issues/384)) ([6485384](https://github.com/widergy/mobile-ui/commit/6485384e2fed5cef0c2c68b88b1cbf8e45d4f3c7))
7
+
1
8
  ## [1.31.2](https://github.com/widergy/mobile-ui/compare/v1.31.1...v1.31.2) (2024-11-05)
2
9
 
3
10
 
@@ -0,0 +1,44 @@
1
+ # UTRating
2
+
3
+ ## Description
4
+
5
+ `UTRating` is a configurable rating input component that enables users to easily provide feedback through visual indicators.
6
+
7
+ ## Props
8
+
9
+ | Name | Type | Default | Description |
10
+ | ------------------- | --------- | ------- | -------------------------------------------------------------------------------------------------------- |
11
+ | classNames | object | | Custom CSS class names for styling the component. |
12
+ | dataTestId | string | | Unique identifier for testing purposes. |
13
+ | disabled | bool | | Indicates whether the input is disabled and cannot be interacted with. |
14
+ | error | string | | Error message to display when validation fails or an issue occurs. |
15
+ | helpTextEnd | string | | Additional help text displayed at the end of the input for user guidance. |
16
+ | helpTextStart | string | | Additional help text displayed at the beginning of the input for user guidance. |
17
+ | onChange | func | | Callback function invoked when the input value changes. |
18
+ | options | array | | Array of options available for selection. |
19
+ | required | bool | | Indicates whether the input is mandatory for form submission. |
20
+ | title | string | | Title for the input, providing context to the user. |
21
+ | validations | array | | Array of validation rules to be applied to the input value. |
22
+ | value | string | | The current value of the input. |
23
+ | variant | string | `star` | Defines the visual style component. |
24
+
25
+
26
+ ### options
27
+
28
+ `options` is an array of objects with a `value` and a `name` key. The values should be in the range of 0-10, except for the `faces` variant. In desktop view, all options are displayed in one row; in responsive view, they are broken into 2 rows if there are more than 5 options.
29
+
30
+ ### variant
31
+
32
+ The value of `variant` must be one of the following:
33
+
34
+ - `faces`: the options are represented as face icons. Option values should exclusively be between 1 and 5, values outside this range are not supported.
35
+ - `star`: the options are represented as star icons.
36
+ - `text`: the options are represented as the option's `text`.
37
+
38
+ ### Structure of Validations
39
+
40
+ For detailed information about the structure of validations, please refer to the UTValidation component documentation.
41
+
42
+ ### Handling Errors
43
+
44
+ Errors can be displayed below the text input using either the `error` prop or the `validations` prop.
@@ -0,0 +1,32 @@
1
+ import { bool, func, object, string } from 'prop-types';
2
+ import React from 'react';
3
+
4
+ import { RATING_VARIANTS } from '../../constants';
5
+ import UTButton from '../../../UTButton';
6
+
7
+ import { getIcon, getVariant } from './utils';
8
+
9
+ const Option = ({ disabled, isSelected, name, onChange, value, variant, wrapperStyle }) => (
10
+ <UTButton
11
+ colorTheme={isSelected ? 'primary' : 'secondary'}
12
+ disabled={disabled}
13
+ Icon={getIcon(variant, value, isSelected)}
14
+ onPress={() => onChange(value)}
15
+ style={{ root: wrapperStyle }}
16
+ variant={getVariant(variant, isSelected)}
17
+ >
18
+ {RATING_VARIANTS.TEXT === variant ? name : null}
19
+ </UTButton>
20
+ );
21
+
22
+ Option.propTypes = {
23
+ disabled: bool,
24
+ isSelected: bool,
25
+ name: string,
26
+ onChange: func,
27
+ value: string,
28
+ variant: string,
29
+ wrapperStyle: object
30
+ };
31
+
32
+ export default Option;
@@ -0,0 +1,17 @@
1
+ import { RATING_VARIANTS } from '../../constants';
2
+
3
+ export const getIcon = (variant, value, isSelected) =>
4
+ ({
5
+ [RATING_VARIANTS.TEXT]: null,
6
+ [RATING_VARIANTS.FACES]: {
7
+ 1: 'IconMoodSad',
8
+ 2: 'IconMoodConfuzed',
9
+ 3: 'IconMoodEmpty',
10
+ 4: 'IconMoodSmile',
11
+ 5: 'IconMoodHappy'
12
+ }[value],
13
+ [RATING_VARIANTS.STAR]: isSelected ? 'IconStarFilled' : 'IconStar'
14
+ })[variant];
15
+
16
+ export const getVariant = (variant, isSelected) =>
17
+ !isSelected || variant === RATING_VARIANTS.STAR ? 'shadow' : 'outlined';
@@ -0,0 +1,5 @@
1
+ export const RATING_VARIANTS = {
2
+ FACES: 'faces',
3
+ STAR: 'star',
4
+ TEXT: 'text'
5
+ };
@@ -0,0 +1,101 @@
1
+ import { func, string, bool, object, array } from 'prop-types';
2
+ import { View } from 'react-native';
3
+ import React, { useCallback, useMemo, useState } from 'react';
4
+
5
+ import { formatErrorToValidation } from '../UTValidation/utils';
6
+ import { withTheme } from '../../theming';
7
+ import UTFieldLabel from '../UTFieldLabel';
8
+ import UTLabel from '../UTLabel';
9
+ import UTValidation from '../UTValidation';
10
+
11
+ import { RATING_VARIANTS } from './constants';
12
+ import Option from './components/Option';
13
+ import styles from './styles';
14
+
15
+ const UTRating = ({
16
+ classNames = {},
17
+ dataTestId,
18
+ disabled,
19
+ error,
20
+ helpTextEnd,
21
+ helpTextStart,
22
+ onChange,
23
+ options = [],
24
+ required,
25
+ theme,
26
+ title,
27
+ validations,
28
+ value,
29
+ variant = RATING_VARIANTS.STAR
30
+ }) => {
31
+ const validationData = useMemo(
32
+ () => validations || (error && formatErrorToValidation(error)),
33
+ [error, validations]
34
+ );
35
+
36
+ const valueIndex = options.map(({ value: optionValue }) => optionValue).indexOf(value);
37
+ const isSelected = index =>
38
+ valueIndex !== -1 && variant === RATING_VARIANTS.STAR ? index <= valueIndex : index === valueIndex;
39
+
40
+ const [containerWidth, setContainerWidth] = useState(0);
41
+
42
+ const onLayout = useCallback(event => {
43
+ const { width } = event.nativeEvent.layout;
44
+ setContainerWidth(width);
45
+ }, []);
46
+
47
+ return (
48
+ <View style={[styles.container, classNames.container]} data-testid={dataTestId}>
49
+ {title && (
50
+ <UTFieldLabel colorTheme="dark" required={required}>
51
+ {title}
52
+ </UTFieldLabel>
53
+ )}
54
+ <View style={styles.optionsContainer} onLayout={onLayout}>
55
+ {options.map((option, index) => (
56
+ <Option
57
+ {...option}
58
+ disabled={disabled}
59
+ error={error}
60
+ isSelected={isSelected(index)}
61
+ key={option.value}
62
+ onChange={onChange}
63
+ variant={variant}
64
+ wrapperStyle={styles.option(containerWidth, error, options, theme)}
65
+ />
66
+ ))}
67
+ </View>
68
+ {helpTextStart && (
69
+ <View style={styles.helpTextContainer}>
70
+ <UTLabel colorTheme="gray" variant="small">
71
+ {helpTextStart}
72
+ </UTLabel>
73
+ {helpTextEnd && (
74
+ <UTLabel colorTheme="gray" variant="small">
75
+ {helpTextEnd}
76
+ </UTLabel>
77
+ )}
78
+ </View>
79
+ )}
80
+ {validationData && <UTValidation validationData={validationData} />}
81
+ </View>
82
+ );
83
+ };
84
+
85
+ UTRating.propTypes = {
86
+ classNames: object,
87
+ dataTestId: string,
88
+ disabled: bool,
89
+ error: string,
90
+ helpTextEnd: string,
91
+ helpTextStart: string,
92
+ onChange: func,
93
+ options: array,
94
+ required: bool,
95
+ title: string,
96
+ validations: array,
97
+ value: string,
98
+ variant: string
99
+ };
100
+
101
+ export default withTheme(UTRating);
@@ -0,0 +1,38 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ container: {
5
+ display: 'flex',
6
+ flexDirection: 'column',
7
+ gap: 8,
8
+ width: '100%'
9
+ },
10
+ optionsContainer: {
11
+ display: 'flex',
12
+ flexDirection: 'row',
13
+ flexWrap: 'wrap',
14
+ gap: 4,
15
+ justifyContent: 'center',
16
+ width: '100%'
17
+ },
18
+ helpTextContainer: {
19
+ display: 'flex',
20
+ flexDirection: 'row',
21
+ justifyContent: 'space-between'
22
+ },
23
+ option: (containerWidth, error, options, theme) => {
24
+ const topItems = Math.ceil(options.length / 2);
25
+ const breakOptions = options.length > 5;
26
+ return {
27
+ alignContent: 'center',
28
+ display: 'flex',
29
+ flexBasis: breakOptions ? (containerWidth - (topItems - 1) * 4) / topItems : 0,
30
+ flexDirection: 'row',
31
+ flexGrow: breakOptions ? 0 : 1,
32
+ flexShrink: 0,
33
+ height: 48,
34
+ justifyContent: 'center',
35
+ ...(error ? { borderColor: theme.Palette.error['05'], borderWidth: 2 } : {})
36
+ };
37
+ }
38
+ });
package/lib/index.js CHANGED
@@ -57,6 +57,7 @@ export { default as UTPasswordField } from './components/UTPasswordField';
57
57
  export { default as UTPhoneInput } from './components/UTPhoneInput';
58
58
  export { default as UTProductItem } from './components/UTProductItem';
59
59
  export { default as UTProgressBar } from './components/UTProgressBar';
60
+ export { default as UTRating } from './components/UTRating';
60
61
  export { default as UTRoundView } from './components/UTRoundView';
61
62
  export { default as UTSearchField } from './components/UTSearchField';
62
63
  export { default as UTSelect } from './components/UTSelect';
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": "1.31.2",
5
+ "version": "1.31.3",
6
6
  "repository": "https://github.com/widergy/mobile-ui.git",
7
7
  "main": "lib/index.js",
8
8
  "files": [