@widergy/mobile-ui 1.46.1 → 1.48.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.
- package/CHANGELOG.md +14 -0
- package/lib/components/CaptionLabel/README.md +30 -8
- package/lib/components/CaptionLabel/index.js +2 -1
- package/lib/components/CaptionLabel/propTypes.js +1 -0
- package/lib/components/Checkbox/README.md +93 -25
- package/lib/components/Checkbox/index.js +14 -1
- package/lib/components/Checkbox/propTypes.js +1 -0
- package/lib/components/Label/index.js +2 -1
- package/lib/components/Label/propTypes.js +1 -0
- package/lib/components/RadioGroup/components/RadioButton/index.js +29 -18
- package/lib/components/RadioGroup/index.js +19 -5
- package/lib/components/Touchable/index.js +3 -1
- package/lib/components/Touchable/propTypes.js +1 -0
- package/lib/components/UTBadge/index.js +3 -1
- package/lib/components/UTBaseInputField/README.md +41 -19
- package/lib/components/UTBaseInputField/components/ActionAdornment/index.js +10 -3
- package/lib/components/UTBaseInputField/components/BadgeAdornment/index.js +6 -1
- package/lib/components/UTBaseInputField/components/IconAdornment/index.js +8 -1
- package/lib/components/UTBaseInputField/components/PrefixAdornment/index.js +8 -2
- package/lib/components/UTBaseInputField/components/SuffixAdornment/index.js +6 -1
- package/lib/components/UTBaseInputField/components/TooltipAdornment/index.js +16 -3
- package/lib/components/UTBaseInputField/index.js +15 -4
- package/lib/components/UTBottomSheet/README.md +94 -23
- package/lib/components/UTBottomSheet/index.js +27 -4
- package/lib/components/UTButton/index.js +18 -4
- package/lib/components/UTButton/proptypes.js +1 -0
- package/lib/components/UTCheckBox/README.md +47 -0
- package/lib/components/UTCheckBox/index.js +24 -3
- package/lib/components/UTCheckBox/proptypes.js +1 -0
- package/lib/components/UTCheckList/README.MD +63 -0
- package/lib/components/UTCheckList/index.js +25 -2
- package/lib/components/UTCheckList/proptypes.js +1 -0
- package/lib/components/UTDetailDrawer/README.md +60 -10
- package/lib/components/UTDetailDrawer/index.js +11 -1
- package/lib/components/UTDetailDrawer/propTypes.js +1 -0
- package/lib/components/UTFieldLabel/README.md +99 -0
- package/lib/components/UTFieldLabel/index.js +19 -2
- package/lib/components/UTIcon/README.md +25 -2
- package/lib/components/UTIcon/index.js +3 -1
- package/lib/components/UTLabel/README.md +26 -0
- package/lib/components/UTLabel/index.js +2 -0
- package/lib/components/UTLabel/proptypes.js +1 -0
- package/lib/components/UTMenu/README.md +275 -0
- package/lib/components/UTMenu/components/ListView/index.js +5 -3
- package/lib/components/UTMenu/components/ListView/proptypes.js +2 -1
- package/lib/components/UTMenu/components/MenuOption/index.js +5 -3
- package/lib/components/UTMenu/index.js +18 -3
- package/lib/components/UTMenu/proptypes.js +2 -1
- package/lib/components/UTModal/README.md +193 -0
- package/lib/components/UTModal/index.js +22 -2
- package/lib/components/UTModal/proptypes.js +1 -0
- package/lib/components/UTPhoneInput/index.js +25 -2
- package/lib/components/UTRoundView/README.md +158 -0
- package/lib/components/UTRoundView/index.js +12 -1
- package/lib/components/UTRoundView/propTypes.js +4 -2
- package/lib/components/UTSearchField/README.md +64 -14
- package/lib/components/UTSearchField/index.js +3 -1
- package/lib/components/UTSearchField/proptypes.js +2 -1
- package/lib/components/UTSelect/versions/V0/README.md +216 -0
- package/lib/components/UTSelect/versions/V0/componentes/MultipleItem/index.js +4 -2
- package/lib/components/UTSelect/versions/V0/index.js +5 -2
- package/lib/components/UTSelect/versions/V0/proptypes.js +2 -1
- package/lib/components/UTSelect/versions/V1/README.md +94 -0
- package/lib/components/UTSelect/versions/V1/index.js +28 -6
- package/lib/components/UTSelect/versions/V1/proptypes.js +1 -0
- package/lib/components/UTSelectableCard/README.md +85 -0
- package/lib/components/UTSelectableCard/index.js +52 -4
- package/lib/components/UTTabs/README.md +27 -11
- package/lib/components/UTTabs/index.js +139 -24
- package/lib/components/UTTabs/styles.js +104 -58
- package/lib/components/UTTextInput/versions/V0/components/BaseInput/index.js +5 -1
- package/lib/components/UTTextInput/versions/V0/components/InputLabel/index.js +4 -1
- package/lib/components/UTTextInput/versions/V0/flavors/FilledInput/index.js +9 -1
- package/lib/components/UTTextInput/versions/V0/flavors/OutlinedInput/index.js +9 -1
- package/lib/components/UTTextInput/versions/V0/flavors/StandardInput/index.js +9 -1
- package/lib/components/UTTextInput/versions/V1/components/TextInputField/index.js +3 -0
- package/lib/components/UTTextInput/versions/V1/index.js +20 -3
- package/lib/components/UTTooltip/README.md +99 -0
- package/lib/components/UTTooltip/index.js +2 -0
- package/lib/components/UTTooltip/proptypes.js +2 -1
- package/lib/components/UTValidation/index.js +26 -4
- package/lib/constants/testIds.js +44 -0
- package/package.json +1 -1
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { bool, object, shape } from 'prop-types';
|
|
2
|
+
import { bool, object, shape, string } from 'prop-types';
|
|
3
3
|
|
|
4
4
|
import UTButton from '../../../UTButton';
|
|
5
5
|
import { propTypes as utbuttonProptypes } from '../../../UTButton/proptypes';
|
|
6
6
|
|
|
7
|
-
const ActionAdornment = ({ action, disabled, actionStyle }) => {
|
|
7
|
+
const ActionAdornment = ({ action, dataTestId, disabled, actionStyle }) => {
|
|
8
8
|
if (!action) return null;
|
|
9
9
|
|
|
10
10
|
return (
|
|
11
|
-
<UTButton
|
|
11
|
+
<UTButton
|
|
12
|
+
dataTestId={dataTestId ? `${dataTestId}.actionAdornment` : undefined}
|
|
13
|
+
disabled={disabled}
|
|
14
|
+
style={actionStyle}
|
|
15
|
+
variant="text"
|
|
16
|
+
{...action}
|
|
17
|
+
>
|
|
12
18
|
{action.text}
|
|
13
19
|
</UTButton>
|
|
14
20
|
);
|
|
@@ -21,6 +27,7 @@ ActionAdornment.propTypes = {
|
|
|
21
27
|
icon: object,
|
|
22
28
|
root: object
|
|
23
29
|
}),
|
|
30
|
+
dataTestId: string,
|
|
24
31
|
disabled: bool
|
|
25
32
|
};
|
|
26
33
|
|
|
@@ -3,10 +3,15 @@ import { number, oneOfType, string } from 'prop-types';
|
|
|
3
3
|
|
|
4
4
|
import UTBadge from '../../../UTBadge';
|
|
5
5
|
|
|
6
|
-
const BadgeAdornment = ({ text, colorTheme }) =>
|
|
6
|
+
const BadgeAdornment = ({ dataTestId, text, colorTheme }) => (
|
|
7
|
+
<UTBadge dataTestId={dataTestId ? `${dataTestId}.badgeAdornment` : undefined} colorTheme={colorTheme}>
|
|
8
|
+
{text}
|
|
9
|
+
</UTBadge>
|
|
10
|
+
);
|
|
7
11
|
|
|
8
12
|
BadgeAdornment.propTypes = {
|
|
9
13
|
colorTheme: string,
|
|
14
|
+
dataTestId: string,
|
|
10
15
|
text: oneOfType([string, number])
|
|
11
16
|
};
|
|
12
17
|
|
|
@@ -12,6 +12,7 @@ const IconAdornment = ({
|
|
|
12
12
|
changeOnError,
|
|
13
13
|
changeOnFocus,
|
|
14
14
|
colorTheme,
|
|
15
|
+
dataTestId,
|
|
15
16
|
error,
|
|
16
17
|
focused,
|
|
17
18
|
Icon,
|
|
@@ -23,12 +24,17 @@ const IconAdornment = ({
|
|
|
23
24
|
|
|
24
25
|
return isUTIcon(IconToRender) ? (
|
|
25
26
|
<UTIcon
|
|
27
|
+
dataTestId={dataTestId ? `${dataTestId}.iconAdornment` : undefined}
|
|
26
28
|
name={IconToRender}
|
|
27
29
|
size={ICON_SIZE}
|
|
28
30
|
{...getIconColorProps(changeOnError, changeOnFocus, colorTheme, error, focused, shade)}
|
|
29
31
|
/>
|
|
30
32
|
) : (
|
|
31
|
-
<Icon
|
|
33
|
+
<Icon
|
|
34
|
+
testID={dataTestId ? `${dataTestId}.iconAdornment` : undefined}
|
|
35
|
+
size={ICON_SIZE}
|
|
36
|
+
fill={inputStyle.root.color}
|
|
37
|
+
/>
|
|
32
38
|
);
|
|
33
39
|
};
|
|
34
40
|
|
|
@@ -36,6 +42,7 @@ IconAdornment.propTypes = {
|
|
|
36
42
|
changeOnError: bool,
|
|
37
43
|
changeOnFocus: bool,
|
|
38
44
|
colorTheme: string,
|
|
45
|
+
dataTestId: string,
|
|
39
46
|
error: oneOfType([bool, string]),
|
|
40
47
|
focused: bool,
|
|
41
48
|
Icon: elementType,
|
|
@@ -3,13 +3,19 @@ import { string } from 'prop-types';
|
|
|
3
3
|
|
|
4
4
|
import UTLabel from '../../../UTLabel';
|
|
5
5
|
|
|
6
|
-
const PrefixAdornment = ({ text }) => (
|
|
7
|
-
<UTLabel
|
|
6
|
+
const PrefixAdornment = ({ dataTestId, text }) => (
|
|
7
|
+
<UTLabel
|
|
8
|
+
dataTestId={dataTestId ? `${dataTestId}.prefixAdornment` : undefined}
|
|
9
|
+
colorTheme="gray"
|
|
10
|
+
variant="small"
|
|
11
|
+
weight="medium"
|
|
12
|
+
>
|
|
8
13
|
{text}
|
|
9
14
|
</UTLabel>
|
|
10
15
|
);
|
|
11
16
|
|
|
12
17
|
PrefixAdornment.propTypes = {
|
|
18
|
+
dataTestId: string,
|
|
13
19
|
text: string
|
|
14
20
|
};
|
|
15
21
|
|
|
@@ -3,9 +3,14 @@ import { string } from 'prop-types';
|
|
|
3
3
|
|
|
4
4
|
import UTLabel from '../../../UTLabel';
|
|
5
5
|
|
|
6
|
-
const SuffixAdornment = ({ text }) =>
|
|
6
|
+
const SuffixAdornment = ({ dataTestId, text }) => (
|
|
7
|
+
<UTLabel dataTestId={dataTestId ? `${dataTestId}.suffixAdornment` : undefined} colorTheme="gray">
|
|
8
|
+
{text}
|
|
9
|
+
</UTLabel>
|
|
10
|
+
);
|
|
7
11
|
|
|
8
12
|
SuffixAdornment.propTypes = {
|
|
13
|
+
dataTestId: string,
|
|
9
14
|
text: string
|
|
10
15
|
};
|
|
11
16
|
|
|
@@ -5,19 +5,32 @@ import UTTooltip from '../../../UTTooltip';
|
|
|
5
5
|
import UTIcon from '../../../UTIcon';
|
|
6
6
|
import UTLabel from '../../../UTLabel';
|
|
7
7
|
|
|
8
|
-
const TooltipAdornment = ({ tooltip, tooltipProps }) => {
|
|
8
|
+
const TooltipAdornment = ({ dataTestId, tooltip, tooltipProps }) => {
|
|
9
9
|
const { tooltip: tooltipStyles, arrowTouchable, labelProps } = tooltipProps || {};
|
|
10
10
|
return tooltip ? (
|
|
11
11
|
<UTTooltip
|
|
12
|
+
dataTestId={dataTestId ? `${dataTestId}.tooltipAdornment` : undefined}
|
|
12
13
|
styles={{ tooltip: tooltipStyles, arrow: arrowTouchable }}
|
|
13
|
-
content={
|
|
14
|
+
content={
|
|
15
|
+
<UTLabel
|
|
16
|
+
dataTestId={dataTestId ? `${dataTestId}.tooltipAdornment.content` : undefined}
|
|
17
|
+
{...labelProps}
|
|
18
|
+
>
|
|
19
|
+
{tooltip}
|
|
20
|
+
</UTLabel>
|
|
21
|
+
}
|
|
14
22
|
>
|
|
15
|
-
<UTIcon
|
|
23
|
+
<UTIcon
|
|
24
|
+
dataTestId={dataTestId ? `${dataTestId}.tooltipAdornment.icon` : undefined}
|
|
25
|
+
name="IconInfoCircle"
|
|
26
|
+
colorTheme="gray"
|
|
27
|
+
/>
|
|
16
28
|
</UTTooltip>
|
|
17
29
|
) : undefined;
|
|
18
30
|
};
|
|
19
31
|
|
|
20
32
|
TooltipAdornment.propTypes = {
|
|
33
|
+
dataTestId: string,
|
|
21
34
|
tooltip: string,
|
|
22
35
|
tooltipProps: shape({
|
|
23
36
|
tooltip: object,
|
|
@@ -14,11 +14,14 @@ import { arrayOf, bool, func, number, object, oneOfType, shape, string } from 'p
|
|
|
14
14
|
|
|
15
15
|
import { useTheme } from '../../theming';
|
|
16
16
|
import UTLabel from '../UTLabel';
|
|
17
|
+
import { TEST_ID_CONSTANTS } from '../../constants/testIds';
|
|
17
18
|
|
|
18
19
|
import { COMPONENTS_MAPPER, DEBOUNCE_CONFIG, DEBOUNCE_DELAY } from './constants';
|
|
19
20
|
import { getPropsByType } from './utils';
|
|
20
21
|
import { CONTAINER, LINE_HEIGHT, retrieveStyle } from './theme';
|
|
21
22
|
|
|
23
|
+
const { characterCount } = TEST_ID_CONSTANTS;
|
|
24
|
+
|
|
22
25
|
const UTBaseInputField = forwardRef(
|
|
23
26
|
(
|
|
24
27
|
{
|
|
@@ -26,6 +29,7 @@ const UTBaseInputField = forwardRef(
|
|
|
26
29
|
autoCapitalize: autoCapitalize_,
|
|
27
30
|
blurOnSubmit,
|
|
28
31
|
disabled,
|
|
32
|
+
dataTestId,
|
|
29
33
|
editable = true,
|
|
30
34
|
error,
|
|
31
35
|
id,
|
|
@@ -153,10 +157,11 @@ const UTBaseInputField = forwardRef(
|
|
|
153
157
|
}));
|
|
154
158
|
|
|
155
159
|
const renderElement = useCallback(
|
|
156
|
-
element => {
|
|
160
|
+
(element, adornmentSide) => {
|
|
157
161
|
const Component = COMPONENTS_MAPPER[element.name];
|
|
158
162
|
return Component ? (
|
|
159
163
|
<Component
|
|
164
|
+
dataTestId={dataTestId ? `${dataTestId}.${adornmentSide}` : undefined}
|
|
160
165
|
actionStyle={actionStyle}
|
|
161
166
|
disabled={disabled}
|
|
162
167
|
error={error}
|
|
@@ -179,11 +184,12 @@ const UTBaseInputField = forwardRef(
|
|
|
179
184
|
return (
|
|
180
185
|
<View style={[containerStyle, { minHeight }]}>
|
|
181
186
|
<View style={inputRowStyle}>
|
|
182
|
-
{leftAdornments.map(renderElement)}
|
|
187
|
+
{leftAdornments.map(element => renderElement(element, 'left'))}
|
|
183
188
|
<TextInput
|
|
184
189
|
autoCapitalize={autoCapitalize}
|
|
185
190
|
autoCorrect={false}
|
|
186
191
|
cursorColor={inputStyle.cursorColor}
|
|
192
|
+
testID={dataTestId}
|
|
187
193
|
defaultValue={value}
|
|
188
194
|
editable={!disabled && !readOnly && editable}
|
|
189
195
|
id={id ? `${id}` : undefined}
|
|
@@ -206,11 +212,15 @@ const UTBaseInputField = forwardRef(
|
|
|
206
212
|
style={inputStyle.root}
|
|
207
213
|
type={type}
|
|
208
214
|
/>
|
|
209
|
-
{rightAdornments.map(renderElement)}
|
|
215
|
+
{rightAdornments.map(element => renderElement(element, 'right'))}
|
|
210
216
|
</View>
|
|
211
217
|
{hasCharactersCount && (
|
|
212
218
|
<View style={textLengthRowStyle}>
|
|
213
|
-
<UTLabel
|
|
219
|
+
<UTLabel
|
|
220
|
+
dataTestId={dataTestId ? `${dataTestId}.${characterCount}` : undefined}
|
|
221
|
+
colorTheme="gray"
|
|
222
|
+
variant="small"
|
|
223
|
+
>
|
|
214
224
|
{value?.length || 0}/{maxLength}
|
|
215
225
|
</UTLabel>
|
|
216
226
|
</View>
|
|
@@ -226,6 +236,7 @@ UTBaseInputField.propTypes = {
|
|
|
226
236
|
alwaysShowPlaceholder: bool,
|
|
227
237
|
autoCapitalize: string,
|
|
228
238
|
blurOnSubmit: bool,
|
|
239
|
+
dataTestId: string,
|
|
229
240
|
disabled: bool,
|
|
230
241
|
editable: bool,
|
|
231
242
|
error: oneOfType([bool, string]),
|
|
@@ -6,29 +6,30 @@
|
|
|
6
6
|
|
|
7
7
|
## Props
|
|
8
8
|
|
|
9
|
-
| Name
|
|
10
|
-
|
|
|
11
|
-
| `actionAlignment`
|
|
12
|
-
| `adjustableHeight`
|
|
13
|
-
| `buttonText`
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
9
|
+
| Name | Type | Default | Description |
|
|
10
|
+
| ---------------------- | -------- | ------- | ----------------------------------------------------------------------- |
|
|
11
|
+
| `actionAlignment` | `string` | | Aligns the actions. |
|
|
12
|
+
| `adjustableHeight` | `bool` | `false` | If true the height of the component adjusts to the content. |
|
|
13
|
+
| `buttonText` | `string` | | Text for the button that appears in the top right corner of the header. |
|
|
14
|
+
| `dataTestId` | `string` | | Test ID for automated testing. Enables hierarchical test ID structure. |
|
|
15
|
+
| `description` | `string` | | Description that appears below the title in the header. |
|
|
16
|
+
| `onClose` | `func` | | Function called when the bottom sheet is closed. |
|
|
17
|
+
| `onCloseProps` | `object` | | Additional props passed to the `onClose` function (optional). |
|
|
18
|
+
| `primaryAction` | `func` | | Callback for the primary action button. |
|
|
19
|
+
| `primaryActionProps` | `object` | | Props for the primary action button. |
|
|
20
|
+
| `primaryActionText` | `string` | | Text for the primary action button. |
|
|
21
|
+
| `required` | `bool` | | Indicates if the field is required, showing an asterisk in the title. |
|
|
22
|
+
| `scrolleable` | `bool` | `false` | Determines if the content inside the bottom sheet should be scrollable. |
|
|
23
|
+
| `secondaryAction` | `func` | | Callback for the secondary action button. |
|
|
24
|
+
| `secondaryActionProps` | `object` | | Props for the secondary action button. |
|
|
25
|
+
| `secondaryActionText` | `string` | | Text for the secondary action button. |
|
|
26
|
+
| `tertiaryAction` | `func` | | Callback for the tertiary action button. |
|
|
27
|
+
| `tertiaryActionProps` | `object` | | Props for the tertiary action button . |
|
|
28
|
+
| `tertiaryActionText` | `string` | | Text for the tertiary action button. |
|
|
29
|
+
| `title` | `string` | | Title that appears in the bottom sheet header. |
|
|
30
|
+
| `titleProps` | `object` | | Props for the title label |
|
|
31
|
+
| `visible` | `bool` | | Controls the visibility of the bottom sheet. |
|
|
32
|
+
| `withBodyPadding` | `bool` | `true` | Controls the visibility of the bottom sheet. |
|
|
32
33
|
|
|
33
34
|
### actionAlignment
|
|
34
35
|
|
|
@@ -39,8 +40,35 @@ The value of `actionAlignment` must be one of the following:
|
|
|
39
40
|
|
|
40
41
|
By default, actions are aligned horizontally if there are two, and vertically otherwise.
|
|
41
42
|
|
|
43
|
+
## Test IDs
|
|
44
|
+
|
|
45
|
+
When `dataTestId` is provided, the component creates a hierarchical test ID structure:
|
|
46
|
+
|
|
47
|
+
| Element | Test ID | Condition |
|
|
48
|
+
| ---------------- | ------------------------------- | --------------------------------------- |
|
|
49
|
+
| Modal container | `${dataTestId}` | Always when `dataTestId` provided |
|
|
50
|
+
| Title | `${dataTestId}.title` | When `title` prop is provided |
|
|
51
|
+
| Description | `${dataTestId}.description` | When `description` prop is provided |
|
|
52
|
+
| Close button | `${dataTestId}.closeButton` | When `buttonText` prop is provided |
|
|
53
|
+
| Primary action | `${dataTestId}.primaryAction` | When `primaryAction` prop is provided |
|
|
54
|
+
| Secondary action | `${dataTestId}.secondaryAction` | When `secondaryAction` prop is provided |
|
|
55
|
+
| Tertiary action | `${dataTestId}.tertiaryAction` | When `tertiaryAction` prop is provided |
|
|
56
|
+
|
|
57
|
+
### Action Button Test IDs
|
|
58
|
+
|
|
59
|
+
Action buttons inherit test IDs from `UTButton` component:
|
|
60
|
+
|
|
61
|
+
- Each action gets its specific test ID (e.g., `${dataTestId}.primaryAction`)
|
|
62
|
+
- UTButton creates its own hierarchy for internal elements
|
|
63
|
+
|
|
64
|
+
### Children Test IDs
|
|
65
|
+
|
|
66
|
+
The content area (children) does not receive a test ID automatically. Developers should add test IDs directly to their children components as needed.
|
|
67
|
+
|
|
42
68
|
## Example
|
|
43
69
|
|
|
70
|
+
### Basic Usage
|
|
71
|
+
|
|
44
72
|
```jsx
|
|
45
73
|
import React, { useState } from 'react';
|
|
46
74
|
import { View, Button, Text } from 'react-native';
|
|
@@ -74,3 +102,46 @@ const Example = () => {
|
|
|
74
102
|
|
|
75
103
|
export default Example;
|
|
76
104
|
```
|
|
105
|
+
|
|
106
|
+
### With Test IDs
|
|
107
|
+
|
|
108
|
+
```jsx
|
|
109
|
+
import React, { useState } from 'react';
|
|
110
|
+
import { View, Button, Text } from 'react-native';
|
|
111
|
+
import UTBottomSheet from './UTBottomSheet';
|
|
112
|
+
|
|
113
|
+
const TestableExample = () => {
|
|
114
|
+
const [visible, setVisible] = useState(false);
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<View style={{ flex: 1 }}>
|
|
118
|
+
<Button title="Show Bottom Sheet" onPress={() => setVisible(true)} />
|
|
119
|
+
<UTBottomSheet
|
|
120
|
+
dataTestId="settingsSheet"
|
|
121
|
+
title="Settings"
|
|
122
|
+
description="Configure your preferences"
|
|
123
|
+
buttonText="Done"
|
|
124
|
+
visible={visible}
|
|
125
|
+
onClose={() => setVisible(false)}
|
|
126
|
+
primaryAction={() => console.log('Save')}
|
|
127
|
+
primaryActionText="Save Changes"
|
|
128
|
+
secondaryAction={() => console.log('Cancel')}
|
|
129
|
+
secondaryActionText="Cancel"
|
|
130
|
+
tertiaryAction={() => console.log('Reset')}
|
|
131
|
+
tertiaryActionText="Reset to Default"
|
|
132
|
+
>
|
|
133
|
+
<Text>Settings content goes here</Text>
|
|
134
|
+
</UTBottomSheet>
|
|
135
|
+
</View>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Generated test IDs:
|
|
140
|
+
// settingsSheet
|
|
141
|
+
// settingsSheet.title
|
|
142
|
+
// settingsSheet.description
|
|
143
|
+
// settingsSheet.closeButton
|
|
144
|
+
// settingsSheet.primaryAction
|
|
145
|
+
// settingsSheet.secondaryAction
|
|
146
|
+
// settingsSheet.tertiaryAction
|
|
147
|
+
```
|
|
@@ -8,10 +8,20 @@ import UTButton from '../UTButton';
|
|
|
8
8
|
import UTFieldLabel from '../UTFieldLabel';
|
|
9
9
|
import UTLabel from '../UTLabel';
|
|
10
10
|
import { IS_IOS } from '../../utils/platformUtils/constants';
|
|
11
|
+
import { TEST_ID_CONSTANTS } from '../../constants/testIds';
|
|
11
12
|
|
|
12
13
|
import styles from './styles';
|
|
13
14
|
import { ACTION_ALIGNMENTS } from './constants';
|
|
14
15
|
|
|
16
|
+
const {
|
|
17
|
+
title: titleTestId,
|
|
18
|
+
closeButton,
|
|
19
|
+
description: descriptionTestId,
|
|
20
|
+
primaryAction: primaryActionTestId,
|
|
21
|
+
secondaryAction: secondaryActionTestId,
|
|
22
|
+
tertiaryAction: tertiaryActionTestId
|
|
23
|
+
} = TEST_ID_CONSTANTS;
|
|
24
|
+
|
|
15
25
|
const screenHeight = Dimensions.get('window').height;
|
|
16
26
|
|
|
17
27
|
const UTBottomSheet = ({
|
|
@@ -36,7 +46,8 @@ const UTBottomSheet = ({
|
|
|
36
46
|
title,
|
|
37
47
|
titleProps = {},
|
|
38
48
|
visible,
|
|
39
|
-
withBodyPadding = true
|
|
49
|
+
withBodyPadding = true,
|
|
50
|
+
dataTestId
|
|
40
51
|
}) => {
|
|
41
52
|
const [height, setHeight] = useState('70%');
|
|
42
53
|
const [modalHeight, setModalHeight] = useState(height);
|
|
@@ -94,6 +105,7 @@ const UTBottomSheet = ({
|
|
|
94
105
|
propagateSwipe
|
|
95
106
|
style={styles.modal}
|
|
96
107
|
swipeDirection="down"
|
|
108
|
+
testID={dataTestId}
|
|
97
109
|
>
|
|
98
110
|
<Animated.View style={[styles.animatedContainer(theme), { height: modalHeight }, pan.getLayout()]}>
|
|
99
111
|
<SafeAreaView onLayout={onLayout} style={styles.content(adjustableHeight)}>
|
|
@@ -108,6 +120,7 @@ const UTBottomSheet = ({
|
|
|
108
120
|
style={styles.title}
|
|
109
121
|
variant="subtitle1"
|
|
110
122
|
weight="medium"
|
|
123
|
+
dataTestId={dataTestId ? `${dataTestId}.${titleTestId}` : undefined}
|
|
111
124
|
{...titleProps}
|
|
112
125
|
>
|
|
113
126
|
{title}
|
|
@@ -117,6 +130,7 @@ const UTBottomSheet = ({
|
|
|
117
130
|
colorTheme="primary"
|
|
118
131
|
onPress={onClose}
|
|
119
132
|
variant="semitransparent"
|
|
133
|
+
dataTestId={dataTestId ? `${dataTestId}.${closeButton}` : undefined}
|
|
120
134
|
{...onCloseProps}
|
|
121
135
|
>
|
|
122
136
|
{buttonText}
|
|
@@ -124,7 +138,11 @@ const UTBottomSheet = ({
|
|
|
124
138
|
)}
|
|
125
139
|
</View>
|
|
126
140
|
{description && (
|
|
127
|
-
<UTLabel
|
|
141
|
+
<UTLabel
|
|
142
|
+
colorTheme="gray"
|
|
143
|
+
variant="small"
|
|
144
|
+
dataTestId={dataTestId ? `${dataTestId}.${descriptionTestId}` : undefined}
|
|
145
|
+
>
|
|
128
146
|
{description}
|
|
129
147
|
</UTLabel>
|
|
130
148
|
)}
|
|
@@ -142,12 +160,14 @@ const UTBottomSheet = ({
|
|
|
142
160
|
variant: 'semitransparent',
|
|
143
161
|
onPress: primaryAction,
|
|
144
162
|
text: primaryActionText,
|
|
163
|
+
dataTestId: dataTestId ? `${dataTestId}.${primaryActionTestId}` : undefined,
|
|
145
164
|
...primaryActionProps
|
|
146
165
|
},
|
|
147
166
|
{
|
|
148
167
|
key: 'secondaryAction',
|
|
149
168
|
onPress: secondaryAction,
|
|
150
169
|
text: secondaryActionText,
|
|
170
|
+
dataTestId: dataTestId ? `${dataTestId}.${secondaryActionTestId}` : undefined,
|
|
151
171
|
...secondaryActionProps
|
|
152
172
|
},
|
|
153
173
|
{
|
|
@@ -155,16 +175,18 @@ const UTBottomSheet = ({
|
|
|
155
175
|
onPress: tertiaryAction,
|
|
156
176
|
text: tertiaryActionText,
|
|
157
177
|
variant: 'text',
|
|
178
|
+
dataTestId: dataTestId ? `${dataTestId}.${tertiaryActionTestId}` : undefined,
|
|
158
179
|
...tertiaryActionProps
|
|
159
180
|
}
|
|
160
181
|
].map(
|
|
161
|
-
({ text, key, onPress, ...actionProps }) =>
|
|
182
|
+
({ text, key, onPress, dataTestId: actionDataTestId, ...actionProps }) =>
|
|
162
183
|
onPress && (
|
|
163
184
|
<UTButton
|
|
164
185
|
key={key}
|
|
165
186
|
onPress={onPress}
|
|
166
187
|
size="large"
|
|
167
188
|
style={styles.action(actionAlignment)}
|
|
189
|
+
dataTestId={actionDataTestId}
|
|
168
190
|
{...actionProps}
|
|
169
191
|
>
|
|
170
192
|
{text}
|
|
@@ -204,7 +226,8 @@ UTBottomSheet.propTypes = {
|
|
|
204
226
|
title: string,
|
|
205
227
|
titleProps: object,
|
|
206
228
|
visible: bool,
|
|
207
|
-
withBodyPadding: bool
|
|
229
|
+
withBodyPadding: bool,
|
|
230
|
+
dataTestId: string
|
|
208
231
|
};
|
|
209
232
|
|
|
210
233
|
export default UTBottomSheet;
|
|
@@ -8,15 +8,19 @@ import UTBadge from '../UTBadge';
|
|
|
8
8
|
import UTIcon from '../UTIcon';
|
|
9
9
|
import UTLabel from '../UTLabel';
|
|
10
10
|
import UTLoading from '../UTLoading';
|
|
11
|
+
import { TEST_ID_CONSTANTS } from '../../constants/testIds';
|
|
11
12
|
|
|
12
13
|
import { COLORS_MAPPER, ICON_PLACEMENTS, VARIANTS_NAMES } from './constants';
|
|
13
14
|
import { defaultProps, propTypes } from './proptypes';
|
|
14
15
|
import { retrieveStyle } from './theme';
|
|
15
16
|
|
|
17
|
+
const { icon, badge, label: labelTestId } = TEST_ID_CONSTANTS;
|
|
18
|
+
|
|
16
19
|
const UTButton = ({
|
|
17
20
|
children,
|
|
18
21
|
colorTheme,
|
|
19
22
|
count,
|
|
23
|
+
dataTestId,
|
|
20
24
|
disabled,
|
|
21
25
|
Icon,
|
|
22
26
|
iconPlacement,
|
|
@@ -67,6 +71,7 @@ const UTButton = ({
|
|
|
67
71
|
return (
|
|
68
72
|
<UTIcon
|
|
69
73
|
colorTheme={textStyles.colorTheme}
|
|
74
|
+
dataTestId={`${dataTestId}.${icon}`}
|
|
70
75
|
name={Icon}
|
|
71
76
|
size={iconSize}
|
|
72
77
|
style={remainingIconStyles}
|
|
@@ -74,15 +79,24 @@ const UTButton = ({
|
|
|
74
79
|
);
|
|
75
80
|
})()
|
|
76
81
|
) : (
|
|
77
|
-
<Icon style={iconStyles} fill={iconStyles.color} />
|
|
82
|
+
<Icon testID={`${dataTestId}.${icon}`} style={iconStyles} fill={iconStyles.color} />
|
|
78
83
|
));
|
|
79
84
|
|
|
80
85
|
const RenderedChildren = (
|
|
81
86
|
<View style={themeChildrenContainerStyles}>
|
|
82
|
-
{count &&
|
|
87
|
+
{count && (
|
|
88
|
+
<UTBadge colorTheme={counterColorTheme} dataTestId={`${dataTestId}.${badge}`}>
|
|
89
|
+
{count}
|
|
90
|
+
</UTBadge>
|
|
91
|
+
)}
|
|
83
92
|
{iconPlacement === ICON_PLACEMENTS.LEFT && IconToShow}
|
|
84
93
|
{children && (
|
|
85
|
-
<UTLabel
|
|
94
|
+
<UTLabel
|
|
95
|
+
colorTheme={textStyles.colorTheme}
|
|
96
|
+
dataTestId={`${dataTestId}.${labelTestId}`}
|
|
97
|
+
variant={textStyles.variant}
|
|
98
|
+
weight={textStyles.weight}
|
|
99
|
+
>
|
|
86
100
|
{children}
|
|
87
101
|
</UTLabel>
|
|
88
102
|
)}
|
|
@@ -91,7 +105,7 @@ const UTButton = ({
|
|
|
91
105
|
);
|
|
92
106
|
|
|
93
107
|
return (
|
|
94
|
-
<Pressable disabled={disabled || loading} onPress={onPress} style={buttonStyles}>
|
|
108
|
+
<Pressable testID={dataTestId} disabled={disabled || loading} onPress={onPress} style={buttonStyles}>
|
|
95
109
|
<UTLoading color={iconStyles.color} loading={loading} size={24} thickness={2}>
|
|
96
110
|
{RenderedChildren}
|
|
97
111
|
</UTLoading>
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
| ------------- | ------ | ------- | ------------------------------------------------------------------------------ |
|
|
11
11
|
| value | bool | false | Indicates whether the checkbox is selected. |
|
|
12
12
|
| onChange | func | | Function to call when the checkbox value changes. |
|
|
13
|
+
| dataTestId | string | | Test ID for automated testing. Enables hierarchical test ID structure. |
|
|
13
14
|
| disabled | bool | false | Disables the checkbox, making it unclickable. |
|
|
14
15
|
| indeterminate | bool | false | Indicates if the checkbox is in an indeterminate state. |
|
|
15
16
|
| isSimple | bool | false | **Deprecated**: Avoid using simple checkboxes in favor of standard checkboxes. |
|
|
@@ -21,6 +22,26 @@
|
|
|
21
22
|
| withMarkdown | bool | false | Enables Markdown rendering for the `title`. |
|
|
22
23
|
| variant | string | | The variant to use for styling the checkbox. |
|
|
23
24
|
|
|
25
|
+
## Test IDs
|
|
26
|
+
|
|
27
|
+
When `dataTestId` is provided, the component creates a hierarchical test ID structure:
|
|
28
|
+
|
|
29
|
+
| Element | Test ID | Condition |
|
|
30
|
+
| ------------------ | -------------------------- | --------------------------------- |
|
|
31
|
+
| Checkbox pressable | `${dataTestId}` | Always when `dataTestId` provided |
|
|
32
|
+
| Checkbox icon | `${dataTestId}.icon` | Always when `dataTestId` provided |
|
|
33
|
+
| Title | `${dataTestId}.title` | When `title` prop is provided |
|
|
34
|
+
| Validation | `${dataTestId}.validation` | When `error` prop is provided |
|
|
35
|
+
|
|
36
|
+
### Test ID Structure Details
|
|
37
|
+
|
|
38
|
+
- **Checkbox pressable**: The main interactive element that users click to toggle the checkbox
|
|
39
|
+
- **Checkbox icon**: The visual indicator (checkmark, indeterminate line, or empty box)
|
|
40
|
+
- **Title**: The text/title displayed next to the checkbox (handled by UTFieldLabel)
|
|
41
|
+
- **Validation**: Error message displayed when validation fails
|
|
42
|
+
|
|
43
|
+
The checkbox icon test ID applies to both simple and standard variants, though the underlying implementation differs.
|
|
44
|
+
|
|
24
45
|
## Usage
|
|
25
46
|
|
|
26
47
|
### Basic Example
|
|
@@ -37,3 +58,29 @@ const Example = () => {
|
|
|
37
58
|
|
|
38
59
|
export default Example;
|
|
39
60
|
```
|
|
61
|
+
|
|
62
|
+
### With Test IDs
|
|
63
|
+
|
|
64
|
+
```jsx
|
|
65
|
+
import React from 'react';
|
|
66
|
+
import UTCheckBox from './UTCheckBox';
|
|
67
|
+
|
|
68
|
+
const TestableExample = () => {
|
|
69
|
+
const [termsAccepted, setTermsAccepted] = React.useState(false);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<UTCheckBox
|
|
73
|
+
dataTestId="termsCheckbox"
|
|
74
|
+
value={termsAccepted}
|
|
75
|
+
title="I accept the terms and conditions"
|
|
76
|
+
onChange={setTermsAccepted}
|
|
77
|
+
required={true}
|
|
78
|
+
/>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Generated test IDs:
|
|
83
|
+
// termsCheckbox (main pressable)
|
|
84
|
+
// termsCheckbox.icon (checkbox indicator)
|
|
85
|
+
// termsCheckbox.title (title text)
|
|
86
|
+
```
|