@telus-uds/components-base 3.28.1 → 3.28.2
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 +10 -1
- package/lib/cjs/Autocomplete/Autocomplete.js +86 -32
- package/lib/cjs/Autocomplete/constants.js +2 -1
- package/lib/cjs/Carousel/Carousel.js +1 -2
- package/lib/cjs/Listbox/ListboxOverlay.js +7 -1
- package/lib/cjs/Listbox/PressableItem.js +2 -2
- package/lib/cjs/TextInput/TextInputBase.js +2 -2
- package/lib/esm/Autocomplete/Autocomplete.js +87 -33
- package/lib/esm/Autocomplete/constants.js +1 -0
- package/lib/esm/Carousel/Carousel.js +1 -2
- package/lib/esm/Listbox/ListboxOverlay.js +7 -1
- package/lib/esm/Listbox/PressableItem.js +3 -3
- package/lib/esm/TextInput/TextInputBase.js +2 -2
- package/lib/package.json +1 -1
- package/package.json +1 -1
- package/src/Autocomplete/Autocomplete.jsx +142 -77
- package/src/Autocomplete/constants.js +1 -0
- package/src/Carousel/Carousel.jsx +1 -2
- package/src/Listbox/ListboxOverlay.jsx +9 -1
- package/src/Listbox/PressableItem.jsx +1 -1
- package/src/TextInput/TextInputBase.jsx +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
# Change Log - @telus-uds/components-base
|
|
2
2
|
|
|
3
|
-
This log was last generated on
|
|
3
|
+
This log was last generated on Tue, 03 Mar 2026 23:02:55 GMT and should not be manually modified.
|
|
4
4
|
|
|
5
5
|
<!-- Start content -->
|
|
6
6
|
|
|
7
|
+
## 3.28.2
|
|
8
|
+
|
|
9
|
+
Tue, 03 Mar 2026 23:02:55 GMT
|
|
10
|
+
|
|
11
|
+
### Patches
|
|
12
|
+
|
|
13
|
+
- `Carousel`: inverse variant navigation arrows fixed by always using raised style even in the inverse state (josue.higueros@telus.com)
|
|
14
|
+
- `Autocomplete`: add the ability to show all values and filter them (josue.higueroscalderon@telus.com)
|
|
15
|
+
|
|
7
16
|
## 3.28.1
|
|
8
17
|
|
|
9
18
|
Fri, 20 Feb 2026 23:53:11 GMT
|
|
@@ -51,22 +51,36 @@ const highlightAllMatches = function (str) {
|
|
|
51
51
|
tokens: {
|
|
52
52
|
color: resultsTextColor
|
|
53
53
|
},
|
|
54
|
-
children: matchIndexes.reduce((acc, matchIndex, index) =>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
54
|
+
children: matchIndexes.reduce((acc, matchIndex, index) => {
|
|
55
|
+
const prefix = index === 0 ? str.slice(0, matchIndex) : null;
|
|
56
|
+
const match = str.slice(matchIndex, matchIndex + substring.length);
|
|
57
|
+
const suffix = str.slice(matchIndex + substring.length, matchIndexes[index + 1] ?? str.length);
|
|
58
|
+
return [...acc, prefix ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
|
|
59
|
+
variant: {
|
|
60
|
+
bold: false
|
|
61
|
+
},
|
|
62
|
+
tokens: {
|
|
63
|
+
color: resultsTextColor
|
|
64
|
+
},
|
|
65
|
+
children: prefix
|
|
66
|
+
}, `pre-${matchIndex}`) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
|
|
67
|
+
variant: {
|
|
68
|
+
bold: true
|
|
69
|
+
},
|
|
70
|
+
tokens: {
|
|
71
|
+
color: resultsTextColor
|
|
72
|
+
},
|
|
73
|
+
children: match
|
|
74
|
+
}, matchIndex), suffix ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
|
|
75
|
+
variant: {
|
|
76
|
+
bold: false
|
|
77
|
+
},
|
|
78
|
+
tokens: {
|
|
79
|
+
color: resultsTextColor
|
|
80
|
+
},
|
|
81
|
+
children: suffix
|
|
82
|
+
}, `post-${matchIndex}`) : null];
|
|
83
|
+
}, []).filter(Boolean)
|
|
70
84
|
})
|
|
71
85
|
);
|
|
72
86
|
};
|
|
@@ -100,12 +114,14 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
100
114
|
isLoading = false,
|
|
101
115
|
items,
|
|
102
116
|
maxSuggestions = _constants.DEFAULT_MAX_SUGGESTIONS,
|
|
117
|
+
maxDropdownHeight = _constants.DEFAULT_MAX_DROPDOWN_HEIGHT,
|
|
103
118
|
minToSuggestion = _constants.DEFAULT_MIN_TO_SUGGESTION,
|
|
104
119
|
noResults,
|
|
105
120
|
onChange,
|
|
106
121
|
onClear,
|
|
107
122
|
onSelect,
|
|
108
123
|
readOnly,
|
|
124
|
+
showOptionsOnFocus = false,
|
|
109
125
|
validation,
|
|
110
126
|
value,
|
|
111
127
|
helpText = '',
|
|
@@ -154,7 +170,7 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
154
170
|
hint,
|
|
155
171
|
label: inputLabel
|
|
156
172
|
} = supportsProps;
|
|
157
|
-
const hintExpansionEnabled = isFocused && helpText && !currentValue;
|
|
173
|
+
const hintExpansionEnabled = isFocused && !!helpText && !currentValue;
|
|
158
174
|
const {
|
|
159
175
|
overlaidPosition,
|
|
160
176
|
sourceRef: inputRef,
|
|
@@ -208,9 +224,10 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
208
224
|
}
|
|
209
225
|
};
|
|
210
226
|
const handleChange = newValue => {
|
|
211
|
-
onChange?.(newValue
|
|
227
|
+
onChange?.(newValue);
|
|
212
228
|
setCurrentValue(newValue);
|
|
213
|
-
|
|
229
|
+
const shouldExpand = newValue?.length >= minToSuggestion || showOptionsOnFocus && isFocused && newValue?.length === 0;
|
|
230
|
+
setIsExpanded(shouldExpand);
|
|
214
231
|
if (!isControlled && initialItems !== undefined) {
|
|
215
232
|
setCurrentItems(initialItems.filter(_ref3 => {
|
|
216
233
|
let {
|
|
@@ -222,25 +239,29 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
222
239
|
};
|
|
223
240
|
const handleSelect = selectedId => {
|
|
224
241
|
onSelect?.(selectedId);
|
|
225
|
-
const {
|
|
226
|
-
label: newValue,
|
|
227
|
-
nested,
|
|
228
|
-
title
|
|
229
|
-
} = (isControlled ? items : currentItems)?.find(_ref4 => {
|
|
242
|
+
const selectedItem = (isControlled ? items : currentItems)?.find(_ref4 => {
|
|
230
243
|
let {
|
|
231
244
|
id
|
|
232
245
|
} = _ref4;
|
|
233
246
|
return id === selectedId;
|
|
234
247
|
});
|
|
248
|
+
const {
|
|
249
|
+
label,
|
|
250
|
+
nested,
|
|
251
|
+
title
|
|
252
|
+
} = selectedItem;
|
|
235
253
|
if (title) return;
|
|
236
254
|
if (!nested) {
|
|
237
255
|
setNestedSelectedValue(null);
|
|
238
|
-
onChange?.(
|
|
256
|
+
onChange?.(label);
|
|
239
257
|
setIsExpanded(false);
|
|
258
|
+
setCurrentValue(label);
|
|
259
|
+
}
|
|
260
|
+
if (!isControlled && inputRef?.current) inputRef.current.value = label;
|
|
261
|
+
if (nested) {
|
|
262
|
+
setNestedSelectedValue(label);
|
|
263
|
+
setCurrentValue(label);
|
|
240
264
|
}
|
|
241
|
-
setCurrentValue(newValue);
|
|
242
|
-
if (!isControlled && inputRef?.current) inputRef.current.value = newValue;
|
|
243
|
-
if (nested) setNestedSelectedValue(newValue);
|
|
244
265
|
inputRef.current.focus();
|
|
245
266
|
};
|
|
246
267
|
|
|
@@ -288,15 +309,33 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
288
309
|
};
|
|
289
310
|
}, [inputRef]);
|
|
290
311
|
const handleClose = event => {
|
|
291
|
-
if (event.type === 'keydown' && (event.key === 'Escape' || event.key === '27')
|
|
312
|
+
if (event.type === 'keydown' && (event.key === 'Escape' || event.key === '27')) {
|
|
292
313
|
setIsExpanded(false);
|
|
293
314
|
setNestedSelectedValue(null);
|
|
294
|
-
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (event.type === 'keydown' && (event.key === 'ArrowDown' || event.key === 'Tab') && isExpanded && !isLoading && targetRef?.current) {
|
|
295
318
|
event.preventDefault();
|
|
296
319
|
targetRef.current.focus();
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (event.type === 'click' || event.type === 'touchstart') {
|
|
323
|
+
const clickTarget = event.type === 'click' ? event.target : event.touches[0]?.target;
|
|
324
|
+
const isOutsideOverlay = openOverlayRef?.current && !openOverlayRef.current.contains(clickTarget);
|
|
325
|
+
const isOutsideInput = inputRef?.current && !inputRef.current.contains(clickTarget);
|
|
326
|
+
if (isOutsideOverlay && isOutsideInput) {
|
|
327
|
+
setIsExpanded(false);
|
|
328
|
+
setNestedSelectedValue(null);
|
|
329
|
+
}
|
|
297
330
|
}
|
|
298
331
|
};
|
|
299
|
-
|
|
332
|
+
// Calculate items to show based on current state
|
|
333
|
+
let itemsToShow = [];
|
|
334
|
+
if (currentValue?.length > 0) {
|
|
335
|
+
itemsToShow = itemsToSuggest(highlight(isControlled ? items : currentItems, currentValue, resultsTextColor));
|
|
336
|
+
} else if (showOptionsOnFocus && isFocused) {
|
|
337
|
+
itemsToShow = itemsToSuggest(isControlled ? items : currentItems || initialItems);
|
|
338
|
+
}
|
|
300
339
|
const helpTextToShow = isFocused && !currentValue ? helpText : noResults ?? getCopy('noResults');
|
|
301
340
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
|
|
302
341
|
style: staticStyles.container,
|
|
@@ -333,9 +372,15 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
333
372
|
onChange: handleChange,
|
|
334
373
|
onFocus: () => {
|
|
335
374
|
setisFocused(true);
|
|
375
|
+
if (showOptionsOnFocus && (!currentValue || currentValue.length === 0)) {
|
|
376
|
+
setIsExpanded(true);
|
|
377
|
+
}
|
|
336
378
|
},
|
|
337
379
|
onBlur: () => {
|
|
338
380
|
setisFocused(false);
|
|
381
|
+
if (showOptionsOnFocus && (!currentValue || currentValue.length === 0)) {
|
|
382
|
+
setIsExpanded(false);
|
|
383
|
+
}
|
|
339
384
|
},
|
|
340
385
|
onClear: onClear,
|
|
341
386
|
onKeyPress: handleClose,
|
|
@@ -367,12 +412,13 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
367
412
|
})
|
|
368
413
|
});
|
|
369
414
|
}
|
|
370
|
-
}), (isExpanded || hintExpansionEnabled) && isInputVisible && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
415
|
+
}), (isExpanded || hintExpansionEnabled) && isInputVisible && (itemsToShow.length > 0 || isExpanded || hintExpansionEnabled) && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
371
416
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Listbox.default.Overlay, {
|
|
372
417
|
overlaidPosition: overlaidPosition,
|
|
373
418
|
isReady: isReady,
|
|
374
419
|
minWidth: fullWidth ? inputWidth : _constants.MIN_LISTBOX_WIDTH,
|
|
375
420
|
maxWidth: inputWidth,
|
|
421
|
+
maxHeight: maxDropdownHeight,
|
|
376
422
|
onLayout: handleMeasure,
|
|
377
423
|
tokens: restOfTokens,
|
|
378
424
|
ref: openOverlayRef,
|
|
@@ -456,6 +502,10 @@ Autocomplete.propTypes = {
|
|
|
456
502
|
* Maximum number of suggestions provided at the same time
|
|
457
503
|
*/
|
|
458
504
|
maxSuggestions: _propTypes.default.number,
|
|
505
|
+
/**
|
|
506
|
+
* Maximum height (in pixels) of the dropdown before scrolling is enabled
|
|
507
|
+
*/
|
|
508
|
+
maxDropdownHeight: _propTypes.default.number,
|
|
459
509
|
/**
|
|
460
510
|
* Text or JSX to render when no results are available
|
|
461
511
|
*/
|
|
@@ -476,6 +526,10 @@ Autocomplete.propTypes = {
|
|
|
476
526
|
* Callback function to be called when an item is selected from the list
|
|
477
527
|
*/
|
|
478
528
|
onSelect: _propTypes.default.func,
|
|
529
|
+
/**
|
|
530
|
+
* When true, displays all available options when the input receives focus (even without typing)
|
|
531
|
+
*/
|
|
532
|
+
showOptionsOnFocus: _propTypes.default.bool,
|
|
479
533
|
/**
|
|
480
534
|
* Input value for controlled usage
|
|
481
535
|
*/
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.MIN_LISTBOX_WIDTH = exports.INPUT_LEFT_PADDING = exports.DEFAULT_MIN_TO_SUGGESTION = exports.DEFAULT_MAX_SUGGESTIONS = void 0;
|
|
6
|
+
exports.MIN_LISTBOX_WIDTH = exports.INPUT_LEFT_PADDING = exports.DEFAULT_MIN_TO_SUGGESTION = exports.DEFAULT_MAX_SUGGESTIONS = exports.DEFAULT_MAX_DROPDOWN_HEIGHT = void 0;
|
|
7
7
|
const DEFAULT_MIN_TO_SUGGESTION = exports.DEFAULT_MIN_TO_SUGGESTION = 1;
|
|
8
8
|
const DEFAULT_MAX_SUGGESTIONS = exports.DEFAULT_MAX_SUGGESTIONS = 5;
|
|
9
|
+
const DEFAULT_MAX_DROPDOWN_HEIGHT = exports.DEFAULT_MAX_DROPDOWN_HEIGHT = 336; // Approximately 7 items (48px each)
|
|
9
10
|
const INPUT_LEFT_PADDING = exports.INPUT_LEFT_PADDING = 16;
|
|
10
11
|
const MIN_LISTBOX_WIDTH = exports.MIN_LISTBOX_WIDTH = 288;
|
|
@@ -924,8 +924,7 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
|
|
|
924
924
|
// Related discussion - https://github.com/telus/universal-design-system/issues/1549
|
|
925
925
|
const previousNextIconButtonVariants = {
|
|
926
926
|
size: previousNextIconSize,
|
|
927
|
-
raised:
|
|
928
|
-
inverse: variant?.inverse
|
|
927
|
+
raised: true
|
|
929
928
|
};
|
|
930
929
|
const getCopyWithPlaceholders = _react.default.useCallback(copyKey => {
|
|
931
930
|
const copyText = getCopy(copyKey).replace(/%\{title\}/g, title).replace(/%\{itemLabel\}/g, itemLabel).replace(/%\{stepNumber\}/g, activeIndex + 1).replace(/%\{stepCount\}/g, totalItems);
|
|
@@ -35,6 +35,7 @@ const DropdownOverlay = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
|
35
35
|
isReady = false,
|
|
36
36
|
overlaidPosition,
|
|
37
37
|
maxWidth,
|
|
38
|
+
maxHeight,
|
|
38
39
|
minWidth,
|
|
39
40
|
onLayout,
|
|
40
41
|
tokens,
|
|
@@ -50,12 +51,16 @@ const DropdownOverlay = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
|
50
51
|
maxWidth,
|
|
51
52
|
minWidth
|
|
52
53
|
}, staticStyles.positioner, !isReady && staticStyles.hidden],
|
|
54
|
+
onMouseDown: e => {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
},
|
|
53
57
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Card.default, {
|
|
54
58
|
tokens: {
|
|
55
59
|
shadow: systemTokens.shadow,
|
|
56
60
|
borderRadius: systemTokens.borderRadius,
|
|
57
61
|
...(_Platform.default.OS === 'web' && {
|
|
58
|
-
|
|
62
|
+
maxHeight,
|
|
63
|
+
overflowY: 'auto'
|
|
59
64
|
}),
|
|
60
65
|
paddingBottom: paddingVertical,
|
|
61
66
|
paddingTop: paddingVertical,
|
|
@@ -85,6 +90,7 @@ DropdownOverlay.propTypes = {
|
|
|
85
90
|
width: _propTypes.default.number
|
|
86
91
|
}),
|
|
87
92
|
maxWidth: _propTypes.default.number,
|
|
93
|
+
maxHeight: _propTypes.default.number,
|
|
88
94
|
minWidth: _propTypes.default.number,
|
|
89
95
|
onLayout: _propTypes.default.func,
|
|
90
96
|
tokens: _propTypes.default.object,
|
|
@@ -129,9 +129,9 @@ const PressableItem = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
|
|
|
129
129
|
onPress(event);
|
|
130
130
|
},
|
|
131
131
|
children: pressableState => {
|
|
132
|
-
return /*#__PURE__*/(0, _jsxRuntime.
|
|
132
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
|
|
133
133
|
style: selectTextStyles(resolveButtonTokens(pressableState)),
|
|
134
|
-
children:
|
|
134
|
+
children: children
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
});
|
|
@@ -278,8 +278,8 @@ const TextInputBase = /*#__PURE__*/_react.default.forwardRef((_ref8, ref) => {
|
|
|
278
278
|
}
|
|
279
279
|
}, [element, pattern]);
|
|
280
280
|
const handleChangeText = event => {
|
|
281
|
-
const text = event.nativeEvent?.text
|
|
282
|
-
let filteredText = isNumeric ? text?.replace(/[^\d]/g, '') : text;
|
|
281
|
+
const text = event.nativeEvent?.text ?? event.target?.value;
|
|
282
|
+
let filteredText = isNumeric ? text?.replace(/[^\d]/g, '') || undefined : text;
|
|
283
283
|
if (type === 'card' && filteredText) {
|
|
284
284
|
const formattedValue = filteredText.replace(/[^a-zA-Z0-9]/g, '');
|
|
285
285
|
const regex = new RegExp(`([a-zA-Z0-9]{4})(?=[a-zA-Z0-9])`, 'g');
|
|
@@ -14,7 +14,7 @@ import { TextInput } from '../TextInput';
|
|
|
14
14
|
import InputSupports from '../InputSupports';
|
|
15
15
|
import Loading from './Loading';
|
|
16
16
|
import Suggestions from './Suggestions';
|
|
17
|
-
import { DEFAULT_MAX_SUGGESTIONS, DEFAULT_MIN_TO_SUGGESTION, INPUT_LEFT_PADDING, MIN_LISTBOX_WIDTH } from './constants';
|
|
17
|
+
import { DEFAULT_MAX_SUGGESTIONS, DEFAULT_MIN_TO_SUGGESTION, DEFAULT_MAX_DROPDOWN_HEIGHT, INPUT_LEFT_PADDING, MIN_LISTBOX_WIDTH } from './constants';
|
|
18
18
|
import dictionary from './dictionary';
|
|
19
19
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
20
20
|
const staticStyles = StyleSheet.create({
|
|
@@ -44,22 +44,36 @@ const highlightAllMatches = function (str) {
|
|
|
44
44
|
tokens: {
|
|
45
45
|
color: resultsTextColor
|
|
46
46
|
},
|
|
47
|
-
children: matchIndexes.reduce((acc, matchIndex, index) =>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
47
|
+
children: matchIndexes.reduce((acc, matchIndex, index) => {
|
|
48
|
+
const prefix = index === 0 ? str.slice(0, matchIndex) : null;
|
|
49
|
+
const match = str.slice(matchIndex, matchIndex + substring.length);
|
|
50
|
+
const suffix = str.slice(matchIndex + substring.length, matchIndexes[index + 1] ?? str.length);
|
|
51
|
+
return [...acc, prefix ? /*#__PURE__*/_jsx(Typography, {
|
|
52
|
+
variant: {
|
|
53
|
+
bold: false
|
|
54
|
+
},
|
|
55
|
+
tokens: {
|
|
56
|
+
color: resultsTextColor
|
|
57
|
+
},
|
|
58
|
+
children: prefix
|
|
59
|
+
}, `pre-${matchIndex}`) : null, /*#__PURE__*/_jsx(Typography, {
|
|
60
|
+
variant: {
|
|
61
|
+
bold: true
|
|
62
|
+
},
|
|
63
|
+
tokens: {
|
|
64
|
+
color: resultsTextColor
|
|
65
|
+
},
|
|
66
|
+
children: match
|
|
67
|
+
}, matchIndex), suffix ? /*#__PURE__*/_jsx(Typography, {
|
|
68
|
+
variant: {
|
|
69
|
+
bold: false
|
|
70
|
+
},
|
|
71
|
+
tokens: {
|
|
72
|
+
color: resultsTextColor
|
|
73
|
+
},
|
|
74
|
+
children: suffix
|
|
75
|
+
}, `post-${matchIndex}`) : null];
|
|
76
|
+
}, []).filter(Boolean)
|
|
63
77
|
})
|
|
64
78
|
);
|
|
65
79
|
};
|
|
@@ -93,12 +107,14 @@ const Autocomplete = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
93
107
|
isLoading = false,
|
|
94
108
|
items,
|
|
95
109
|
maxSuggestions = DEFAULT_MAX_SUGGESTIONS,
|
|
110
|
+
maxDropdownHeight = DEFAULT_MAX_DROPDOWN_HEIGHT,
|
|
96
111
|
minToSuggestion = DEFAULT_MIN_TO_SUGGESTION,
|
|
97
112
|
noResults,
|
|
98
113
|
onChange,
|
|
99
114
|
onClear,
|
|
100
115
|
onSelect,
|
|
101
116
|
readOnly,
|
|
117
|
+
showOptionsOnFocus = false,
|
|
102
118
|
validation,
|
|
103
119
|
value,
|
|
104
120
|
helpText = '',
|
|
@@ -147,7 +163,7 @@ const Autocomplete = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
147
163
|
hint,
|
|
148
164
|
label: inputLabel
|
|
149
165
|
} = supportsProps;
|
|
150
|
-
const hintExpansionEnabled = isFocused && helpText && !currentValue;
|
|
166
|
+
const hintExpansionEnabled = isFocused && !!helpText && !currentValue;
|
|
151
167
|
const {
|
|
152
168
|
overlaidPosition,
|
|
153
169
|
sourceRef: inputRef,
|
|
@@ -201,9 +217,10 @@ const Autocomplete = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
201
217
|
}
|
|
202
218
|
};
|
|
203
219
|
const handleChange = newValue => {
|
|
204
|
-
onChange?.(newValue
|
|
220
|
+
onChange?.(newValue);
|
|
205
221
|
setCurrentValue(newValue);
|
|
206
|
-
|
|
222
|
+
const shouldExpand = newValue?.length >= minToSuggestion || showOptionsOnFocus && isFocused && newValue?.length === 0;
|
|
223
|
+
setIsExpanded(shouldExpand);
|
|
207
224
|
if (!isControlled && initialItems !== undefined) {
|
|
208
225
|
setCurrentItems(initialItems.filter(_ref3 => {
|
|
209
226
|
let {
|
|
@@ -215,25 +232,29 @@ const Autocomplete = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
215
232
|
};
|
|
216
233
|
const handleSelect = selectedId => {
|
|
217
234
|
onSelect?.(selectedId);
|
|
218
|
-
const {
|
|
219
|
-
label: newValue,
|
|
220
|
-
nested,
|
|
221
|
-
title
|
|
222
|
-
} = (isControlled ? items : currentItems)?.find(_ref4 => {
|
|
235
|
+
const selectedItem = (isControlled ? items : currentItems)?.find(_ref4 => {
|
|
223
236
|
let {
|
|
224
237
|
id
|
|
225
238
|
} = _ref4;
|
|
226
239
|
return id === selectedId;
|
|
227
240
|
});
|
|
241
|
+
const {
|
|
242
|
+
label,
|
|
243
|
+
nested,
|
|
244
|
+
title
|
|
245
|
+
} = selectedItem;
|
|
228
246
|
if (title) return;
|
|
229
247
|
if (!nested) {
|
|
230
248
|
setNestedSelectedValue(null);
|
|
231
|
-
onChange?.(
|
|
249
|
+
onChange?.(label);
|
|
232
250
|
setIsExpanded(false);
|
|
251
|
+
setCurrentValue(label);
|
|
252
|
+
}
|
|
253
|
+
if (!isControlled && inputRef?.current) inputRef.current.value = label;
|
|
254
|
+
if (nested) {
|
|
255
|
+
setNestedSelectedValue(label);
|
|
256
|
+
setCurrentValue(label);
|
|
233
257
|
}
|
|
234
|
-
setCurrentValue(newValue);
|
|
235
|
-
if (!isControlled && inputRef?.current) inputRef.current.value = newValue;
|
|
236
|
-
if (nested) setNestedSelectedValue(newValue);
|
|
237
258
|
inputRef.current.focus();
|
|
238
259
|
};
|
|
239
260
|
|
|
@@ -281,15 +302,33 @@ const Autocomplete = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
281
302
|
};
|
|
282
303
|
}, [inputRef]);
|
|
283
304
|
const handleClose = event => {
|
|
284
|
-
if (event.type === 'keydown' && (event.key === 'Escape' || event.key === '27')
|
|
305
|
+
if (event.type === 'keydown' && (event.key === 'Escape' || event.key === '27')) {
|
|
285
306
|
setIsExpanded(false);
|
|
286
307
|
setNestedSelectedValue(null);
|
|
287
|
-
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (event.type === 'keydown' && (event.key === 'ArrowDown' || event.key === 'Tab') && isExpanded && !isLoading && targetRef?.current) {
|
|
288
311
|
event.preventDefault();
|
|
289
312
|
targetRef.current.focus();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (event.type === 'click' || event.type === 'touchstart') {
|
|
316
|
+
const clickTarget = event.type === 'click' ? event.target : event.touches[0]?.target;
|
|
317
|
+
const isOutsideOverlay = openOverlayRef?.current && !openOverlayRef.current.contains(clickTarget);
|
|
318
|
+
const isOutsideInput = inputRef?.current && !inputRef.current.contains(clickTarget);
|
|
319
|
+
if (isOutsideOverlay && isOutsideInput) {
|
|
320
|
+
setIsExpanded(false);
|
|
321
|
+
setNestedSelectedValue(null);
|
|
322
|
+
}
|
|
290
323
|
}
|
|
291
324
|
};
|
|
292
|
-
|
|
325
|
+
// Calculate items to show based on current state
|
|
326
|
+
let itemsToShow = [];
|
|
327
|
+
if (currentValue?.length > 0) {
|
|
328
|
+
itemsToShow = itemsToSuggest(highlight(isControlled ? items : currentItems, currentValue, resultsTextColor));
|
|
329
|
+
} else if (showOptionsOnFocus && isFocused) {
|
|
330
|
+
itemsToShow = itemsToSuggest(isControlled ? items : currentItems || initialItems);
|
|
331
|
+
}
|
|
293
332
|
const helpTextToShow = isFocused && !currentValue ? helpText : noResults ?? getCopy('noResults');
|
|
294
333
|
return /*#__PURE__*/_jsxs(View, {
|
|
295
334
|
style: staticStyles.container,
|
|
@@ -326,9 +365,15 @@ const Autocomplete = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
326
365
|
onChange: handleChange,
|
|
327
366
|
onFocus: () => {
|
|
328
367
|
setisFocused(true);
|
|
368
|
+
if (showOptionsOnFocus && (!currentValue || currentValue.length === 0)) {
|
|
369
|
+
setIsExpanded(true);
|
|
370
|
+
}
|
|
329
371
|
},
|
|
330
372
|
onBlur: () => {
|
|
331
373
|
setisFocused(false);
|
|
374
|
+
if (showOptionsOnFocus && (!currentValue || currentValue.length === 0)) {
|
|
375
|
+
setIsExpanded(false);
|
|
376
|
+
}
|
|
332
377
|
},
|
|
333
378
|
onClear: onClear,
|
|
334
379
|
onKeyPress: handleClose,
|
|
@@ -360,12 +405,13 @@ const Autocomplete = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
360
405
|
})
|
|
361
406
|
});
|
|
362
407
|
}
|
|
363
|
-
}), (isExpanded || hintExpansionEnabled) && isInputVisible && /*#__PURE__*/_jsxs(_Fragment, {
|
|
408
|
+
}), (isExpanded || hintExpansionEnabled) && isInputVisible && (itemsToShow.length > 0 || isExpanded || hintExpansionEnabled) && /*#__PURE__*/_jsxs(_Fragment, {
|
|
364
409
|
children: [/*#__PURE__*/_jsx(Listbox.Overlay, {
|
|
365
410
|
overlaidPosition: overlaidPosition,
|
|
366
411
|
isReady: isReady,
|
|
367
412
|
minWidth: fullWidth ? inputWidth : MIN_LISTBOX_WIDTH,
|
|
368
413
|
maxWidth: inputWidth,
|
|
414
|
+
maxHeight: maxDropdownHeight,
|
|
369
415
|
onLayout: handleMeasure,
|
|
370
416
|
tokens: restOfTokens,
|
|
371
417
|
ref: openOverlayRef,
|
|
@@ -449,6 +495,10 @@ Autocomplete.propTypes = {
|
|
|
449
495
|
* Maximum number of suggestions provided at the same time
|
|
450
496
|
*/
|
|
451
497
|
maxSuggestions: PropTypes.number,
|
|
498
|
+
/**
|
|
499
|
+
* Maximum height (in pixels) of the dropdown before scrolling is enabled
|
|
500
|
+
*/
|
|
501
|
+
maxDropdownHeight: PropTypes.number,
|
|
452
502
|
/**
|
|
453
503
|
* Text or JSX to render when no results are available
|
|
454
504
|
*/
|
|
@@ -469,6 +519,10 @@ Autocomplete.propTypes = {
|
|
|
469
519
|
* Callback function to be called when an item is selected from the list
|
|
470
520
|
*/
|
|
471
521
|
onSelect: PropTypes.func,
|
|
522
|
+
/**
|
|
523
|
+
* When true, displays all available options when the input receives focus (even without typing)
|
|
524
|
+
*/
|
|
525
|
+
showOptionsOnFocus: PropTypes.bool,
|
|
472
526
|
/**
|
|
473
527
|
* Input value for controlled usage
|
|
474
528
|
*/
|
|
@@ -917,8 +917,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
917
917
|
// Related discussion - https://github.com/telus/universal-design-system/issues/1549
|
|
918
918
|
const previousNextIconButtonVariants = {
|
|
919
919
|
size: previousNextIconSize,
|
|
920
|
-
raised:
|
|
921
|
-
inverse: variant?.inverse
|
|
920
|
+
raised: true
|
|
922
921
|
};
|
|
923
922
|
const getCopyWithPlaceholders = React.useCallback(copyKey => {
|
|
924
923
|
const copyText = getCopy(copyKey).replace(/%\{title\}/g, title).replace(/%\{itemLabel\}/g, itemLabel).replace(/%\{stepNumber\}/g, activeIndex + 1).replace(/%\{stepCount\}/g, totalItems);
|
|
@@ -28,6 +28,7 @@ const DropdownOverlay = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
28
28
|
isReady = false,
|
|
29
29
|
overlaidPosition,
|
|
30
30
|
maxWidth,
|
|
31
|
+
maxHeight,
|
|
31
32
|
minWidth,
|
|
32
33
|
onLayout,
|
|
33
34
|
tokens,
|
|
@@ -43,12 +44,16 @@ const DropdownOverlay = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
43
44
|
maxWidth,
|
|
44
45
|
minWidth
|
|
45
46
|
}, staticStyles.positioner, !isReady && staticStyles.hidden],
|
|
47
|
+
onMouseDown: e => {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
},
|
|
46
50
|
children: /*#__PURE__*/_jsx(Card, {
|
|
47
51
|
tokens: {
|
|
48
52
|
shadow: systemTokens.shadow,
|
|
49
53
|
borderRadius: systemTokens.borderRadius,
|
|
50
54
|
...(Platform.OS === 'web' && {
|
|
51
|
-
|
|
55
|
+
maxHeight,
|
|
56
|
+
overflowY: 'auto'
|
|
52
57
|
}),
|
|
53
58
|
paddingBottom: paddingVertical,
|
|
54
59
|
paddingTop: paddingVertical,
|
|
@@ -78,6 +83,7 @@ DropdownOverlay.propTypes = {
|
|
|
78
83
|
width: PropTypes.number
|
|
79
84
|
}),
|
|
80
85
|
maxWidth: PropTypes.number,
|
|
86
|
+
maxHeight: PropTypes.number,
|
|
81
87
|
minWidth: PropTypes.number,
|
|
82
88
|
onLayout: PropTypes.func,
|
|
83
89
|
tokens: PropTypes.object,
|
|
@@ -4,7 +4,7 @@ import Pressable from "react-native-web/dist/exports/Pressable";
|
|
|
4
4
|
import Text from "react-native-web/dist/exports/Text";
|
|
5
5
|
import { selectSystemProps, resolvePressableTokens, htmlAttrs } from '../utils';
|
|
6
6
|
import { useListboxContext } from './ListboxContext';
|
|
7
|
-
import {
|
|
7
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
8
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs]);
|
|
9
9
|
const getItemStyles = _ref => {
|
|
10
10
|
let {
|
|
@@ -122,9 +122,9 @@ const PressableItem = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
|
|
|
122
122
|
onPress(event);
|
|
123
123
|
},
|
|
124
124
|
children: pressableState => {
|
|
125
|
-
return /*#__PURE__*/
|
|
125
|
+
return /*#__PURE__*/_jsx(Text, {
|
|
126
126
|
style: selectTextStyles(resolveButtonTokens(pressableState)),
|
|
127
|
-
children:
|
|
127
|
+
children: children
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
130
|
});
|
|
@@ -271,8 +271,8 @@ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref8, ref) => {
|
|
|
271
271
|
}
|
|
272
272
|
}, [element, pattern]);
|
|
273
273
|
const handleChangeText = event => {
|
|
274
|
-
const text = event.nativeEvent?.text
|
|
275
|
-
let filteredText = isNumeric ? text?.replace(/[^\d]/g, '') : text;
|
|
274
|
+
const text = event.nativeEvent?.text ?? event.target?.value;
|
|
275
|
+
let filteredText = isNumeric ? text?.replace(/[^\d]/g, '') || undefined : text;
|
|
276
276
|
if (type === 'card' && filteredText) {
|
|
277
277
|
const formattedValue = filteredText.replace(/[^a-zA-Z0-9]/g, '');
|
|
278
278
|
const regex = new RegExp(`([a-zA-Z0-9]{4})(?=[a-zA-Z0-9])`, 'g');
|
package/lib/package.json
CHANGED
package/package.json
CHANGED
|
@@ -24,6 +24,7 @@ import Suggestions from './Suggestions'
|
|
|
24
24
|
import {
|
|
25
25
|
DEFAULT_MAX_SUGGESTIONS,
|
|
26
26
|
DEFAULT_MIN_TO_SUGGESTION,
|
|
27
|
+
DEFAULT_MAX_DROPDOWN_HEIGHT,
|
|
27
28
|
INPUT_LEFT_PADDING,
|
|
28
29
|
MIN_LISTBOX_WIDTH
|
|
29
30
|
} from './constants'
|
|
@@ -51,20 +52,44 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
|
51
52
|
const highlightAllMatches = (str, substring = '', matchIndexes = [], resultsTextColor) => (
|
|
52
53
|
// Wrapping all in bold
|
|
53
54
|
<Typography variant={{ bold: false }} tokens={{ color: resultsTextColor }}>
|
|
54
|
-
{matchIndexes
|
|
55
|
-
(acc, matchIndex, index) =>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
{matchIndexes
|
|
56
|
+
.reduce((acc, matchIndex, index) => {
|
|
57
|
+
const prefix = index === 0 ? str.slice(0, matchIndex) : null
|
|
58
|
+
const match = str.slice(matchIndex, matchIndex + substring.length)
|
|
59
|
+
const suffix = str.slice(
|
|
60
|
+
matchIndex + substring.length,
|
|
61
|
+
matchIndexes[index + 1] ?? str.length
|
|
62
|
+
)
|
|
63
|
+
return [
|
|
64
|
+
...acc,
|
|
65
|
+
prefix ? (
|
|
66
|
+
<Typography
|
|
67
|
+
key={`pre-${matchIndex}`}
|
|
68
|
+
variant={{ bold: false }}
|
|
69
|
+
tokens={{ color: resultsTextColor }}
|
|
70
|
+
>
|
|
71
|
+
{prefix}
|
|
72
|
+
</Typography>
|
|
73
|
+
) : null,
|
|
74
|
+
<Typography
|
|
75
|
+
key={matchIndex}
|
|
76
|
+
variant={{ bold: true }}
|
|
77
|
+
tokens={{ color: resultsTextColor }}
|
|
78
|
+
>
|
|
79
|
+
{match}
|
|
80
|
+
</Typography>,
|
|
81
|
+
suffix ? (
|
|
82
|
+
<Typography
|
|
83
|
+
key={`post-${matchIndex}`}
|
|
84
|
+
variant={{ bold: false }}
|
|
85
|
+
tokens={{ color: resultsTextColor }}
|
|
86
|
+
>
|
|
87
|
+
{suffix}
|
|
88
|
+
</Typography>
|
|
89
|
+
) : null
|
|
90
|
+
]
|
|
91
|
+
}, [])
|
|
92
|
+
.filter(Boolean)}
|
|
68
93
|
</Typography>
|
|
69
94
|
)
|
|
70
95
|
const highlight = (items = [], text = '', color) =>
|
|
@@ -94,12 +119,14 @@ const Autocomplete = React.forwardRef(
|
|
|
94
119
|
isLoading = false,
|
|
95
120
|
items,
|
|
96
121
|
maxSuggestions = DEFAULT_MAX_SUGGESTIONS,
|
|
122
|
+
maxDropdownHeight = DEFAULT_MAX_DROPDOWN_HEIGHT,
|
|
97
123
|
minToSuggestion = DEFAULT_MIN_TO_SUGGESTION,
|
|
98
124
|
noResults,
|
|
99
125
|
onChange,
|
|
100
126
|
onClear,
|
|
101
127
|
onSelect,
|
|
102
128
|
readOnly,
|
|
129
|
+
showOptionsOnFocus = false,
|
|
103
130
|
validation,
|
|
104
131
|
value,
|
|
105
132
|
helpText = '',
|
|
@@ -144,7 +171,7 @@ const Autocomplete = React.forwardRef(
|
|
|
144
171
|
|
|
145
172
|
const { supportsProps, ...selectedProps } = selectProps(rest)
|
|
146
173
|
const { hint, label: inputLabel } = supportsProps
|
|
147
|
-
const hintExpansionEnabled = isFocused && helpText && !currentValue
|
|
174
|
+
const hintExpansionEnabled = isFocused && !!helpText && !currentValue
|
|
148
175
|
const {
|
|
149
176
|
overlaidPosition,
|
|
150
177
|
sourceRef: inputRef,
|
|
@@ -198,9 +225,12 @@ const Autocomplete = React.forwardRef(
|
|
|
198
225
|
}
|
|
199
226
|
|
|
200
227
|
const handleChange = (newValue) => {
|
|
201
|
-
onChange?.(newValue
|
|
228
|
+
onChange?.(newValue)
|
|
202
229
|
setCurrentValue(newValue)
|
|
203
|
-
|
|
230
|
+
const shouldExpand =
|
|
231
|
+
newValue?.length >= minToSuggestion ||
|
|
232
|
+
(showOptionsOnFocus && isFocused && newValue?.length === 0)
|
|
233
|
+
setIsExpanded(shouldExpand)
|
|
204
234
|
if (!isControlled && initialItems !== undefined) {
|
|
205
235
|
setCurrentItems(
|
|
206
236
|
initialItems.filter(({ label }) =>
|
|
@@ -211,21 +241,24 @@ const Autocomplete = React.forwardRef(
|
|
|
211
241
|
}
|
|
212
242
|
const handleSelect = (selectedId) => {
|
|
213
243
|
onSelect?.(selectedId)
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
244
|
+
const selectedItem = (isControlled ? items : currentItems)?.find(
|
|
245
|
+
({ id }) => id === selectedId
|
|
246
|
+
)
|
|
247
|
+
const { label, nested, title } = selectedItem
|
|
248
|
+
|
|
219
249
|
if (title) return
|
|
220
250
|
if (!nested) {
|
|
221
251
|
setNestedSelectedValue(null)
|
|
222
|
-
onChange?.(
|
|
252
|
+
onChange?.(label)
|
|
223
253
|
setIsExpanded(false)
|
|
254
|
+
setCurrentValue(label)
|
|
224
255
|
}
|
|
225
|
-
|
|
226
|
-
if (!isControlled && inputRef?.current) inputRef.current.value = newValue
|
|
256
|
+
if (!isControlled && inputRef?.current) inputRef.current.value = label
|
|
227
257
|
|
|
228
|
-
if (nested)
|
|
258
|
+
if (nested) {
|
|
259
|
+
setNestedSelectedValue(label)
|
|
260
|
+
setCurrentValue(label)
|
|
261
|
+
}
|
|
229
262
|
|
|
230
263
|
inputRef.current.focus()
|
|
231
264
|
}
|
|
@@ -278,17 +311,13 @@ const Autocomplete = React.forwardRef(
|
|
|
278
311
|
}, [inputRef])
|
|
279
312
|
|
|
280
313
|
const handleClose = (event) => {
|
|
281
|
-
if (
|
|
282
|
-
(event.type === 'keydown' && (event.key === 'Escape' || event.key === '27')) ||
|
|
283
|
-
(event.type === 'click' && !openOverlayRef?.current?.contains(event.target)) ||
|
|
284
|
-
(event.type === 'touchstart' &&
|
|
285
|
-
openOverlayRef?.current &&
|
|
286
|
-
event.touches[0].target &&
|
|
287
|
-
!openOverlayRef?.current?.contains(event.touches[0].target))
|
|
288
|
-
) {
|
|
314
|
+
if (event.type === 'keydown' && (event.key === 'Escape' || event.key === '27')) {
|
|
289
315
|
setIsExpanded(false)
|
|
290
316
|
setNestedSelectedValue(null)
|
|
291
|
-
|
|
317
|
+
return
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (
|
|
292
321
|
event.type === 'keydown' &&
|
|
293
322
|
(event.key === 'ArrowDown' || event.key === 'Tab') &&
|
|
294
323
|
isExpanded &&
|
|
@@ -297,13 +326,30 @@ const Autocomplete = React.forwardRef(
|
|
|
297
326
|
) {
|
|
298
327
|
event.preventDefault()
|
|
299
328
|
targetRef.current.focus()
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (event.type === 'click' || event.type === 'touchstart') {
|
|
333
|
+
const clickTarget = event.type === 'click' ? event.target : event.touches[0]?.target
|
|
334
|
+
const isOutsideOverlay =
|
|
335
|
+
openOverlayRef?.current && !openOverlayRef.current.contains(clickTarget)
|
|
336
|
+
const isOutsideInput = inputRef?.current && !inputRef.current.contains(clickTarget)
|
|
337
|
+
|
|
338
|
+
if (isOutsideOverlay && isOutsideInput) {
|
|
339
|
+
setIsExpanded(false)
|
|
340
|
+
setNestedSelectedValue(null)
|
|
341
|
+
}
|
|
300
342
|
}
|
|
301
343
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
344
|
+
// Calculate items to show based on current state
|
|
345
|
+
let itemsToShow = []
|
|
346
|
+
if (currentValue?.length > 0) {
|
|
347
|
+
itemsToShow = itemsToSuggest(
|
|
348
|
+
highlight(isControlled ? items : currentItems, currentValue, resultsTextColor)
|
|
349
|
+
)
|
|
350
|
+
} else if (showOptionsOnFocus && isFocused) {
|
|
351
|
+
itemsToShow = itemsToSuggest(isControlled ? items : currentItems || initialItems)
|
|
352
|
+
}
|
|
307
353
|
const helpTextToShow = isFocused && !currentValue ? helpText : noResults ?? getCopy('noResults')
|
|
308
354
|
|
|
309
355
|
return (
|
|
@@ -337,9 +383,15 @@ const Autocomplete = React.forwardRef(
|
|
|
337
383
|
onChange={handleChange}
|
|
338
384
|
onFocus={() => {
|
|
339
385
|
setisFocused(true)
|
|
386
|
+
if (showOptionsOnFocus && (!currentValue || currentValue.length === 0)) {
|
|
387
|
+
setIsExpanded(true)
|
|
388
|
+
}
|
|
340
389
|
}}
|
|
341
390
|
onBlur={() => {
|
|
342
391
|
setisFocused(false)
|
|
392
|
+
if (showOptionsOnFocus && (!currentValue || currentValue.length === 0)) {
|
|
393
|
+
setIsExpanded(false)
|
|
394
|
+
}
|
|
343
395
|
}}
|
|
344
396
|
onClear={onClear}
|
|
345
397
|
onKeyPress={handleClose}
|
|
@@ -368,45 +420,50 @@ const Autocomplete = React.forwardRef(
|
|
|
368
420
|
)
|
|
369
421
|
}}
|
|
370
422
|
</InputSupports>
|
|
371
|
-
{(isExpanded || hintExpansionEnabled) &&
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
423
|
+
{(isExpanded || hintExpansionEnabled) &&
|
|
424
|
+
isInputVisible &&
|
|
425
|
+
(itemsToShow.length > 0 || isExpanded || hintExpansionEnabled) && (
|
|
426
|
+
<>
|
|
427
|
+
<Listbox.Overlay
|
|
428
|
+
overlaidPosition={overlaidPosition}
|
|
429
|
+
isReady={isReady}
|
|
430
|
+
minWidth={fullWidth ? inputWidth : MIN_LISTBOX_WIDTH}
|
|
431
|
+
maxWidth={inputWidth}
|
|
432
|
+
maxHeight={maxDropdownHeight}
|
|
433
|
+
onLayout={handleMeasure}
|
|
434
|
+
tokens={restOfTokens}
|
|
435
|
+
ref={openOverlayRef}
|
|
436
|
+
>
|
|
437
|
+
{isLoading ? (
|
|
438
|
+
<Loading label={loadingLabel ?? getCopy('loading')} />
|
|
439
|
+
) : (
|
|
440
|
+
<Suggestions
|
|
441
|
+
hasResults={getCopy('hasResults')}
|
|
442
|
+
id="autocomplete"
|
|
443
|
+
items={
|
|
444
|
+
nestedSelectedValue
|
|
445
|
+
? itemsToSuggest(
|
|
446
|
+
highlight(otherItems, nestedSelectedValue, resultsTextColor)
|
|
447
|
+
)
|
|
448
|
+
: itemsToShow
|
|
449
|
+
}
|
|
450
|
+
noResults={helpTextToShow}
|
|
451
|
+
onClose={handleClose}
|
|
452
|
+
onSelect={handleSelect}
|
|
453
|
+
parentRef={inputRef}
|
|
454
|
+
ref={targetRef}
|
|
455
|
+
/>
|
|
456
|
+
)}
|
|
457
|
+
</Listbox.Overlay>
|
|
458
|
+
{targetRef?.current && (
|
|
459
|
+
<View
|
|
460
|
+
// This catches and shifts focus to other interactive elements.
|
|
461
|
+
onFocus={() => targetRef?.current?.focus()}
|
|
462
|
+
tabIndex={0}
|
|
398
463
|
/>
|
|
399
464
|
)}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
<View
|
|
403
|
-
// This catches and shifts focus to other interactive elements.
|
|
404
|
-
onFocus={() => targetRef?.current?.focus()}
|
|
405
|
-
tabIndex={0}
|
|
406
|
-
/>
|
|
407
|
-
)}
|
|
408
|
-
</>
|
|
409
|
-
)}
|
|
465
|
+
</>
|
|
466
|
+
)}
|
|
410
467
|
</View>
|
|
411
468
|
)
|
|
412
469
|
}
|
|
@@ -468,6 +525,10 @@ Autocomplete.propTypes = {
|
|
|
468
525
|
* Maximum number of suggestions provided at the same time
|
|
469
526
|
*/
|
|
470
527
|
maxSuggestions: PropTypes.number,
|
|
528
|
+
/**
|
|
529
|
+
* Maximum height (in pixels) of the dropdown before scrolling is enabled
|
|
530
|
+
*/
|
|
531
|
+
maxDropdownHeight: PropTypes.number,
|
|
471
532
|
/**
|
|
472
533
|
* Text or JSX to render when no results are available
|
|
473
534
|
*/
|
|
@@ -488,6 +549,10 @@ Autocomplete.propTypes = {
|
|
|
488
549
|
* Callback function to be called when an item is selected from the list
|
|
489
550
|
*/
|
|
490
551
|
onSelect: PropTypes.func,
|
|
552
|
+
/**
|
|
553
|
+
* When true, displays all available options when the input receives focus (even without typing)
|
|
554
|
+
*/
|
|
555
|
+
showOptionsOnFocus: PropTypes.bool,
|
|
491
556
|
/**
|
|
492
557
|
* Input value for controlled usage
|
|
493
558
|
*/
|
|
@@ -1056,8 +1056,7 @@ const Carousel = React.forwardRef(
|
|
|
1056
1056
|
// Related discussion - https://github.com/telus/universal-design-system/issues/1549
|
|
1057
1057
|
const previousNextIconButtonVariants = {
|
|
1058
1058
|
size: previousNextIconSize,
|
|
1059
|
-
raised:
|
|
1060
|
-
inverse: variant?.inverse
|
|
1059
|
+
raised: true
|
|
1061
1060
|
}
|
|
1062
1061
|
|
|
1063
1062
|
const getCopyWithPlaceholders = React.useCallback(
|
|
@@ -28,6 +28,7 @@ const DropdownOverlay = React.forwardRef(
|
|
|
28
28
|
isReady = false,
|
|
29
29
|
overlaidPosition,
|
|
30
30
|
maxWidth,
|
|
31
|
+
maxHeight,
|
|
31
32
|
minWidth,
|
|
32
33
|
onLayout,
|
|
33
34
|
tokens,
|
|
@@ -50,12 +51,18 @@ const DropdownOverlay = React.forwardRef(
|
|
|
50
51
|
staticStyles.positioner,
|
|
51
52
|
!isReady && staticStyles.hidden
|
|
52
53
|
]}
|
|
54
|
+
onMouseDown={(e) => {
|
|
55
|
+
e.preventDefault()
|
|
56
|
+
}}
|
|
53
57
|
>
|
|
54
58
|
<Card
|
|
55
59
|
tokens={{
|
|
56
60
|
shadow: systemTokens.shadow,
|
|
57
61
|
borderRadius: systemTokens.borderRadius,
|
|
58
|
-
...(Platform.OS === 'web' && {
|
|
62
|
+
...(Platform.OS === 'web' && {
|
|
63
|
+
maxHeight,
|
|
64
|
+
overflowY: 'auto'
|
|
65
|
+
}),
|
|
59
66
|
paddingBottom: paddingVertical,
|
|
60
67
|
paddingTop: paddingVertical,
|
|
61
68
|
paddingLeft: paddingHorizontal,
|
|
@@ -89,6 +96,7 @@ DropdownOverlay.propTypes = {
|
|
|
89
96
|
width: PropTypes.number
|
|
90
97
|
}),
|
|
91
98
|
maxWidth: PropTypes.number,
|
|
99
|
+
maxHeight: PropTypes.number,
|
|
92
100
|
minWidth: PropTypes.number,
|
|
93
101
|
onLayout: PropTypes.func,
|
|
94
102
|
tokens: PropTypes.object,
|
|
@@ -120,7 +120,7 @@ const PressableItem = React.forwardRef(
|
|
|
120
120
|
>
|
|
121
121
|
{(pressableState) => {
|
|
122
122
|
return (
|
|
123
|
-
<Text style={selectTextStyles(resolveButtonTokens(pressableState))}>{children}
|
|
123
|
+
<Text style={selectTextStyles(resolveButtonTokens(pressableState))}>{children}</Text>
|
|
124
124
|
)
|
|
125
125
|
}}
|
|
126
126
|
</Pressable>
|
|
@@ -255,8 +255,8 @@ const TextInputBase = React.forwardRef(
|
|
|
255
255
|
}, [element, pattern])
|
|
256
256
|
|
|
257
257
|
const handleChangeText = (event) => {
|
|
258
|
-
const text = event.nativeEvent?.text
|
|
259
|
-
let filteredText = isNumeric ? text?.replace(/[^\d]/g, '') : text
|
|
258
|
+
const text = event.nativeEvent?.text ?? event.target?.value
|
|
259
|
+
let filteredText = isNumeric ? text?.replace(/[^\d]/g, '') || undefined : text
|
|
260
260
|
if (type === 'card' && filteredText) {
|
|
261
261
|
const formattedValue = filteredText.replace(/[^a-zA-Z0-9]/g, '')
|
|
262
262
|
const regex = new RegExp(`([a-zA-Z0-9]{4})(?=[a-zA-Z0-9])`, 'g')
|