@widergy/mobile-ui 1.47.0 → 1.48.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.
- package/CHANGELOG.md +14 -0
- package/README.md +1 -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/constants.js +0 -10
- package/lib/components/UTLabel/index.js +2 -0
- package/lib/components/UTLabel/proptypes.js +1 -0
- package/lib/components/UTLabel/utils.js +4 -22
- 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/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
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
| alwaysShowPlaceholder | bool | false | Whether to always show the placeholder text, even when the field is focused. |
|
|
12
12
|
| autoCapitalize | oneOf('none','sentences','words','characters') | 'sentences' | Defines how to automatically capitalize certain characters. |
|
|
13
13
|
| blurOnSubmit | bool | | If true, the input will be blurred when the user submits the text. |
|
|
14
|
+
| dataTestId | string | | Test ID for automated testing. Enables hierarchical test ID structure. |
|
|
14
15
|
| disabled | bool | | Whether the input field is disabled. |
|
|
15
16
|
| editable | bool | true | Whether the input field is editable. If false, it behaves like a disabled field. |
|
|
16
17
|
| error | oneOfType([bool, string]) | | Error message to display, or `true` to indicate an error state without a message. |
|
|
@@ -33,6 +34,28 @@
|
|
|
33
34
|
| type | string | | Type of the input field (e.g., text, email, numeric, password). |
|
|
34
35
|
| variant | string | 'white' | Variant of the input field. One of: `white`, `gray`. |
|
|
35
36
|
|
|
37
|
+
## Test IDs
|
|
38
|
+
|
|
39
|
+
When `dataTestId` is provided, the component creates a hierarchical test ID structure:
|
|
40
|
+
|
|
41
|
+
| Element | Test ID | Condition |
|
|
42
|
+
| ---------------- | ------------------------------ | --------------------------------- |
|
|
43
|
+
| Input field | `${dataTestId}` | Always when `dataTestId` provided |
|
|
44
|
+
| Left adornments | `${dataTestId}.left` | When left adornments are present |
|
|
45
|
+
| Right adornments | `${dataTestId}.right` | When right adornments are present |
|
|
46
|
+
| Character count | `${dataTestId}.characterCount` | When `showCharacterCount` is true |
|
|
47
|
+
|
|
48
|
+
### Test ID Structure Details
|
|
49
|
+
|
|
50
|
+
- **Input field**: The main TextInput element gets the base `dataTestId`
|
|
51
|
+
- **Left adornments**: All left-side adornments share the `.left` test ID
|
|
52
|
+
- **Right adornments**: All right-side adornments share the `.right` test ID
|
|
53
|
+
- **Character count**: The character count display when enabled
|
|
54
|
+
|
|
55
|
+
### Adornment Test IDs
|
|
56
|
+
|
|
57
|
+
Individual adornments within the left/right containers inherit the adornment test ID and may create their own hierarchical structure based on their component type (e.g., UTIcon, UTButton, etc.).
|
|
58
|
+
|
|
36
59
|
## Input Types
|
|
37
60
|
|
|
38
61
|
The `type` prop can be one of these values:
|
|
@@ -176,31 +199,30 @@ Displays a tooltip with an icon.
|
|
|
176
199
|
<UTBaseInputField rightAdornments={[{ name: 'Tooltip', props: { tooltip: 'Tooltip Text' } }]} />
|
|
177
200
|
```
|
|
178
201
|
|
|
179
|
-
### Example
|
|
202
|
+
### Example with Test IDs
|
|
180
203
|
|
|
181
204
|
```javascript
|
|
182
|
-
//
|
|
183
|
-
<UTBaseInputField
|
|
184
|
-
leftAdornments={[{ name: 'Prefix', props: { text: 'Prefix Text' } }]}
|
|
185
|
-
/>
|
|
186
|
-
|
|
187
|
-
// Example of SuffixAdornment usage
|
|
188
|
-
<UTBaseInputField
|
|
189
|
-
rightAdornments={[{ name: 'Suffix', props: { text: 'Suffix Text' } }]}
|
|
190
|
-
/>
|
|
191
|
-
|
|
192
|
-
// Example of IconAdornment usage
|
|
205
|
+
// Basic input with test ID
|
|
193
206
|
<UTBaseInputField
|
|
194
|
-
|
|
207
|
+
dataTestId="userEmail"
|
|
208
|
+
placeholder="Enter your email"
|
|
209
|
+
type="email"
|
|
195
210
|
/>
|
|
196
211
|
|
|
197
|
-
//
|
|
212
|
+
// Input with adornments and test IDs
|
|
198
213
|
<UTBaseInputField
|
|
199
|
-
|
|
214
|
+
dataTestId="searchField"
|
|
215
|
+
placeholder="Search products..."
|
|
216
|
+
leftAdornments={[{ name: 'Icon', props: { Icon: 'IconSearch' } }]}
|
|
217
|
+
rightAdornments={[{ name: 'Action', props: { action: { text: 'Search', onPress: handleSearch } } }]}
|
|
218
|
+
showCharacterCount
|
|
219
|
+
maxLength={100}
|
|
200
220
|
/>
|
|
201
221
|
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
222
|
+
// Generated test IDs:
|
|
223
|
+
// userEmail (input field)
|
|
224
|
+
// searchField (input field)
|
|
225
|
+
// searchField.left (left adornments container)
|
|
226
|
+
// searchField.right (right adornments container)
|
|
227
|
+
// searchField.characterCount (character count display)
|
|
206
228
|
```
|
|
@@ -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>
|