@telus-uds/components-web 2.10.0 → 2.11.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 +17 -2
- package/component-docs.json +12 -0
- package/lib/BlockQuote/BlockQuote.js +4 -1
- package/lib/DatePicker/DatePicker.js +23 -12
- package/lib/Listbox/GroupControl.js +44 -28
- package/lib/Listbox/Listbox.js +54 -47
- package/lib/Listbox/ListboxGroup.js +36 -20
- package/lib/Listbox/ListboxItem.js +14 -51
- package/lib/Listbox/ListboxOverlay.js +1 -1
- package/lib/Video/ControlBar/ControlBar.js +13 -10
- package/lib/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.js +4 -1
- package/lib/VideoPicker/VideoPicker.js +1 -1
- package/lib/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.js +14 -2
- package/lib/utils/index.js +3 -3
- package/lib-module/BlockQuote/BlockQuote.js +4 -1
- package/lib-module/DatePicker/DatePicker.js +23 -12
- package/lib-module/Listbox/GroupControl.js +45 -29
- package/lib-module/Listbox/Listbox.js +54 -46
- package/lib-module/Listbox/ListboxGroup.js +37 -21
- package/lib-module/Listbox/ListboxItem.js +15 -51
- package/lib-module/Listbox/ListboxOverlay.js +1 -1
- package/lib-module/Video/ControlBar/ControlBar.js +14 -11
- package/lib-module/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.js +4 -1
- package/lib-module/VideoPicker/VideoPicker.js +1 -1
- package/lib-module/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.js +14 -2
- package/lib-module/utils/index.js +1 -1
- package/package.json +3 -3
- package/src/BlockQuote/BlockQuote.jsx +13 -1
- package/src/DatePicker/DatePicker.jsx +22 -12
- package/src/Listbox/GroupControl.jsx +50 -33
- package/src/Listbox/Listbox.jsx +59 -50
- package/src/Listbox/ListboxGroup.jsx +34 -19
- package/src/Listbox/ListboxItem.jsx +26 -48
- package/src/Listbox/ListboxOverlay.jsx +1 -1
- package/src/Video/ControlBar/ControlBar.jsx +17 -13
- package/src/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.jsx +2 -1
- package/src/VideoPicker/VideoPicker.jsx +1 -1
- package/src/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.jsx +8 -1
- package/src/utils/index.js +1 -1
- package/lib/Listbox/PressableItem.js +0 -149
- package/lib/utils/htmlAttrs.js +0 -33
- package/lib-module/Listbox/PressableItem.js +0 -128
- package/lib-module/utils/htmlAttrs.js +0 -22
- package/src/Listbox/PressableItem.jsx +0 -121
- package/src/utils/htmlAttrs.js +0 -29
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
|
-
import { StackView, useThemeTokens, selectSystemProps, Icon } from '@telus-uds/components-base';
|
|
4
|
+
import { StackView, useThemeTokens, selectSystemProps, Icon, useViewport } from '@telus-uds/components-base';
|
|
5
5
|
import VideoProgressBar from './Controls/VideoProgressBar/VideoProgressBar';
|
|
6
6
|
import VolumeSlider from './Controls/VolumeSlider/VolumeSlider';
|
|
7
7
|
import VideoButton from './Controls/VideoButton/VideoButton';
|
|
@@ -37,13 +37,14 @@ const StyledControlBar = /*#__PURE__*/styled.div.withConfig({
|
|
|
37
37
|
componentId: "components-web__sc-13y61ky-1"
|
|
38
38
|
})(_ref2 => {
|
|
39
39
|
let {
|
|
40
|
-
padding
|
|
40
|
+
padding,
|
|
41
|
+
height
|
|
41
42
|
} = _ref2;
|
|
42
43
|
return {
|
|
43
44
|
boxSizing: 'border-box',
|
|
44
45
|
position: 'absolute',
|
|
45
46
|
width: '100%',
|
|
46
|
-
height
|
|
47
|
+
height,
|
|
47
48
|
padding,
|
|
48
49
|
bottom: 0,
|
|
49
50
|
backgroundColor: 'rgba(42, 44, 46, 0.85)',
|
|
@@ -119,21 +120,23 @@ const ControlBar = _ref4 => {
|
|
|
119
120
|
variant,
|
|
120
121
|
...rest
|
|
121
122
|
} = _ref4;
|
|
123
|
+
const viewport = useViewport();
|
|
122
124
|
const {
|
|
123
125
|
paddingTop,
|
|
124
126
|
paddingBottom,
|
|
125
|
-
paddingLeft
|
|
126
|
-
paddingRight
|
|
127
|
-
paddingLeftCompactMode,
|
|
128
|
-
paddingRightCompactMode,
|
|
127
|
+
paddingLeft,
|
|
128
|
+
paddingRight,
|
|
129
129
|
menuBottom,
|
|
130
130
|
menuRight,
|
|
131
131
|
menuMarginLeft,
|
|
132
132
|
captionsIcon,
|
|
133
133
|
settingsIcon,
|
|
134
134
|
minimizeIcon,
|
|
135
|
-
maximizeIcon
|
|
136
|
-
|
|
135
|
+
maximizeIcon,
|
|
136
|
+
height
|
|
137
|
+
} = useThemeTokens('VideoControlBar', tokens, variant, {
|
|
138
|
+
viewport
|
|
139
|
+
});
|
|
137
140
|
|
|
138
141
|
const parseVideoQuality = () => {
|
|
139
142
|
return sources.map(source => {
|
|
@@ -162,8 +165,6 @@ const ControlBar = _ref4 => {
|
|
|
162
165
|
return parsed;
|
|
163
166
|
};
|
|
164
167
|
|
|
165
|
-
const paddingLeft = videoPlayerWidth > compactModeThreshold ? paddingLeftDefault : paddingLeftCompactMode;
|
|
166
|
-
const paddingRight = videoPlayerWidth > compactModeThreshold ? paddingRightDefault : paddingRightCompactMode;
|
|
167
168
|
const menuContainerStyleProps = {
|
|
168
169
|
menuBottom,
|
|
169
170
|
menuRight,
|
|
@@ -175,10 +176,12 @@ const ControlBar = _ref4 => {
|
|
|
175
176
|
...selectProps(rest),
|
|
176
177
|
children: /*#__PURE__*/_jsxs(StyledControlBar, {
|
|
177
178
|
padding: `${paddingTop}px ${paddingRight}px ${paddingBottom}px ${paddingLeft}px`,
|
|
179
|
+
height: `${height}px`,
|
|
178
180
|
children: [/*#__PURE__*/_jsx(VideoProgressBarContainer, {
|
|
179
181
|
children: /*#__PURE__*/_jsx(VideoProgressBar, {
|
|
180
182
|
copy: copy,
|
|
181
183
|
videoPlayer: videoPlayer,
|
|
184
|
+
playing: videoPlaying,
|
|
182
185
|
videoLength: videoLength,
|
|
183
186
|
videoCurrentTime: videoCurrentTime,
|
|
184
187
|
videoBufferEnd: videoBufferEnd,
|
|
@@ -122,6 +122,7 @@ const VideoProgressBar = _ref5 => {
|
|
|
122
122
|
videoLength,
|
|
123
123
|
videoCurrentTime,
|
|
124
124
|
videoBufferEnd,
|
|
125
|
+
playing,
|
|
125
126
|
setSeek,
|
|
126
127
|
resetInactivityTimer,
|
|
127
128
|
tokens,
|
|
@@ -137,7 +138,9 @@ const VideoProgressBar = _ref5 => {
|
|
|
137
138
|
trackGradientStart,
|
|
138
139
|
trackGradientEnd,
|
|
139
140
|
rangeBackground
|
|
140
|
-
} = useThemeTokens('VideoProgressBar', tokens, variant
|
|
141
|
+
} = useThemeTokens('VideoProgressBar', tokens, variant, {
|
|
142
|
+
playing
|
|
143
|
+
});
|
|
141
144
|
const videoProgressBar = /*#__PURE__*/React.createRef();
|
|
142
145
|
|
|
143
146
|
const handleVideoSkip = () => {
|
|
@@ -87,7 +87,7 @@ const VideoPicker = _ref6 => {
|
|
|
87
87
|
setCurrentVideoId(selectedVideo);
|
|
88
88
|
}, [selectedVideo]); // `frame` variant should only work on larger screens
|
|
89
89
|
|
|
90
|
-
const isFramed = frame && [viewports.
|
|
90
|
+
const isFramed = frame && [viewports.lg, viewports.xl].includes(viewport);
|
|
91
91
|
const hasSlider = !frame && [viewports.md, viewports.lg, viewports.xl].includes(viewport);
|
|
92
92
|
const listElements = videoList.map((video, index) => /*#__PURE__*/_jsx(VideoPickerThumbnail, {
|
|
93
93
|
video: video,
|
|
@@ -157,14 +157,25 @@ const selectButtonContentTokens = _ref14 => {
|
|
|
157
157
|
};
|
|
158
158
|
};
|
|
159
159
|
|
|
160
|
-
const
|
|
160
|
+
const getLabelTokens = _ref15 => {
|
|
161
|
+
let {
|
|
162
|
+
labelFontName: fontName,
|
|
163
|
+
labelFontWeight: fontWeight
|
|
164
|
+
} = _ref15;
|
|
165
|
+
return {
|
|
166
|
+
fontName,
|
|
167
|
+
fontWeight
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const SplashButtonWithDetails = _ref16 => {
|
|
161
172
|
let {
|
|
162
173
|
label,
|
|
163
174
|
tokens,
|
|
164
175
|
variant,
|
|
165
176
|
copy,
|
|
166
177
|
videoLength
|
|
167
|
-
} =
|
|
178
|
+
} = _ref16;
|
|
168
179
|
const {
|
|
169
180
|
buttonContentChildrenBackground
|
|
170
181
|
} = useThemeTokens('SplashButtonWithDetails', tokens, variant, {
|
|
@@ -191,6 +202,7 @@ const SplashButtonWithDetails = _ref15 => {
|
|
|
191
202
|
variant: {
|
|
192
203
|
bold: true
|
|
193
204
|
},
|
|
205
|
+
tokens: getLabelTokens(themeTokens),
|
|
194
206
|
children: label
|
|
195
207
|
}), /*#__PURE__*/_jsx(Typography, {
|
|
196
208
|
variant: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { htmlAttrs } from '@telus-uds/components-base';
|
|
1
2
|
import { warn, deprecate } from './logger';
|
|
2
3
|
import { transformGradient } from './transforms';
|
|
3
4
|
import useTypographyTheme from './useTypographyTheme';
|
|
4
|
-
import htmlAttrs from './htmlAttrs';
|
|
5
5
|
import media from './media';
|
|
6
6
|
import ssrStyles from './ssr';
|
|
7
7
|
import renderStructuredContent from './renderStructuredContent';
|
package/package.json
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
],
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@gorhom/portal": "^1.0.14",
|
|
8
|
-
"@telus-uds/components-base": "1.
|
|
8
|
+
"@telus-uds/components-base": "1.52.0",
|
|
9
9
|
"@telus-uds/system-constants": "^1.2.1",
|
|
10
10
|
"fscreen": "^1.2.0",
|
|
11
11
|
"lodash.omit": "^4.5.0",
|
|
12
12
|
"react-dates": "^21.8.0",
|
|
13
13
|
"react-helmet-async": "^1.3.0",
|
|
14
14
|
"react-moment-proptypes": "^1.8.1",
|
|
15
|
-
"@telus-uds/system-theme-tokens": "^2.
|
|
15
|
+
"@telus-uds/system-theme-tokens": "^2.35.0",
|
|
16
16
|
"prop-types": "^15.7.2",
|
|
17
17
|
"lodash.throttle": "^4.1.1",
|
|
18
18
|
"react-youtube": "^10.1.0",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"skip": true
|
|
64
64
|
},
|
|
65
65
|
"types": "types/index.d.ts",
|
|
66
|
-
"version": "2.
|
|
66
|
+
"version": "2.11.0"
|
|
67
67
|
}
|
|
@@ -110,7 +110,19 @@ const BlockQuote = ({
|
|
|
110
110
|
)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
return
|
|
113
|
+
return (
|
|
114
|
+
<Typography
|
|
115
|
+
tokens={{
|
|
116
|
+
color,
|
|
117
|
+
fontName: linkFontName,
|
|
118
|
+
fontSize: linkFontSize,
|
|
119
|
+
fontWeight: linkFontWeight,
|
|
120
|
+
lineHeight: linkLineHeight
|
|
121
|
+
}}
|
|
122
|
+
>
|
|
123
|
+
{link}
|
|
124
|
+
</Typography>
|
|
125
|
+
)
|
|
114
126
|
}
|
|
115
127
|
|
|
116
128
|
const renderQuote = () => {
|
|
@@ -91,6 +91,7 @@ const DatePicker = forwardRef(
|
|
|
91
91
|
tokens,
|
|
92
92
|
variant = {},
|
|
93
93
|
validation,
|
|
94
|
+
disabled,
|
|
94
95
|
...rest
|
|
95
96
|
},
|
|
96
97
|
ref
|
|
@@ -110,20 +111,22 @@ const DatePicker = forwardRef(
|
|
|
110
111
|
setIsClickedInside(false)
|
|
111
112
|
}
|
|
112
113
|
const handleFocus = (event) => {
|
|
113
|
-
if (event.target.tagName === 'INPUT') {
|
|
114
|
+
if (event.target.tagName === 'INPUT' && !disabled) {
|
|
114
115
|
setIsFocused(true)
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
const handleMouseDown = (event) => {
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
if (!disabled) {
|
|
120
|
+
if (event.target.tagName === 'INPUT') {
|
|
121
|
+
setIsClickedInside(true)
|
|
122
|
+
setIsFocused(true)
|
|
123
|
+
} else if (event.target.tagName === 'path') {
|
|
124
|
+
// needed to handle the case where the user clicks on the tooltip icon
|
|
125
|
+
setIsClickedInside(true)
|
|
126
|
+
event.stopPropagation()
|
|
127
|
+
} else {
|
|
128
|
+
event.stopPropagation()
|
|
129
|
+
}
|
|
127
130
|
}
|
|
128
131
|
}
|
|
129
132
|
const onChange = (value) => {
|
|
@@ -253,9 +256,11 @@ const DatePicker = forwardRef(
|
|
|
253
256
|
label={dictionary[copy]?.roleDescription ?? label}
|
|
254
257
|
value={inputText}
|
|
255
258
|
validation={validation}
|
|
259
|
+
inactive={disabled}
|
|
256
260
|
>
|
|
257
261
|
<SingleDatePicker
|
|
258
262
|
date={inputDate}
|
|
263
|
+
disabled={disabled}
|
|
259
264
|
onDateChange={onChange}
|
|
260
265
|
focused={isFocused}
|
|
261
266
|
onFocusChange={onFocusChange}
|
|
@@ -347,7 +352,11 @@ DatePicker.propTypes = {
|
|
|
347
352
|
/**
|
|
348
353
|
* Use to visually mark an input as valid or invalid.
|
|
349
354
|
*/
|
|
350
|
-
validation: PropTypes.oneOf(['error', 'success'])
|
|
355
|
+
validation: PropTypes.oneOf(['error', 'success']),
|
|
356
|
+
/**
|
|
357
|
+
* Disable the input which will not open the calendar picker
|
|
358
|
+
*/
|
|
359
|
+
disabled: PropTypes.bool
|
|
351
360
|
}
|
|
352
361
|
|
|
353
362
|
DatePicker.defaultProps = {
|
|
@@ -361,7 +370,8 @@ DatePicker.defaultProps = {
|
|
|
361
370
|
hintPosition: 'inline',
|
|
362
371
|
tooltip: undefined,
|
|
363
372
|
onDateChange: () => {},
|
|
364
|
-
validation: undefined
|
|
373
|
+
validation: undefined,
|
|
374
|
+
disabled: false
|
|
365
375
|
}
|
|
366
376
|
|
|
367
377
|
export default DatePicker
|
|
@@ -1,64 +1,81 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import styled from 'styled-components'
|
|
3
3
|
import PropTypes from 'prop-types'
|
|
4
|
-
import { Icon, Spacer, useThemeTokens } from '@telus-uds/components-base'
|
|
4
|
+
import { Icon, Spacer, useThemeTokens, useListboxContext } from '@telus-uds/components-base'
|
|
5
5
|
|
|
6
|
-
const StyledControlWrapper = styled.div(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
6
|
+
const StyledControlWrapper = styled.div(
|
|
7
|
+
({
|
|
8
|
+
groupFontName,
|
|
9
|
+
groupFontWeight,
|
|
10
|
+
groupFontSize,
|
|
11
|
+
groupColor,
|
|
12
|
+
groupBackgroundColor,
|
|
13
|
+
groupBorderColor,
|
|
14
|
+
groupBorderWidth,
|
|
15
|
+
groupBorderRadius,
|
|
16
|
+
groupPaddingLeft,
|
|
17
|
+
groupPaddingRight,
|
|
18
|
+
groupPaddingTop,
|
|
19
|
+
groupPaddingBottom,
|
|
20
|
+
itemTextDecoration,
|
|
21
|
+
itemOutline,
|
|
22
|
+
groupHeight
|
|
23
|
+
}) => ({
|
|
24
|
+
fontFamily: `${groupFontName}${groupFontWeight}normal`,
|
|
25
|
+
fontSize: groupFontSize,
|
|
26
|
+
color: groupColor,
|
|
27
|
+
textDecoration: itemTextDecoration,
|
|
28
|
+
backgroundColor: groupBackgroundColor,
|
|
29
|
+
outline: itemOutline,
|
|
30
|
+
width: '100%',
|
|
31
|
+
height: groupHeight,
|
|
32
|
+
display: 'flex',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
justifyContent: 'space-between',
|
|
35
|
+
boxSizing: 'border-box',
|
|
36
|
+
border: `${groupBorderWidth}px solid ${groupBorderColor}`,
|
|
37
|
+
borderRadius: groupBorderRadius,
|
|
38
|
+
paddingLeft: groupPaddingLeft - groupBorderWidth,
|
|
39
|
+
paddingRight: groupPaddingRight - groupBorderWidth,
|
|
40
|
+
paddingTop: groupPaddingTop - groupBorderWidth,
|
|
41
|
+
paddingBottom: groupPaddingBottom - groupBorderWidth
|
|
42
|
+
})
|
|
43
|
+
)
|
|
32
44
|
|
|
33
|
-
const GroupControl = ({ expanded, pressed, hover, focus,
|
|
45
|
+
const GroupControl = ({ expanded, pressed, hover, focus, label, id }) => {
|
|
46
|
+
const { selectedId, setSelectedId } = useListboxContext()
|
|
34
47
|
const tokens = useThemeTokens(
|
|
35
|
-
'
|
|
48
|
+
'Listbox',
|
|
36
49
|
{},
|
|
37
50
|
{},
|
|
38
51
|
{
|
|
39
52
|
expanded,
|
|
40
53
|
pressed,
|
|
41
54
|
hover,
|
|
42
|
-
current,
|
|
55
|
+
current: selectedId === id && id !== undefined,
|
|
43
56
|
focus
|
|
44
57
|
}
|
|
45
58
|
)
|
|
46
59
|
|
|
47
60
|
return (
|
|
48
|
-
<StyledControlWrapper {
|
|
61
|
+
<StyledControlWrapper onClick={() => setSelectedId(id)} {...tokens}>
|
|
49
62
|
{label}
|
|
50
63
|
<Spacer space={1} direction="row" />
|
|
51
|
-
<Icon
|
|
64
|
+
<Icon
|
|
65
|
+
icon={tokens.groupIcon}
|
|
66
|
+
tokens={{ color: tokens.groupColor }}
|
|
67
|
+
variant={{ size: 'micro' }}
|
|
68
|
+
/>
|
|
52
69
|
</StyledControlWrapper>
|
|
53
70
|
)
|
|
54
71
|
}
|
|
55
72
|
|
|
56
73
|
GroupControl.propTypes = {
|
|
74
|
+
id: PropTypes.string,
|
|
57
75
|
expanded: PropTypes.bool,
|
|
58
76
|
pressed: PropTypes.bool,
|
|
59
77
|
hover: PropTypes.bool,
|
|
60
78
|
focus: PropTypes.bool,
|
|
61
|
-
current: PropTypes.bool,
|
|
62
79
|
label: PropTypes.string
|
|
63
80
|
}
|
|
64
81
|
|
package/src/Listbox/Listbox.jsx
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import styled from 'styled-components'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
ExpandCollapse,
|
|
6
|
+
useThemeTokens,
|
|
7
|
+
withLinkRouter,
|
|
8
|
+
ListboxContext
|
|
9
|
+
} from '@telus-uds/components-base'
|
|
5
10
|
import ListboxGroup from './ListboxGroup'
|
|
6
11
|
import ListboxItem from './ListboxItem'
|
|
7
12
|
import DropdownOverlay from './ListboxOverlay'
|
|
8
|
-
import resolveItemSelection from '../NavigationBar/resolveItemSelection'
|
|
9
13
|
|
|
10
14
|
const StyledList = styled.ul({
|
|
11
15
|
margin: 0,
|
|
@@ -26,12 +30,18 @@ const Listbox = ({
|
|
|
26
30
|
items = [],
|
|
27
31
|
firstItemRef = null, // focus will be moved to this one once within the menu
|
|
28
32
|
parentRef = null, // to return focus to after leaving the last menu item
|
|
29
|
-
selectedId,
|
|
33
|
+
selectedId: defaultSelectedId,
|
|
30
34
|
LinkRouter,
|
|
31
35
|
itemRouterProps,
|
|
32
|
-
onClose
|
|
36
|
+
onClose,
|
|
37
|
+
variant,
|
|
38
|
+
tokens
|
|
33
39
|
}) => {
|
|
34
|
-
const initialOpen = getInitialOpen(items,
|
|
40
|
+
const initialOpen = getInitialOpen(items, defaultSelectedId)
|
|
41
|
+
|
|
42
|
+
const [selectedId, setSelectedId] = useState(defaultSelectedId)
|
|
43
|
+
|
|
44
|
+
const { minHeight, minWidth } = useThemeTokens('Listbox', variant, tokens)
|
|
35
45
|
|
|
36
46
|
// We need to keep track of each item's ref in order to be able to
|
|
37
47
|
// focus on a specific item via keyboard navigation
|
|
@@ -78,53 +88,52 @@ const Listbox = ({
|
|
|
78
88
|
}, [onClose, handleKeydown])
|
|
79
89
|
|
|
80
90
|
return (
|
|
81
|
-
<
|
|
82
|
-
{
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
selectedId
|
|
89
|
-
)
|
|
91
|
+
<ListboxContext.Provider value={{ selectedId, setSelectedId }}>
|
|
92
|
+
<ExpandCollapse initialOpen={initialOpen} maxOpen={1}>
|
|
93
|
+
{(expandProps) => (
|
|
94
|
+
<StyledList role="listbox" style={{ minHeight, minWidth }}>
|
|
95
|
+
{items.map((item, index) => {
|
|
96
|
+
const { id, label, items: nestedItems } = item
|
|
97
|
+
const itemId = id ?? label
|
|
90
98
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
// Give `firstItemRef` to the first focusable item
|
|
100
|
+
const itemRef =
|
|
101
|
+
(index === 0 && !itemId !== selectedId) ||
|
|
102
|
+
(index === 1 && items[0].id === selectedId)
|
|
103
|
+
? firstItemRef
|
|
104
|
+
: (ref) => {
|
|
105
|
+
itemRefs.current[index] = ref
|
|
106
|
+
return ref
|
|
107
|
+
}
|
|
99
108
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
</
|
|
109
|
+
return nestedItems ? (
|
|
110
|
+
<ListboxGroup
|
|
111
|
+
{...item}
|
|
112
|
+
expandProps={expandProps}
|
|
113
|
+
LinkRouter={LinkRouter}
|
|
114
|
+
itemRouterProps={itemRouterProps}
|
|
115
|
+
prevItemRef={itemRefs.current[index - 1] ?? null}
|
|
116
|
+
nextItemRef={itemRefs.current[index + 1] ?? null}
|
|
117
|
+
ref={itemRef}
|
|
118
|
+
key={itemId}
|
|
119
|
+
/>
|
|
120
|
+
) : (
|
|
121
|
+
<ListboxItem
|
|
122
|
+
{...item}
|
|
123
|
+
key={itemId}
|
|
124
|
+
id={itemId}
|
|
125
|
+
LinkRouter={LinkRouter}
|
|
126
|
+
itemRouterProps={itemRouterProps}
|
|
127
|
+
prevItemRef={itemRefs.current[index - 1] ?? null}
|
|
128
|
+
nextItemRef={itemRefs.current[index + 1] ?? null}
|
|
129
|
+
ref={itemRef}
|
|
130
|
+
/>
|
|
131
|
+
)
|
|
132
|
+
})}
|
|
133
|
+
</StyledList>
|
|
134
|
+
)}
|
|
135
|
+
</ExpandCollapse>
|
|
136
|
+
</ListboxContext.Provider>
|
|
128
137
|
)
|
|
129
138
|
}
|
|
130
139
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable react/require-default-props */
|
|
2
2
|
import React, { forwardRef } from 'react'
|
|
3
3
|
import PropTypes from 'prop-types'
|
|
4
|
-
import { ExpandCollapse, withLinkRouter } from '@telus-uds/components-base'
|
|
4
|
+
import { ExpandCollapse, withLinkRouter, useListboxContext } from '@telus-uds/components-base'
|
|
5
5
|
import styled from 'styled-components'
|
|
6
6
|
import ListboxItem from './ListboxItem'
|
|
7
7
|
import GroupControl from './GroupControl'
|
|
@@ -31,7 +31,6 @@ const ListboxGroup = forwardRef(
|
|
|
31
31
|
id,
|
|
32
32
|
label,
|
|
33
33
|
items,
|
|
34
|
-
selectedId,
|
|
35
34
|
LinkRouter,
|
|
36
35
|
linkRouterProps,
|
|
37
36
|
expandProps,
|
|
@@ -41,8 +40,9 @@ const ListboxGroup = forwardRef(
|
|
|
41
40
|
},
|
|
42
41
|
ref
|
|
43
42
|
) => {
|
|
44
|
-
|
|
43
|
+
const { selectedId } = useListboxContext()
|
|
45
44
|
|
|
45
|
+
// TODO: implement keyboard navigation via refs for grouped items separately here
|
|
46
46
|
return (
|
|
47
47
|
<StyledGroupWrapper role="option">
|
|
48
48
|
<ExpandCollapse.Panel
|
|
@@ -52,34 +52,49 @@ const ListboxGroup = forwardRef(
|
|
|
52
52
|
paddingLeft: 'none',
|
|
53
53
|
paddingRight: 'none',
|
|
54
54
|
paddingTop: 'none',
|
|
55
|
-
paddingBottom: 'none'
|
|
55
|
+
paddingBottom: 'none',
|
|
56
|
+
backgroundColor: 'transparent',
|
|
57
|
+
borderColor: 'transparent',
|
|
58
|
+
textLine: 'none',
|
|
59
|
+
borderWidth: 0
|
|
56
60
|
}}
|
|
57
61
|
// TODO refactor
|
|
58
62
|
// eslint-disable-next-line react/no-unstable-nested-components
|
|
59
|
-
control={(controlProps) =>
|
|
63
|
+
control={(controlProps) => (
|
|
64
|
+
<GroupControl id={id ?? label} {...controlProps} label={label} />
|
|
65
|
+
)}
|
|
60
66
|
{...expandProps}
|
|
61
67
|
tokens={{
|
|
62
68
|
contentPaddingLeft: 'none',
|
|
63
69
|
contentPaddingRight: 'none',
|
|
64
70
|
contentPaddingTop: 'none',
|
|
65
|
-
contentPaddingBottom: 'none'
|
|
71
|
+
contentPaddingBottom: 'none',
|
|
72
|
+
borderColor: 'transparent',
|
|
73
|
+
borderRadius: 0,
|
|
74
|
+
borderWidth: 0,
|
|
75
|
+
marginBottom: 0
|
|
66
76
|
}}
|
|
67
77
|
controlRef={ref}
|
|
68
78
|
>
|
|
69
79
|
<StyledList>
|
|
70
|
-
{items.map((item, index) =>
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
{items.map((item, index) => {
|
|
81
|
+
return (
|
|
82
|
+
<ListboxItem
|
|
83
|
+
key={item.label}
|
|
84
|
+
id={item.id ?? item.label}
|
|
85
|
+
{...item}
|
|
86
|
+
selected={
|
|
87
|
+
(item.id && item.id === selectedId) || (item.label && item.label === selectedId)
|
|
88
|
+
}
|
|
89
|
+
isChild
|
|
90
|
+
LinkRouter={LinkRouter}
|
|
91
|
+
linkRouterProps={linkRouterProps}
|
|
92
|
+
{...(index === 0 && { prevItemRef })}
|
|
93
|
+
{...(index === items.length - 1 && { nextItemRef })}
|
|
94
|
+
{...(index === items.length - 1 && { onBlur: onLastItemBlur })}
|
|
95
|
+
/>
|
|
96
|
+
)
|
|
97
|
+
})}
|
|
83
98
|
</StyledList>
|
|
84
99
|
</ExpandCollapse.Panel>
|
|
85
100
|
</StyledGroupWrapper>
|