@telus-uds/components-base 3.28.1 → 3.29.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 +25 -1
- package/lib/cjs/Autocomplete/Autocomplete.js +86 -32
- package/lib/cjs/Autocomplete/constants.js +2 -1
- package/lib/cjs/Card/CardBase.js +12 -0
- package/lib/cjs/Carousel/Carousel.js +1 -2
- package/lib/cjs/ColourToggle/ColourBubble.js +17 -3
- package/lib/cjs/ColourToggle/ColourToggle.js +8 -2
- package/lib/cjs/ExpandCollapse/Control.js +17 -3
- package/lib/cjs/ExpandCollapse/Panel.js +6 -0
- package/lib/cjs/ExpandCollapseMini/ExpandCollapseMini.js +14 -2
- package/lib/cjs/ExpandCollapseMini/ExpandCollapseMiniControl.js +15 -2
- package/lib/cjs/Link/ChevronLink.js +1 -0
- package/lib/cjs/Link/LinkBase.js +29 -13
- package/lib/cjs/Link/MobileIconTextContent.js +156 -0
- package/lib/cjs/Listbox/ListboxOverlay.js +7 -1
- package/lib/cjs/Listbox/PressableItem.js +2 -2
- package/lib/cjs/TabBar/TabBar.js +7 -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/Card/CardBase.js +12 -0
- package/lib/esm/Carousel/Carousel.js +1 -2
- package/lib/esm/ColourToggle/ColourBubble.js +17 -3
- package/lib/esm/ColourToggle/ColourToggle.js +8 -2
- package/lib/esm/ExpandCollapse/Control.js +17 -3
- package/lib/esm/ExpandCollapse/Panel.js +6 -0
- package/lib/esm/ExpandCollapseMini/ExpandCollapseMini.js +14 -2
- package/lib/esm/ExpandCollapseMini/ExpandCollapseMiniControl.js +15 -2
- package/lib/esm/Link/ChevronLink.js +1 -0
- package/lib/esm/Link/LinkBase.js +29 -13
- package/lib/esm/Link/MobileIconTextContent.js +147 -0
- package/lib/esm/Listbox/ListboxOverlay.js +7 -1
- package/lib/esm/Listbox/PressableItem.js +3 -3
- package/lib/esm/TabBar/TabBar.js +7 -2
- 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/Card/CardBase.jsx +12 -0
- package/src/Carousel/Carousel.jsx +1 -2
- package/src/ColourToggle/ColourBubble.jsx +18 -3
- package/src/ColourToggle/ColourToggle.jsx +7 -2
- package/src/ExpandCollapse/Control.jsx +24 -4
- package/src/ExpandCollapse/Panel.jsx +6 -0
- package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +23 -3
- package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +14 -2
- package/src/Link/ChevronLink.jsx +1 -0
- package/src/Link/LinkBase.jsx +47 -20
- package/src/Link/MobileIconTextContent.jsx +129 -0
- package/src/Listbox/ListboxOverlay.jsx +9 -1
- package/src/Listbox/PressableItem.jsx +1 -1
- package/src/TabBar/TabBar.jsx +21 -4
- package/src/TextInput/TextInputBase.jsx +2 -2
|
@@ -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
|
*/
|
package/src/Card/CardBase.jsx
CHANGED
|
@@ -59,9 +59,21 @@ const setBackgroundImage = ({
|
|
|
59
59
|
case 'left-center':
|
|
60
60
|
backgroundPosition = 'left center'
|
|
61
61
|
break
|
|
62
|
+
case 'left-start':
|
|
63
|
+
backgroundPosition = 'left top'
|
|
64
|
+
break
|
|
65
|
+
case 'left-end':
|
|
66
|
+
backgroundPosition = 'left bottom'
|
|
67
|
+
break
|
|
62
68
|
case 'right-center':
|
|
63
69
|
backgroundPosition = 'right center'
|
|
64
70
|
break
|
|
71
|
+
case 'right-start':
|
|
72
|
+
backgroundPosition = 'right top'
|
|
73
|
+
break
|
|
74
|
+
case 'right-end':
|
|
75
|
+
backgroundPosition = 'right bottom'
|
|
76
|
+
break
|
|
65
77
|
default:
|
|
66
78
|
backgroundPosition = 'center center'
|
|
67
79
|
}
|
|
@@ -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(
|
|
@@ -5,6 +5,7 @@ import { View, Pressable, Platform } from 'react-native'
|
|
|
5
5
|
import { resolvePressableTokens } from '../utils/pressability'
|
|
6
6
|
import { applyShadowToken } from '../ThemeProvider'
|
|
7
7
|
import { getTokensPropType } from '../utils'
|
|
8
|
+
import Tooltip from '../Tooltip'
|
|
8
9
|
|
|
9
10
|
const selectGeneralBubbleTokens = ({
|
|
10
11
|
outerBubbleHeight,
|
|
@@ -52,14 +53,14 @@ const selectBorderBubbleTokens = ({
|
|
|
52
53
|
})
|
|
53
54
|
|
|
54
55
|
const ColourBubble = React.forwardRef(
|
|
55
|
-
({ tokens = {}, id, colourHexCode, colourName, isSelected, onPress }, ref) => {
|
|
56
|
+
({ tokens = {}, id, colourHexCode, colourName, isSelected, onPress, showTooltip }, ref) => {
|
|
56
57
|
const defaultTokens = tokens({ selected: isSelected })
|
|
57
58
|
|
|
58
59
|
const resolveColourBubbleTokens = (pressState) => resolvePressableTokens(tokens, pressState, {})
|
|
59
60
|
|
|
60
61
|
const themeTokens = React.useMemo(() => tokens(), [tokens])
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
const pressable = (
|
|
63
64
|
<Pressable
|
|
64
65
|
style={(state) => [
|
|
65
66
|
selectGeneralBubbleTokens(resolveColourBubbleTokens(state)),
|
|
@@ -76,6 +77,16 @@ const ColourBubble = React.forwardRef(
|
|
|
76
77
|
<View style={[selectInnerBubbleTokens(themeTokens), { backgroundColor: colourHexCode }]} />
|
|
77
78
|
</Pressable>
|
|
78
79
|
)
|
|
80
|
+
|
|
81
|
+
if (showTooltip) {
|
|
82
|
+
return (
|
|
83
|
+
<Tooltip content={colourName} activateOnHover>
|
|
84
|
+
{pressable}
|
|
85
|
+
</Tooltip>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return pressable
|
|
79
90
|
}
|
|
80
91
|
)
|
|
81
92
|
ColourBubble.displayName = 'ColourBubble'
|
|
@@ -106,7 +117,11 @@ ColourBubble.propTypes = {
|
|
|
106
117
|
* of the color is changed of all currently `items`.
|
|
107
118
|
* Receives two parameters: item object selected and the event
|
|
108
119
|
*/
|
|
109
|
-
onPress: PropTypes.func
|
|
120
|
+
onPress: PropTypes.func,
|
|
121
|
+
/**
|
|
122
|
+
* When true, wraps the bubble in a Tooltip that displays the colourName on hover (web only).
|
|
123
|
+
*/
|
|
124
|
+
showTooltip: PropTypes.bool
|
|
110
125
|
}
|
|
111
126
|
|
|
112
127
|
export default ColourBubble
|
|
@@ -11,7 +11,7 @@ import ColourBubble from './ColourBubble'
|
|
|
11
11
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
12
12
|
|
|
13
13
|
const ColourToggle = React.forwardRef(
|
|
14
|
-
({ tokens, variant, defaultColourId, items, onChange, ...rest }, ref) => {
|
|
14
|
+
({ tokens, variant, defaultColourId, items, onChange, showTooltips, ...rest }, ref) => {
|
|
15
15
|
const [currentColourId, setCurrentColourId] = React.useState(defaultColourId)
|
|
16
16
|
const getTokens = useThemeTokensCallback('ColourToggle', tokens, variant)
|
|
17
17
|
|
|
@@ -40,6 +40,7 @@ const ColourToggle = React.forwardRef(
|
|
|
40
40
|
colourHexCode={colourHexCode}
|
|
41
41
|
colourName={colourName}
|
|
42
42
|
onPress={handleChangeColour}
|
|
43
|
+
showTooltip={showTooltips}
|
|
43
44
|
/>
|
|
44
45
|
)
|
|
45
46
|
})}
|
|
@@ -77,7 +78,11 @@ ColourToggle.propTypes = {
|
|
|
77
78
|
/**
|
|
78
79
|
* If provided, this function is called when the current selection of the color is changed of all currently `items`. Receives two parameters: item object selected and the event
|
|
79
80
|
*/
|
|
80
|
-
onChange: PropTypes.func
|
|
81
|
+
onChange: PropTypes.func,
|
|
82
|
+
/**
|
|
83
|
+
* When true, displays each colour's name as a tooltip on hover (web only).
|
|
84
|
+
*/
|
|
85
|
+
showTooltips: PropTypes.bool
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
export default ColourToggle
|
|
@@ -54,10 +54,11 @@ function selectIconContainerStyles({ iconGap, iconPaddingTop, iconPosition }) {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function selectTextContainerStyles({ textLine }) {
|
|
57
|
+
function selectTextContainerStyles({ textLine, controlAlign }) {
|
|
58
58
|
return {
|
|
59
59
|
textDecorationLine: textLine,
|
|
60
|
-
flex: 1
|
|
60
|
+
flex: 1,
|
|
61
|
+
...(controlAlign && { alignItems: controlAlign })
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -70,7 +71,16 @@ function selectIconTokens(tokens) {
|
|
|
70
71
|
|
|
71
72
|
const ExpandCollapseControl = React.forwardRef(
|
|
72
73
|
(
|
|
73
|
-
{
|
|
74
|
+
{
|
|
75
|
+
onPress,
|
|
76
|
+
isExpanded,
|
|
77
|
+
children,
|
|
78
|
+
tokens,
|
|
79
|
+
controlAlign,
|
|
80
|
+
accessibilityRole = 'button',
|
|
81
|
+
variant,
|
|
82
|
+
...rest
|
|
83
|
+
},
|
|
74
84
|
ref
|
|
75
85
|
) => {
|
|
76
86
|
const getTokens = useThemeTokensCallback('ExpandCollapseControl', tokens, variant)
|
|
@@ -110,7 +120,13 @@ const ExpandCollapseControl = React.forwardRef(
|
|
|
110
120
|
</View>
|
|
111
121
|
)}
|
|
112
122
|
<View
|
|
113
|
-
style={[
|
|
123
|
+
style={[
|
|
124
|
+
selectTextContainerStyles({
|
|
125
|
+
...themeTokens,
|
|
126
|
+
...(controlAlign && { controlAlign })
|
|
127
|
+
}),
|
|
128
|
+
staticStyles.bubblePointerEvents
|
|
129
|
+
]}
|
|
114
130
|
>
|
|
115
131
|
{typeof children === 'function'
|
|
116
132
|
? children(getControlState(pressableState))
|
|
@@ -144,6 +160,10 @@ ExpandCollapseControl.propTypes = {
|
|
|
144
160
|
* Whether the linked ExpandCollapsePanel is opened or closed. Allows themes to set `expanded` styles.
|
|
145
161
|
*/
|
|
146
162
|
isExpanded: PropTypes.bool,
|
|
163
|
+
/**
|
|
164
|
+
* Optional alignment for control content. Overrides token-driven alignment.
|
|
165
|
+
*/
|
|
166
|
+
controlAlign: PropTypes.oneOf(['flex-start', 'center', 'flex-end']),
|
|
147
167
|
/**
|
|
148
168
|
* Function called when the ExpandCollapse is pressed.
|
|
149
169
|
*/
|
|
@@ -90,6 +90,7 @@ const ExpandCollapsePanel = React.forwardRef(
|
|
|
90
90
|
onPress,
|
|
91
91
|
control,
|
|
92
92
|
controlTokens,
|
|
93
|
+
controlAlign,
|
|
93
94
|
children,
|
|
94
95
|
tokens,
|
|
95
96
|
variant,
|
|
@@ -174,6 +175,7 @@ const ExpandCollapsePanel = React.forwardRef(
|
|
|
174
175
|
{...selectedProps}
|
|
175
176
|
isExpanded={isExpanded}
|
|
176
177
|
tokens={controlTokens}
|
|
178
|
+
controlAlign={controlAlign}
|
|
177
179
|
variant={variant}
|
|
178
180
|
onPress={handleControlPress}
|
|
179
181
|
ref={controlRef}
|
|
@@ -284,6 +286,10 @@ ExpandCollapsePanel.propTypes = {
|
|
|
284
286
|
* Optional theme token overrides that may be passed to the ExpandCollapseControl element.
|
|
285
287
|
*/
|
|
286
288
|
controlTokens: getTokensPropType('ExpandCollapseControl'),
|
|
289
|
+
/**
|
|
290
|
+
* Optional alignment for control content.
|
|
291
|
+
*/
|
|
292
|
+
controlAlign: PropTypes.oneOf(['flex-start', 'center', 'flex-end']),
|
|
287
293
|
/**
|
|
288
294
|
* An optional ref to be attached to the control
|
|
289
295
|
*/
|
|
@@ -7,9 +7,24 @@ import ExpandCollapseMiniControl from './ExpandCollapseMiniControl'
|
|
|
7
7
|
|
|
8
8
|
const [selectContainerProps, selectedContainerPropTypes] = selectSystemProps([contentfulProps])
|
|
9
9
|
|
|
10
|
+
const alignMap = {
|
|
11
|
+
start: 'flex-start',
|
|
12
|
+
middle: 'center',
|
|
13
|
+
end: 'flex-end'
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
const ExpandCollapseMini = React.forwardRef(
|
|
11
17
|
(
|
|
12
|
-
{
|
|
18
|
+
{
|
|
19
|
+
children,
|
|
20
|
+
onToggle = () => {},
|
|
21
|
+
tokens = {},
|
|
22
|
+
nativeID,
|
|
23
|
+
initialOpen = false,
|
|
24
|
+
dataSet,
|
|
25
|
+
align,
|
|
26
|
+
...rest
|
|
27
|
+
},
|
|
13
28
|
ref
|
|
14
29
|
) => {
|
|
15
30
|
const expandCollapeMiniPanelId = useUniqueId('ExpandCollapseMiniPanel')
|
|
@@ -40,10 +55,11 @@ const ExpandCollapseMini = React.forwardRef(
|
|
|
40
55
|
textLine: tokens.textLine ?? 'none',
|
|
41
56
|
backgroundColor: 'transparent'
|
|
42
57
|
}}
|
|
58
|
+
controlAlign={align && alignMap[align]}
|
|
43
59
|
// TODO refactor
|
|
44
60
|
// eslint-disable-next-line react/no-unstable-nested-components
|
|
45
61
|
control={(pressableState) => (
|
|
46
|
-
<ExpandCollapseMiniControl pressableState={pressableState} {...rest} />
|
|
62
|
+
<ExpandCollapseMiniControl pressableState={pressableState} align={align} {...rest} />
|
|
47
63
|
)}
|
|
48
64
|
controlRef={ref}
|
|
49
65
|
nativeID={nativeID}
|
|
@@ -87,7 +103,11 @@ ExpandCollapseMini.propTypes = {
|
|
|
87
103
|
/**
|
|
88
104
|
* The dataSet prop allows to pass data-* attributes element to the component.
|
|
89
105
|
*/
|
|
90
|
-
dataSet: PropTypes.object
|
|
106
|
+
dataSet: PropTypes.object,
|
|
107
|
+
/**
|
|
108
|
+
* Controls the horizontal alignment of the trigger label and icon within the panel width.
|
|
109
|
+
*/
|
|
110
|
+
align: PropTypes.oneOf(['start', 'middle', 'end'])
|
|
91
111
|
}
|
|
92
112
|
|
|
93
113
|
export default ExpandCollapseMini
|
|
@@ -7,6 +7,12 @@ import { htmlAttrs, viewProps, selectSystemProps } from '../utils'
|
|
|
7
7
|
|
|
8
8
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs, viewProps])
|
|
9
9
|
|
|
10
|
+
const alignSelfMap = {
|
|
11
|
+
start: 'flex-start',
|
|
12
|
+
middle: 'center',
|
|
13
|
+
end: 'flex-end'
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
// The ExpandCollapseControl has all the appropriate role, a11y, press handling etc
|
|
11
17
|
// and a more appropriate press area, defer interaction handling to it.
|
|
12
18
|
const presentationOnly = {
|
|
@@ -24,6 +30,7 @@ const ExpandCollapseMiniControl = React.forwardRef(
|
|
|
24
30
|
iconPosition = 'right',
|
|
25
31
|
tokens,
|
|
26
32
|
variant = {},
|
|
33
|
+
align,
|
|
27
34
|
...rest
|
|
28
35
|
},
|
|
29
36
|
ref
|
|
@@ -96,7 +103,8 @@ const ExpandCollapseMiniControl = React.forwardRef(
|
|
|
96
103
|
...getTokens(linkState),
|
|
97
104
|
iconSize,
|
|
98
105
|
blockFontSize: fontSize,
|
|
99
|
-
blockLineHeight: lineHeight
|
|
106
|
+
blockLineHeight: lineHeight,
|
|
107
|
+
...(align && { alignSelf: alignSelfMap[align] })
|
|
100
108
|
})}
|
|
101
109
|
ref={ref}
|
|
102
110
|
{...presentationOnly}
|
|
@@ -132,7 +140,11 @@ ExpandCollapseMiniControl.propTypes = {
|
|
|
132
140
|
/**
|
|
133
141
|
* Optional variant object to override the default theme tokens
|
|
134
142
|
*/
|
|
135
|
-
variant: PropTypes.object
|
|
143
|
+
variant: PropTypes.object,
|
|
144
|
+
/**
|
|
145
|
+
* Controls the horizontal alignment of the trigger label and icon
|
|
146
|
+
*/
|
|
147
|
+
align: PropTypes.oneOf(['start', 'middle', 'end'])
|
|
136
148
|
}
|
|
137
149
|
|
|
138
150
|
export default ExpandCollapseMiniControl
|