@telus-uds/components-base 2.3.0 → 2.4.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 +21 -2
- package/lib/InputLabel/InputLabel.js +36 -2
- package/lib/InputSupports/InputSupports.js +31 -8
- package/lib/InputSupports/dictionary.js +12 -0
- package/lib/InputSupports/useInputSupports.js +12 -3
- package/lib/Link/LinkBase.js +17 -15
- package/lib/Modal/Modal.js +2 -2
- package/lib/MultiSelectFilter/MultiSelectFilter.js +54 -41
- package/lib/Notification/Notification.js +7 -3
- package/lib/Search/Search.js +39 -8
- package/lib/Select/Picker.native.js +8 -4
- package/lib/Select/constants.js +4 -2
- package/lib/TextInput/TextArea.js +7 -6
- package/lib/TextInput/TextInput.js +7 -6
- package/lib/TextInput/TextInputBase.js +48 -14
- package/lib/utils/props/inputSupportsProps.js +15 -3
- package/package.json +2 -2
- package/src/InputLabel/InputLabel.jsx +39 -2
- package/src/InputSupports/InputSupports.jsx +33 -7
- package/src/InputSupports/dictionary.js +12 -0
- package/src/InputSupports/useInputSupports.js +24 -3
- package/src/Link/LinkBase.jsx +17 -15
- package/src/Modal/Modal.jsx +1 -1
- package/src/MultiSelectFilter/MultiSelectFilter.jsx +55 -27
- package/src/Notification/Notification.jsx +9 -3
- package/src/Search/Search.jsx +52 -24
- package/src/Select/Picker.native.jsx +10 -4
- package/src/Select/constants.js +4 -1
- package/src/TextInput/TextArea.jsx +12 -5
- package/src/TextInput/TextInput.jsx +13 -6
- package/src/TextInput/TextInputBase.jsx +57 -10
- package/src/utils/props/inputSupportsProps.js +15 -3
|
@@ -61,10 +61,6 @@ const TextArea = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
61
61
|
} = selectProps(rest);
|
|
62
62
|
const inputProps = {
|
|
63
63
|
...selectedProps,
|
|
64
|
-
variant: {
|
|
65
|
-
...variant,
|
|
66
|
-
validation: supportsProps.validation
|
|
67
|
-
},
|
|
68
64
|
multiline: true,
|
|
69
65
|
onContentSizeChange: onHeightChange,
|
|
70
66
|
height: inputHeight,
|
|
@@ -72,6 +68,7 @@ const TextArea = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
72
68
|
};
|
|
73
69
|
return /*#__PURE__*/_jsx(InputSupports, {
|
|
74
70
|
...supportsProps,
|
|
71
|
+
inputValue: selectedProps === null || selectedProps === void 0 ? void 0 : selectedProps.value,
|
|
75
72
|
children: _ref3 => {
|
|
76
73
|
let {
|
|
77
74
|
inputId,
|
|
@@ -79,9 +76,13 @@ const TextArea = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
79
76
|
} = _ref3;
|
|
80
77
|
return /*#__PURE__*/_jsx(TextInputBase, {
|
|
81
78
|
ref: ref,
|
|
82
|
-
...inputProps,
|
|
83
79
|
nativeID: inputId,
|
|
84
|
-
...props
|
|
80
|
+
...props,
|
|
81
|
+
...inputProps,
|
|
82
|
+
variant: {
|
|
83
|
+
...variant,
|
|
84
|
+
validation: props.validation
|
|
85
|
+
}
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
88
|
});
|
|
@@ -38,16 +38,13 @@ const TextInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
38
38
|
} = selectProps(rest);
|
|
39
39
|
const inputProps = {
|
|
40
40
|
...selectedProps,
|
|
41
|
-
tokens
|
|
42
|
-
variant: {
|
|
43
|
-
...variant,
|
|
44
|
-
validation: supportsProps.validation
|
|
45
|
-
}
|
|
41
|
+
tokens
|
|
46
42
|
};
|
|
47
43
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
48
44
|
children: [/*#__PURE__*/_jsx(InputSupports, {
|
|
49
45
|
nativeID: nativeID,
|
|
50
46
|
...supportsProps,
|
|
47
|
+
inputValue: selectedProps === null || selectedProps === void 0 ? void 0 : selectedProps.value,
|
|
51
48
|
children: _ref2 => {
|
|
52
49
|
let {
|
|
53
50
|
inputId,
|
|
@@ -57,7 +54,11 @@ const TextInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
57
54
|
ref: ref,
|
|
58
55
|
nativeID: inputId,
|
|
59
56
|
...propsFromInputSupports,
|
|
60
|
-
...inputProps
|
|
57
|
+
...inputProps,
|
|
58
|
+
variant: {
|
|
59
|
+
...variant,
|
|
60
|
+
validation: propsFromInputSupports.validation
|
|
61
|
+
}
|
|
61
62
|
});
|
|
62
63
|
}
|
|
63
64
|
}), rest.children]
|
|
@@ -37,6 +37,9 @@ const selectInputStyles = function (_ref, themeOptions, inactive, type) {
|
|
|
37
37
|
let buttonSize = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
|
|
38
38
|
let buttonsGapSize = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;
|
|
39
39
|
let isPassword = arguments.length > 7 ? arguments[7] : undefined;
|
|
40
|
+
let iconLeftWidth = arguments.length > 8 ? arguments[8] : undefined;
|
|
41
|
+
let iconLeftGap = arguments.length > 9 ? arguments[9] : undefined;
|
|
42
|
+
let direction = arguments.length > 10 ? arguments[10] : undefined;
|
|
40
43
|
// Subtract border width from padding so overall input width/height doesn't
|
|
41
44
|
// jump around if the border width changes (avoiding NaN and negative padding)
|
|
42
45
|
const offsetBorder = value => typeof value === 'number' ? Math.max(0, value - borderWidth) : value;
|
|
@@ -63,6 +66,15 @@ const selectInputStyles = function (_ref, themeOptions, inactive, type) {
|
|
|
63
66
|
resize: minHeight !== maxHeight ? 'vertical' : 'none' // does nothing for an input, only needed for textarea
|
|
64
67
|
}
|
|
65
68
|
});
|
|
69
|
+
const getPaddingLeft = () => {
|
|
70
|
+
if (type === 'card') {
|
|
71
|
+
return offsetBorder(paddingLeft + 34);
|
|
72
|
+
}
|
|
73
|
+
if (direction === 'left') {
|
|
74
|
+
return offsetBorder(iconLeftWidth + iconLeftGap + staticStyles.iconLeftContainer.paddingLeft);
|
|
75
|
+
}
|
|
76
|
+
return offsetBorder(paddingLeft);
|
|
77
|
+
};
|
|
66
78
|
const buttonSpacing = isPassword ? buttonsGapSize : -buttonsGapSize;
|
|
67
79
|
const adjustedPaddingRight = paddingRight + (buttonCount ? 1 : 0) * (buttonSize + buttonSpacing);
|
|
68
80
|
const adjustedPaddingWithButtons = buttonCount > 1 ? paddingRight : adjustedPaddingRight;
|
|
@@ -73,7 +85,7 @@ const selectInputStyles = function (_ref, themeOptions, inactive, type) {
|
|
|
73
85
|
borderWidth,
|
|
74
86
|
borderColor,
|
|
75
87
|
borderRadius,
|
|
76
|
-
paddingLeft:
|
|
88
|
+
paddingLeft: getPaddingLeft(),
|
|
77
89
|
paddingRight: icon ? offsetBorder(paddingWithIcon) : offsetBorder(adjustedPaddingWithButtons),
|
|
78
90
|
paddingTop: offsetBorder(paddingTop),
|
|
79
91
|
paddingBottom: offsetBorder(paddingBottom),
|
|
@@ -123,20 +135,26 @@ const selectIconContainerStyles = (_ref4, buttonCount) => {
|
|
|
123
135
|
paddingBottom
|
|
124
136
|
};
|
|
125
137
|
};
|
|
126
|
-
const
|
|
138
|
+
const selectIconCardLeftContainerStyles = _ref5 => {
|
|
127
139
|
let {
|
|
128
140
|
leftIconPaddingBottom
|
|
129
141
|
} = _ref5;
|
|
130
142
|
return {
|
|
131
|
-
// not tokenizing paddingLeft as it remains same across brands for now
|
|
132
|
-
paddingLeft: 10,
|
|
133
143
|
paddingBottom: leftIconPaddingBottom
|
|
134
144
|
};
|
|
135
145
|
};
|
|
136
|
-
const
|
|
146
|
+
const selectIconLeftContainerStyles = _ref6 => {
|
|
137
147
|
let {
|
|
138
|
-
|
|
148
|
+
iconLeftPaddingBottom
|
|
139
149
|
} = _ref6;
|
|
150
|
+
return {
|
|
151
|
+
paddingBottom: iconLeftPaddingBottom
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
const selectButtonsContainerStyle = _ref7 => {
|
|
155
|
+
let {
|
|
156
|
+
buttonsPaddingRight
|
|
157
|
+
} = _ref7;
|
|
140
158
|
return {
|
|
141
159
|
paddingRight: buttonsPaddingRight
|
|
142
160
|
};
|
|
@@ -180,7 +198,7 @@ const getIcon = function () {
|
|
|
180
198
|
testID: selectedIcon.testID
|
|
181
199
|
});
|
|
182
200
|
};
|
|
183
|
-
const TextInputBase = /*#__PURE__*/React.forwardRef((
|
|
201
|
+
const TextInputBase = /*#__PURE__*/React.forwardRef((_ref8, ref) => {
|
|
184
202
|
let {
|
|
185
203
|
buttons = [],
|
|
186
204
|
copy = 'en',
|
|
@@ -201,8 +219,9 @@ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
|
|
|
201
219
|
variant = {},
|
|
202
220
|
type,
|
|
203
221
|
onKeyPress,
|
|
222
|
+
direction,
|
|
204
223
|
...rest
|
|
205
|
-
} =
|
|
224
|
+
} = _ref8;
|
|
206
225
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
207
226
|
const [showPassword, setShowPassword] = React.useState(false);
|
|
208
227
|
const handleFocus = event => {
|
|
@@ -288,14 +307,16 @@ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
|
|
|
288
307
|
defaultCreditIcon,
|
|
289
308
|
amexIcon,
|
|
290
309
|
visaIcon,
|
|
291
|
-
masterCardIcon
|
|
310
|
+
masterCardIcon,
|
|
311
|
+
iconLeftGap
|
|
292
312
|
} = themeTokens;
|
|
293
313
|
const buttonsGapSize = useSpacingScale(buttonsGap);
|
|
294
314
|
const getCopy = useCopy({
|
|
295
315
|
dictionary,
|
|
296
316
|
copy
|
|
297
317
|
});
|
|
298
|
-
const textInputButtons = buttons;
|
|
318
|
+
const textInputButtons = direction === 'left' ? buttons.filter(button => button && button.key !== 'submitIcon') : buttons;
|
|
319
|
+
const submitIcon = direction === 'left' ? buttons.find(button => button && button.key === 'submitIcon') : null;
|
|
299
320
|
if (onClear && isDirty) {
|
|
300
321
|
textInputButtons === null || textInputButtons === void 0 || textInputButtons.unshift(/*#__PURE__*/_jsx(IconButton, {
|
|
301
322
|
accessibilityLabel: getCopy('clearButtonAccessibilityLabel'),
|
|
@@ -339,15 +360,20 @@ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
|
|
|
339
360
|
const {
|
|
340
361
|
themeOptions
|
|
341
362
|
} = useTheme();
|
|
363
|
+
const iconLeftWidth = submitIcon ? submitIcon.props.tokens.size ?? 0 : 0;
|
|
342
364
|
const nativeInputStyle = selectInputStyles({
|
|
343
365
|
...themeTokens,
|
|
344
366
|
height
|
|
345
|
-
}, themeOptions, inactive, type, buttons === null || buttons === void 0 ? void 0 : buttons.length, themeTokens.buttonSize, buttonsGapSize, isPassword);
|
|
367
|
+
}, themeOptions, inactive, type, buttons === null || buttons === void 0 ? void 0 : buttons.length, themeTokens.buttonSize, buttonsGapSize, isPassword, iconLeftWidth, iconLeftGap, direction);
|
|
368
|
+
const shouldShowSubmitIcon = submitIcon && direction === 'left' && !inactive;
|
|
346
369
|
return /*#__PURE__*/_jsxs(View, {
|
|
347
370
|
style: selectOuterBorderStyles(themeTokens),
|
|
348
|
-
children: [
|
|
371
|
+
children: [shouldShowSubmitIcon && /*#__PURE__*/_jsx(View, {
|
|
372
|
+
style: [staticStyles.iconLeftContainer, selectIconLeftContainerStyles(themeTokens)],
|
|
373
|
+
children: submitIcon
|
|
374
|
+
}), type === 'card' && /*#__PURE__*/_jsx(View, {
|
|
349
375
|
pointerEvents: "none",
|
|
350
|
-
style: [staticStyles.
|
|
376
|
+
style: [staticStyles.iconCardLeftContainer, selectIconCardLeftContainerStyles(themeTokens)],
|
|
351
377
|
children: getIcon(currentValue, {
|
|
352
378
|
defaultCreditIcon,
|
|
353
379
|
amexIcon,
|
|
@@ -425,7 +451,15 @@ const staticStyles = StyleSheet.create({
|
|
|
425
451
|
right: 0,
|
|
426
452
|
bottom: 0
|
|
427
453
|
},
|
|
428
|
-
|
|
454
|
+
iconCardLeftContainer: {
|
|
455
|
+
paddingLeft: 10,
|
|
456
|
+
position: 'absolute',
|
|
457
|
+
left: 0,
|
|
458
|
+
bottom: 0,
|
|
459
|
+
zIndex: 1
|
|
460
|
+
},
|
|
461
|
+
iconLeftContainer: {
|
|
462
|
+
paddingLeft: 10,
|
|
429
463
|
position: 'absolute',
|
|
430
464
|
left: 0,
|
|
431
465
|
bottom: 0,
|
|
@@ -37,7 +37,15 @@ export default {
|
|
|
37
37
|
/**
|
|
38
38
|
* Use to visually mark an input as valid or invalid.
|
|
39
39
|
*/
|
|
40
|
-
validation: PropTypes.oneOf(['error', 'success'])
|
|
40
|
+
validation: PropTypes.oneOf(['error', 'success']),
|
|
41
|
+
/**
|
|
42
|
+
* The text value from an input field.
|
|
43
|
+
*/
|
|
44
|
+
inputValue: PropTypes.string,
|
|
45
|
+
/**
|
|
46
|
+
* Max number of characters allowed id an input text.
|
|
47
|
+
*/
|
|
48
|
+
maxCharacterAllowed: PropTypes.number
|
|
41
49
|
},
|
|
42
50
|
select: _ref => {
|
|
43
51
|
let {
|
|
@@ -49,7 +57,9 @@ export default {
|
|
|
49
57
|
feedbackTokens,
|
|
50
58
|
feedbackProps,
|
|
51
59
|
tooltip,
|
|
52
|
-
validation
|
|
60
|
+
validation,
|
|
61
|
+
inputValue,
|
|
62
|
+
maxCharacterAllowed
|
|
53
63
|
} = _ref;
|
|
54
64
|
return {
|
|
55
65
|
supportsProps: {
|
|
@@ -61,7 +71,9 @@ export default {
|
|
|
61
71
|
feedbackTokens,
|
|
62
72
|
feedbackProps,
|
|
63
73
|
tooltip,
|
|
64
|
-
validation
|
|
74
|
+
validation,
|
|
75
|
+
inputValue,
|
|
76
|
+
maxCharacterAllowed
|
|
65
77
|
}
|
|
66
78
|
};
|
|
67
79
|
}
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@gorhom/portal": "^1.0.14",
|
|
14
14
|
"@react-native-picker/picker": "^2.9.0",
|
|
15
15
|
"@telus-uds/system-constants": "^2.0.0",
|
|
16
|
-
"@telus-uds/system-theme-tokens": "^3.
|
|
16
|
+
"@telus-uds/system-theme-tokens": "^3.3.0",
|
|
17
17
|
"airbnb-prop-types": "^2.16.0",
|
|
18
18
|
"css-mediaquery": "^0.1.2",
|
|
19
19
|
"expo-document-picker": "^13.0.1",
|
|
@@ -81,6 +81,6 @@
|
|
|
81
81
|
"standard-engine": {
|
|
82
82
|
"skip": true
|
|
83
83
|
},
|
|
84
|
-
"version": "2.
|
|
84
|
+
"version": "2.4.0",
|
|
85
85
|
"types": "types/index.d.ts"
|
|
86
86
|
}
|
|
@@ -47,6 +47,8 @@ const InputLabel = React.forwardRef(
|
|
|
47
47
|
tooltip,
|
|
48
48
|
tokens,
|
|
49
49
|
variant,
|
|
50
|
+
characterCount,
|
|
51
|
+
maxCharacterAllowed,
|
|
50
52
|
...rest
|
|
51
53
|
},
|
|
52
54
|
ref
|
|
@@ -95,12 +97,30 @@ const InputLabel = React.forwardRef(
|
|
|
95
97
|
<Tooltip content={tooltip} copy={copy} />
|
|
96
98
|
</View>
|
|
97
99
|
)}
|
|
100
|
+
{maxCharacterAllowed && isHintInline && (
|
|
101
|
+
<Text style={[selectHintStyles({ ...themeTokens }), staticStyles.characterCountlabel]}>
|
|
102
|
+
{characterCount}/{maxCharacterAllowed}
|
|
103
|
+
</Text>
|
|
104
|
+
)}
|
|
98
105
|
</View>
|
|
99
|
-
{hint && !isHintInline && (
|
|
106
|
+
{hint && !maxCharacterAllowed && !isHintInline && (
|
|
100
107
|
<Text style={[selectHintStyles(themeTokens), staticStyles.hintBelow]} nativeID={hintId}>
|
|
101
108
|
{hint}
|
|
102
109
|
</Text>
|
|
103
110
|
)}
|
|
111
|
+
{hint && maxCharacterAllowed && !isHintInline && (
|
|
112
|
+
<View style={staticStyles.container}>
|
|
113
|
+
<Text
|
|
114
|
+
style={[selectHintStyles(themeTokens), staticStyles.flexHintBelow]}
|
|
115
|
+
nativeID={hintId}
|
|
116
|
+
>
|
|
117
|
+
{hint}
|
|
118
|
+
</Text>
|
|
119
|
+
<Text style={[selectHintStyles(themeTokens), staticStyles.characterCountlabel]}>
|
|
120
|
+
{characterCount}/{maxCharacterAllowed}
|
|
121
|
+
</Text>
|
|
122
|
+
</View>
|
|
123
|
+
)}
|
|
104
124
|
</>
|
|
105
125
|
)
|
|
106
126
|
}
|
|
@@ -137,6 +157,14 @@ InputLabel.propTypes = {
|
|
|
137
157
|
* Content of an optional `Tooltip`. If set, a tooltip button will be shown next to the label.
|
|
138
158
|
*/
|
|
139
159
|
tooltip: PropTypes.string,
|
|
160
|
+
/**
|
|
161
|
+
* Current number of characterts of an input text.
|
|
162
|
+
*/
|
|
163
|
+
characterCount: PropTypes.number,
|
|
164
|
+
/**
|
|
165
|
+
* Max number of characters that allows an input text.
|
|
166
|
+
*/
|
|
167
|
+
maxCharacterAllowed: PropTypes.number,
|
|
140
168
|
tokens: getTokensPropType('InputLabel'),
|
|
141
169
|
variant: variantProp.propType
|
|
142
170
|
}
|
|
@@ -148,13 +176,22 @@ const staticStyles = StyleSheet.create({
|
|
|
148
176
|
flexShrink: 1,
|
|
149
177
|
flexDirection: 'row'
|
|
150
178
|
},
|
|
179
|
+
characterCountlabel: {
|
|
180
|
+
marginLeft: 'auto',
|
|
181
|
+
marginTop: 'auto'
|
|
182
|
+
},
|
|
151
183
|
label: {
|
|
152
|
-
flexShrink: 1
|
|
184
|
+
flexShrink: 1,
|
|
185
|
+
alignSelf: 'center'
|
|
153
186
|
},
|
|
154
187
|
hintBelow: {
|
|
155
188
|
flexBasis: '100%',
|
|
156
189
|
flexShrink: 0
|
|
157
190
|
},
|
|
191
|
+
flexHintBelow: {
|
|
192
|
+
flexBasis: '100%',
|
|
193
|
+
flexShrink: 1
|
|
194
|
+
},
|
|
158
195
|
tooltipAlign: {
|
|
159
196
|
alignSelf: 'center',
|
|
160
197
|
justifyContent: 'center'
|
|
@@ -6,7 +6,8 @@ import Feedback from '../Feedback'
|
|
|
6
6
|
import StackView from '../StackView'
|
|
7
7
|
import { useThemeTokens } from '../ThemeProvider'
|
|
8
8
|
import useInputSupports from './useInputSupports'
|
|
9
|
-
import { getTokensPropType } from '../utils'
|
|
9
|
+
import { getTokensPropType, useCopy } from '../utils'
|
|
10
|
+
import dictionary from './dictionary'
|
|
10
11
|
|
|
11
12
|
const InputSupports = React.forwardRef(
|
|
12
13
|
(
|
|
@@ -21,18 +22,31 @@ const InputSupports = React.forwardRef(
|
|
|
21
22
|
feedbackProps = {},
|
|
22
23
|
tooltip,
|
|
23
24
|
validation,
|
|
25
|
+
maxCharacterAllowed,
|
|
26
|
+
inputValue,
|
|
24
27
|
nativeID
|
|
25
28
|
},
|
|
26
29
|
ref
|
|
27
30
|
) => {
|
|
28
31
|
const { space } = useThemeTokens('InputSupports')
|
|
32
|
+
const getCopy = useCopy({ dictionary, copy })
|
|
33
|
+
|
|
34
|
+
const maxCharsReachedErrorMessage =
|
|
35
|
+
inputValue?.length > maxCharacterAllowed
|
|
36
|
+
? getCopy('maxCharsMessage').replace(/%\{charCount\}/g, maxCharacterAllowed)
|
|
37
|
+
: ''
|
|
38
|
+
|
|
39
|
+
const feedbackValidation = inputValue?.length > maxCharacterAllowed ? 'error' : validation
|
|
29
40
|
|
|
30
41
|
const { inputId, hintId, feedbackId, a11yProps } = useInputSupports({
|
|
31
42
|
feedback,
|
|
32
43
|
hint,
|
|
33
44
|
label,
|
|
34
45
|
validation,
|
|
35
|
-
nativeID
|
|
46
|
+
nativeID,
|
|
47
|
+
copy,
|
|
48
|
+
maxCharacterAllowed,
|
|
49
|
+
charactersCount: maxCharacterAllowed - inputValue?.length
|
|
36
50
|
})
|
|
37
51
|
|
|
38
52
|
return (
|
|
@@ -46,14 +60,18 @@ const InputSupports = React.forwardRef(
|
|
|
46
60
|
hintId={hintId}
|
|
47
61
|
tooltip={tooltip}
|
|
48
62
|
forId={inputId}
|
|
63
|
+
characterCount={inputValue?.length}
|
|
64
|
+
maxCharacterAllowed={maxCharacterAllowed}
|
|
49
65
|
/>
|
|
50
66
|
)}
|
|
51
|
-
{typeof children === 'function'
|
|
52
|
-
|
|
67
|
+
{typeof children === 'function'
|
|
68
|
+
? children({ inputId, ...a11yProps, validation: feedbackValidation })
|
|
69
|
+
: children}
|
|
70
|
+
{feedback || maxCharsReachedErrorMessage ? (
|
|
53
71
|
<Feedback
|
|
54
72
|
id={feedbackId}
|
|
55
|
-
title={feedback}
|
|
56
|
-
validation={
|
|
73
|
+
title={feedback || maxCharsReachedErrorMessage}
|
|
74
|
+
validation={feedbackValidation}
|
|
57
75
|
tokens={feedbackTokens}
|
|
58
76
|
variant={{ icon: feedbackProps.showFeedbackIcon }}
|
|
59
77
|
{...feedbackProps}
|
|
@@ -107,7 +125,15 @@ InputSupports.propTypes = {
|
|
|
107
125
|
/**
|
|
108
126
|
* ID for DOM element on web
|
|
109
127
|
*/
|
|
110
|
-
nativeID: PropTypes.string
|
|
128
|
+
nativeID: PropTypes.string,
|
|
129
|
+
/**
|
|
130
|
+
* The text value of a TextArea or TextInput
|
|
131
|
+
*/
|
|
132
|
+
inputValue: PropTypes.string,
|
|
133
|
+
/**
|
|
134
|
+
* Max number of characters that allows an input text.
|
|
135
|
+
*/
|
|
136
|
+
maxCharacterAllowed: PropTypes.number
|
|
111
137
|
}
|
|
112
138
|
|
|
113
139
|
export default InputSupports
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
en: {
|
|
3
|
+
maxCharacters: 'Maximum %{charCount} characters',
|
|
4
|
+
charactersRemaining: '%{charCount} characters remaining',
|
|
5
|
+
maxCharsMessage: 'Must not exceed %{charCount} characters'
|
|
6
|
+
},
|
|
7
|
+
fr: {
|
|
8
|
+
maxCharacters: '%{charCount} caractères maximum',
|
|
9
|
+
charactersRemaining: '%{charCount} caractères restants',
|
|
10
|
+
maxCharsMessage: 'Ne doit pas dépasser %{charCount} caractères'
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import useUniqueId from '../utils/useUniqueId'
|
|
2
|
+
import { useCopy } from '../utils'
|
|
3
|
+
import dictionary from './dictionary'
|
|
2
4
|
|
|
3
5
|
const joinDefined = (array) => array.filter((item) => item !== undefined).join(' ')
|
|
4
6
|
|
|
5
|
-
const useInputSupports = ({
|
|
7
|
+
const useInputSupports = ({
|
|
8
|
+
label,
|
|
9
|
+
feedback,
|
|
10
|
+
validation,
|
|
11
|
+
hint,
|
|
12
|
+
nativeID,
|
|
13
|
+
copy,
|
|
14
|
+
maxCharacterAllowed,
|
|
15
|
+
charactersCount
|
|
16
|
+
}) => {
|
|
17
|
+
const getCopy = useCopy({ dictionary, copy })
|
|
6
18
|
const hasValidationError = validation === 'error'
|
|
7
19
|
|
|
8
20
|
const inputId = useUniqueId('input')
|
|
@@ -11,10 +23,19 @@ const useInputSupports = ({ label, feedback, validation, hint, nativeID }) => {
|
|
|
11
23
|
|
|
12
24
|
const a11yProps = {
|
|
13
25
|
accessibilityLabel: label,
|
|
14
|
-
accessibilityHint: joinDefined([
|
|
26
|
+
accessibilityHint: joinDefined([
|
|
27
|
+
!hasValidationError && feedback,
|
|
28
|
+
hint,
|
|
29
|
+
maxCharacterAllowed
|
|
30
|
+
? getCopy('maxCharacters').replace(/%\{charCount\}/g, maxCharacterAllowed)
|
|
31
|
+
: undefined
|
|
32
|
+
]), // native only -> replaced with describedBy on web
|
|
15
33
|
accessibilityDescribedBy: joinDefined([
|
|
16
34
|
!hasValidationError && feedback && feedbackId, // feedback receives a11yRole=alert on error, so there's no need to include it here
|
|
17
|
-
hint && hintId
|
|
35
|
+
hint && hintId,
|
|
36
|
+
charactersCount
|
|
37
|
+
? getCopy('charactersRemaining').replace(/%\{charCount\}/g, charactersCount)
|
|
38
|
+
: undefined
|
|
18
39
|
]),
|
|
19
40
|
accessibilityInvalid: hasValidationError
|
|
20
41
|
}
|
package/src/Link/LinkBase.jsx
CHANGED
|
@@ -32,21 +32,15 @@ const selectOuterBorderStyles = ({
|
|
|
32
32
|
outerBorderGap,
|
|
33
33
|
borderRadius,
|
|
34
34
|
outerBorderOutline
|
|
35
|
-
}) =>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
outerBorderWidth,
|
|
45
|
-
outerBorderGap
|
|
46
|
-
}),
|
|
47
|
-
borderRadius
|
|
48
|
-
}
|
|
49
|
-
: {}
|
|
35
|
+
}) => ({
|
|
36
|
+
outline: outerBorderOutline,
|
|
37
|
+
...applyOuterBorder({
|
|
38
|
+
outerBorderColor,
|
|
39
|
+
outerBorderWidth,
|
|
40
|
+
outerBorderGap
|
|
41
|
+
}),
|
|
42
|
+
borderRadius
|
|
43
|
+
})
|
|
50
44
|
|
|
51
45
|
const selectTextStyles = ({ color, blockFontSize }) => {
|
|
52
46
|
return {
|
|
@@ -174,6 +168,7 @@ const LinkBase = React.forwardRef(
|
|
|
174
168
|
const decorationStyles = selectDecorationStyles(themeTokens)
|
|
175
169
|
return [
|
|
176
170
|
outerBorderStyles,
|
|
171
|
+
staticStyles.outerBorderStyles,
|
|
177
172
|
blockLeftStyle,
|
|
178
173
|
decorationStyles,
|
|
179
174
|
hasIcon && staticStyles.rowContainer
|
|
@@ -273,6 +268,13 @@ const staticStyles = StyleSheet.create({
|
|
|
273
268
|
pointerEvents: 'none'
|
|
274
269
|
}
|
|
275
270
|
})
|
|
271
|
+
},
|
|
272
|
+
outerBorderStyles: {
|
|
273
|
+
...(Platform.OS !== 'web' && {
|
|
274
|
+
margin: 0,
|
|
275
|
+
marginHorizontal: 2,
|
|
276
|
+
padding: 0
|
|
277
|
+
})
|
|
276
278
|
}
|
|
277
279
|
})
|
|
278
280
|
|
package/src/Modal/Modal.jsx
CHANGED
|
@@ -30,14 +30,6 @@ import ModalOverlay from './ModalOverlay'
|
|
|
30
30
|
|
|
31
31
|
const { Col, Row } = FlexGrid
|
|
32
32
|
|
|
33
|
-
const selectSubTitleTokens = ({ subtitleColor }) => ({
|
|
34
|
-
color: subtitleColor
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
const selectDividerTokens = ({ dividerColor }) => ({
|
|
38
|
-
color: dividerColor
|
|
39
|
-
})
|
|
40
|
-
|
|
41
33
|
const selectHeaderTokens = ({
|
|
42
34
|
contentMarginLeft,
|
|
43
35
|
contentMarginRight,
|
|
@@ -113,23 +105,6 @@ const MultiSelectFilter = React.forwardRef(
|
|
|
113
105
|
const [checkedIds, setCheckedIds] = React.useState(currentValues ?? [])
|
|
114
106
|
const [maxWidth, setMaxWidth] = React.useState(false)
|
|
115
107
|
|
|
116
|
-
const themeTokens = useThemeTokens('ButtonDropdown', tokens, variant)
|
|
117
|
-
const getItemTokens = useThemeTokensCallback('ButtonDropdown', tokens, variant)
|
|
118
|
-
const getButtonTokens = (buttonState) => selectTokens('Button', getItemTokens(buttonState))
|
|
119
|
-
const getCopy = useCopy({ dictionary, copy })
|
|
120
|
-
const colSizeNotMobile = items.length > rowLimit ? 2 : 1
|
|
121
|
-
const colSize = viewport !== 'xs' ? colSizeNotMobile : 1
|
|
122
|
-
const itemsLengthNotMobile = items.length > 24 ? items.length / 2 : rowLimit
|
|
123
|
-
const isSelected = currentValues.length > 0
|
|
124
|
-
const rowLength = viewport !== 'xs' ? itemsLengthNotMobile : items.length
|
|
125
|
-
|
|
126
|
-
React.useEffect(() => {
|
|
127
|
-
if (colSize === 1) return setMaxWidth(false)
|
|
128
|
-
return colSize === 2 && setMaxWidth(true)
|
|
129
|
-
}, [colSize])
|
|
130
|
-
|
|
131
|
-
React.useEffect(() => setCheckedIds(currentValues ?? []), [currentValues])
|
|
132
|
-
|
|
133
108
|
const {
|
|
134
109
|
headerFontColor,
|
|
135
110
|
headerFontSize,
|
|
@@ -143,6 +118,20 @@ const MultiSelectFilter = React.forwardRef(
|
|
|
143
118
|
subHeaderLineHeight,
|
|
144
119
|
minHeight,
|
|
145
120
|
minWidth,
|
|
121
|
+
labelFontName,
|
|
122
|
+
labelFontSize,
|
|
123
|
+
labelFontWeight,
|
|
124
|
+
labelColor,
|
|
125
|
+
labelLineHeight,
|
|
126
|
+
labelPaddingTop,
|
|
127
|
+
labelPaddingBottom,
|
|
128
|
+
labelPaddingLeft,
|
|
129
|
+
labelPaddingRight,
|
|
130
|
+
buttonBorderColor,
|
|
131
|
+
buttonIconSize,
|
|
132
|
+
buttonIconPadding,
|
|
133
|
+
subtitleColor,
|
|
134
|
+
dividerColor,
|
|
146
135
|
...restTokens
|
|
147
136
|
} = useThemeTokens(
|
|
148
137
|
'MultiSelectFilter',
|
|
@@ -150,6 +139,40 @@ const MultiSelectFilter = React.forwardRef(
|
|
|
150
139
|
{ ...variant, maxHeight, maxWidth },
|
|
151
140
|
{ viewport }
|
|
152
141
|
)
|
|
142
|
+
const dropdownTokens = {
|
|
143
|
+
borderColor: buttonBorderColor,
|
|
144
|
+
iconSize: buttonIconSize,
|
|
145
|
+
iconPadding: buttonIconPadding,
|
|
146
|
+
lineHeight: labelLineHeight,
|
|
147
|
+
fontName: labelFontName,
|
|
148
|
+
fontSize: labelFontSize,
|
|
149
|
+
fontWeight: labelFontWeight,
|
|
150
|
+
color: labelColor,
|
|
151
|
+
paddingTop: labelPaddingTop,
|
|
152
|
+
paddingBottom: labelPaddingBottom,
|
|
153
|
+
paddingLeft: labelPaddingLeft,
|
|
154
|
+
paddingRight: labelPaddingRight
|
|
155
|
+
}
|
|
156
|
+
const getButtonDropdownTokens = useThemeTokensCallback(
|
|
157
|
+
'ButtonDropdown',
|
|
158
|
+
dropdownTokens,
|
|
159
|
+
variant
|
|
160
|
+
)
|
|
161
|
+
const getButtonTokens = (buttonState) =>
|
|
162
|
+
selectTokens('ButtonDropdown', getButtonDropdownTokens(buttonState))
|
|
163
|
+
const getCopy = useCopy({ dictionary, copy })
|
|
164
|
+
const colSizeNotMobile = items.length > rowLimit ? 2 : 1
|
|
165
|
+
const colSize = viewport !== 'xs' ? colSizeNotMobile : 1
|
|
166
|
+
const itemsLengthNotMobile = items.length > 24 ? items.length / 2 : rowLimit
|
|
167
|
+
const isSelected = currentValues.length > 0
|
|
168
|
+
const rowLength = viewport !== 'xs' ? itemsLengthNotMobile : items.length
|
|
169
|
+
|
|
170
|
+
React.useEffect(() => {
|
|
171
|
+
if (colSize === 1) return setMaxWidth(false)
|
|
172
|
+
return colSize === 2 && setMaxWidth(true)
|
|
173
|
+
}, [colSize])
|
|
174
|
+
|
|
175
|
+
React.useEffect(() => setCheckedIds(currentValues ?? []), [currentValues])
|
|
153
176
|
|
|
154
177
|
const uniqueFields = ['id', 'label']
|
|
155
178
|
if (!containUniqueFields(items, uniqueFields)) {
|
|
@@ -199,7 +222,7 @@ const MultiSelectFilter = React.forwardRef(
|
|
|
199
222
|
const subeHeaderStyles = applyTextStyles({
|
|
200
223
|
fontSize: subHeaderFontSize,
|
|
201
224
|
fontWeight: subHeaderFontWeight,
|
|
202
|
-
fontColor:
|
|
225
|
+
fontColor: subtitleColor
|
|
203
226
|
})
|
|
204
227
|
|
|
205
228
|
const { overlaidPosition, onTargetLayout, isReady, sourceRef } = useOverlaidPosition({
|
|
@@ -275,7 +298,12 @@ const MultiSelectFilter = React.forwardRef(
|
|
|
275
298
|
const controlsContent = (
|
|
276
299
|
<>
|
|
277
300
|
{isScrolling ? (
|
|
278
|
-
<Divider
|
|
301
|
+
<Divider
|
|
302
|
+
tokens={{
|
|
303
|
+
color: dividerColor
|
|
304
|
+
}}
|
|
305
|
+
space={4}
|
|
306
|
+
/>
|
|
279
307
|
) : (
|
|
280
308
|
<Spacer space={4} />
|
|
281
309
|
)}
|