@telus-uds/components-base 1.82.0 → 1.83.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 +15 -2
- package/lib/Listbox/Listbox.js +7 -5
- package/lib/Notification/Notification.js +1 -1
- package/lib/Radio/Radio.js +1 -1
- package/lib-module/Listbox/Listbox.js +8 -6
- package/lib-module/Notification/Notification.js +1 -1
- package/lib-module/Radio/Radio.js +1 -1
- package/package.json +1 -1
- package/src/Listbox/Listbox.jsx +112 -105
- package/src/Notification/Notification.jsx +1 -1
- package/src/Radio/Radio.jsx +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
# Change Log - @telus-uds/components-base
|
|
2
2
|
|
|
3
|
-
This log was last generated on
|
|
3
|
+
This log was last generated on Wed, 24 Apr 2024 16:28:55 GMT and should not be manually modified.
|
|
4
4
|
|
|
5
5
|
<!-- Start content -->
|
|
6
6
|
|
|
7
|
+
## 1.83.0
|
|
8
|
+
|
|
9
|
+
Wed, 24 Apr 2024 16:28:55 GMT
|
|
10
|
+
|
|
11
|
+
### Minor changes
|
|
12
|
+
|
|
13
|
+
- Radio: Allow React node along with string labels for label prop (35577399+JoshHC@users.noreply.github.com)
|
|
14
|
+
- `Listbox:` add ref prop (guillermo.peitzner@telus.com)
|
|
15
|
+
|
|
16
|
+
### Patches
|
|
17
|
+
|
|
18
|
+
- Notification: fix justify-content not being reflected. (evander.owusu@telus.com)
|
|
19
|
+
|
|
7
20
|
## 1.82.0
|
|
8
21
|
|
|
9
|
-
Fri, 05 Apr 2024 17:
|
|
22
|
+
Fri, 05 Apr 2024 17:16:24 GMT
|
|
10
23
|
|
|
11
24
|
### Minor changes
|
|
12
25
|
|
package/lib/Listbox/Listbox.js
CHANGED
|
@@ -27,7 +27,7 @@ const styles = _StyleSheet.default.create({
|
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
const getInitialOpen = (items, selectedId) => items.filter(item => item.items && item.items.some(nestedItem => (nestedItem.id ?? nestedItem.label) === selectedId)).map(item => item.id ?? item.label);
|
|
30
|
-
const Listbox = _ref => {
|
|
30
|
+
const Listbox = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
|
|
31
31
|
let {
|
|
32
32
|
items = [],
|
|
33
33
|
firstItemRef = null,
|
|
@@ -106,6 +106,7 @@ const Listbox = _ref => {
|
|
|
106
106
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandCollapse.default, {
|
|
107
107
|
initialOpen: initialOpen,
|
|
108
108
|
maxOpen: 1,
|
|
109
|
+
ref: ref,
|
|
109
110
|
children: expandProps => /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
|
|
110
111
|
style: [styles.list, {
|
|
111
112
|
minHeight,
|
|
@@ -121,9 +122,9 @@ const Listbox = _ref => {
|
|
|
121
122
|
const itemId = id ?? label;
|
|
122
123
|
|
|
123
124
|
// Give the list of refs.
|
|
124
|
-
const itemRef =
|
|
125
|
-
itemRefs.current[index] =
|
|
126
|
-
return
|
|
125
|
+
const itemRef = currentItemRef => {
|
|
126
|
+
itemRefs.current[index] = currentItemRef;
|
|
127
|
+
return currentItemRef;
|
|
127
128
|
};
|
|
128
129
|
return nestedItems ? /*#__PURE__*/(0, _react.createElement)(_ListboxGroup.default, {
|
|
129
130
|
...item,
|
|
@@ -148,7 +149,8 @@ const Listbox = _ref => {
|
|
|
148
149
|
})
|
|
149
150
|
})
|
|
150
151
|
});
|
|
151
|
-
};
|
|
152
|
+
});
|
|
153
|
+
Listbox.displayName = 'Listbox';
|
|
152
154
|
Listbox.propTypes = {
|
|
153
155
|
..._utils.withLinkRouter.propTypes,
|
|
154
156
|
tokens: (0, _utils.getTokensPropType)('Listbox'),
|
|
@@ -72,7 +72,7 @@ const selectDismissButtonContainerStyles = _ref4 => {
|
|
|
72
72
|
};
|
|
73
73
|
};
|
|
74
74
|
const selectContentContainerStyle = maxWidth => ({
|
|
75
|
-
|
|
75
|
+
maxWidth: maxWidth || '100%'
|
|
76
76
|
});
|
|
77
77
|
const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, dismissible) => {
|
|
78
78
|
const transformedSelectContainerStyles = Object.entries(themeTokens).reduce((acc, _ref5) => {
|
package/lib/Radio/Radio.js
CHANGED
|
@@ -248,7 +248,7 @@ Radio.propTypes = {
|
|
|
248
248
|
/**
|
|
249
249
|
* The label.
|
|
250
250
|
*/
|
|
251
|
-
label: _propTypes.default.string,
|
|
251
|
+
label: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.node]),
|
|
252
252
|
/**
|
|
253
253
|
* Associate this radio button with a group (set as the name attribute).
|
|
254
254
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
1
|
+
import React, { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import View from "react-native-web/dist/exports/View";
|
|
4
4
|
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
@@ -19,7 +19,7 @@ const styles = StyleSheet.create({
|
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
21
|
const getInitialOpen = (items, selectedId) => items.filter(item => item.items && item.items.some(nestedItem => (nestedItem.id ?? nestedItem.label) === selectedId)).map(item => item.id ?? item.label);
|
|
22
|
-
const Listbox = _ref => {
|
|
22
|
+
const Listbox = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
23
23
|
let {
|
|
24
24
|
items = [],
|
|
25
25
|
firstItemRef = null,
|
|
@@ -98,6 +98,7 @@ const Listbox = _ref => {
|
|
|
98
98
|
children: /*#__PURE__*/_jsx(ExpandCollapse, {
|
|
99
99
|
initialOpen: initialOpen,
|
|
100
100
|
maxOpen: 1,
|
|
101
|
+
ref: ref,
|
|
101
102
|
children: expandProps => /*#__PURE__*/_jsx(View, {
|
|
102
103
|
style: [styles.list, {
|
|
103
104
|
minHeight,
|
|
@@ -113,9 +114,9 @@ const Listbox = _ref => {
|
|
|
113
114
|
const itemId = id ?? label;
|
|
114
115
|
|
|
115
116
|
// Give the list of refs.
|
|
116
|
-
const itemRef =
|
|
117
|
-
itemRefs.current[index] =
|
|
118
|
-
return
|
|
117
|
+
const itemRef = currentItemRef => {
|
|
118
|
+
itemRefs.current[index] = currentItemRef;
|
|
119
|
+
return currentItemRef;
|
|
119
120
|
};
|
|
120
121
|
return nestedItems ? /*#__PURE__*/_createElement(ListboxGroup, {
|
|
121
122
|
...item,
|
|
@@ -140,7 +141,8 @@ const Listbox = _ref => {
|
|
|
140
141
|
})
|
|
141
142
|
})
|
|
142
143
|
});
|
|
143
|
-
};
|
|
144
|
+
});
|
|
145
|
+
Listbox.displayName = 'Listbox';
|
|
144
146
|
Listbox.propTypes = {
|
|
145
147
|
...withLinkRouter.propTypes,
|
|
146
148
|
tokens: getTokensPropType('Listbox'),
|
|
@@ -64,7 +64,7 @@ const selectDismissButtonContainerStyles = _ref4 => {
|
|
|
64
64
|
};
|
|
65
65
|
};
|
|
66
66
|
const selectContentContainerStyle = maxWidth => ({
|
|
67
|
-
|
|
67
|
+
maxWidth: maxWidth || '100%'
|
|
68
68
|
});
|
|
69
69
|
const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, dismissible) => {
|
|
70
70
|
const transformedSelectContainerStyles = Object.entries(themeTokens).reduce((acc, _ref5) => {
|
package/package.json
CHANGED
package/src/Listbox/Listbox.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
1
|
+
import React, { forwardRef, useCallback, useEffect, useRef, useState } from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import { View, StyleSheet, Platform } from 'react-native'
|
|
4
4
|
import { useThemeTokens } from '../ThemeProvider'
|
|
@@ -25,119 +25,126 @@ const getInitialOpen = (items, selectedId) =>
|
|
|
25
25
|
)
|
|
26
26
|
.map((item) => item.id ?? item.label)
|
|
27
27
|
|
|
28
|
-
const Listbox = (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
const Listbox = forwardRef(
|
|
29
|
+
(
|
|
30
|
+
{
|
|
31
|
+
items = [],
|
|
32
|
+
firstItemRef = null, // focus will be moved to this one once within the menu
|
|
33
|
+
parentRef = null, // to return focus to after leaving the last menu item
|
|
34
|
+
selectedId: defaultSelectedId,
|
|
35
|
+
LinkRouter,
|
|
36
|
+
itemRouterProps,
|
|
37
|
+
onClose,
|
|
38
|
+
variant,
|
|
39
|
+
tokens
|
|
40
|
+
},
|
|
41
|
+
ref
|
|
42
|
+
) => {
|
|
43
|
+
const initialOpen = getInitialOpen(items, defaultSelectedId)
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
const [selectedId, setSelectedId] = useState(defaultSelectedId)
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
const { minHeight, minWidth } = useThemeTokens('Listbox', variant, tokens)
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
// We need to keep track of each item's ref in order to be able to
|
|
50
|
+
// focus on a specific item via keyboard navigation
|
|
51
|
+
const itemRefs = useRef([])
|
|
52
|
+
if (firstItemRef?.current) itemRefs.current[0] = firstItemRef.current
|
|
53
|
+
const [focusedIndex, setFocusedIndex] = useState(0)
|
|
54
|
+
const handleKeydown = useCallback(
|
|
55
|
+
(event) => {
|
|
56
|
+
const nextItemRef = itemRefs.current[focusedIndex + 1]
|
|
57
|
+
const prevItemRef = itemRefs.current[focusedIndex - 1]
|
|
58
|
+
if (event.key === 'ArrowUp' || (event.shiftKey && event.key === 'Tab')) {
|
|
59
|
+
// Move the focus to the previous item or to the parent one if on the first
|
|
60
|
+
if (prevItemRef) {
|
|
61
|
+
event.preventDefault()
|
|
62
|
+
prevItemRef.focus()
|
|
63
|
+
} else if (parentRef) parentRef.current?.focus()
|
|
64
|
+
setFocusedIndex(focusedIndex - 1)
|
|
65
|
+
} else if ((event.key === 'ArrowDown' || event.key === 'Tab') && nextItemRef) {
|
|
57
66
|
event.preventDefault()
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
firstItemRef.current?.focus()
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
[focusedIndex, onClose, parentRef, firstItemRef]
|
|
79
|
-
)
|
|
67
|
+
setFocusedIndex(focusedIndex + 1)
|
|
68
|
+
nextItemRef.focus()
|
|
69
|
+
} else if (event.key === 'Escape') {
|
|
70
|
+
// Close the dropdown
|
|
71
|
+
parentRef?.current?.click()
|
|
72
|
+
// Return focus to the dropdown control after leaving the last item
|
|
73
|
+
parentRef?.current?.focus()
|
|
74
|
+
if (onClose) onClose(event)
|
|
75
|
+
} else if (!nextItemRef && firstItemRef) {
|
|
76
|
+
// If the last item is focused, move the focus to the first one
|
|
77
|
+
event.preventDefault()
|
|
78
|
+
setFocusedIndex(0)
|
|
79
|
+
firstItemRef.current?.focus()
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
[focusedIndex, onClose, parentRef, firstItemRef]
|
|
83
|
+
)
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
// Add listeners for mouse clicks outside and for key presses
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (Platform.OS === 'web') {
|
|
88
|
+
window.addEventListener('click', onClose)
|
|
89
|
+
window.addEventListener('keydown', handleKeydown)
|
|
90
|
+
window.addEventListener('touchstart', onClose)
|
|
91
|
+
return () => {
|
|
92
|
+
window.removeEventListener('click', onClose)
|
|
93
|
+
window.removeEventListener('keydown', handleKeydown)
|
|
94
|
+
window.removeEventListener('touchstart', onClose)
|
|
95
|
+
}
|
|
91
96
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}, [onClose, handleKeydown])
|
|
97
|
+
return () => {}
|
|
98
|
+
}, [onClose, handleKeydown])
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
return (
|
|
101
|
+
<ListboxContext.Provider value={{ selectedId, setSelectedId }}>
|
|
102
|
+
<ExpandCollapse initialOpen={initialOpen} maxOpen={1} ref={ref}>
|
|
103
|
+
{(expandProps) => (
|
|
104
|
+
<View style={[styles.list, { minHeight, minWidth }]} role="listbox">
|
|
105
|
+
{items.map((item, index) => {
|
|
106
|
+
const { id, label, items: nestedItems } = item
|
|
107
|
+
const itemId = id ?? label
|
|
104
108
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
// Give the list of refs.
|
|
110
|
+
const itemRef = (currentItemRef) => {
|
|
111
|
+
itemRefs.current[index] = currentItemRef
|
|
112
|
+
return currentItemRef
|
|
113
|
+
}
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
115
|
+
return nestedItems ? (
|
|
116
|
+
<ListboxGroup
|
|
117
|
+
{...item}
|
|
118
|
+
expandProps={expandProps}
|
|
119
|
+
LinkRouter={LinkRouter}
|
|
120
|
+
itemRouterProps={itemRouterProps}
|
|
121
|
+
prevItemRef={itemRefs.current[index - 1] ?? null}
|
|
122
|
+
nextItemRef={itemRefs.current[index + 1] ?? null}
|
|
123
|
+
ref={index === 0 ? firstItemRef : itemRef}
|
|
124
|
+
key={itemId}
|
|
125
|
+
/>
|
|
126
|
+
) : (
|
|
127
|
+
<ListboxItem
|
|
128
|
+
{...item}
|
|
129
|
+
key={itemId}
|
|
130
|
+
id={itemId}
|
|
131
|
+
LinkRouter={LinkRouter}
|
|
132
|
+
itemRouterProps={itemRouterProps}
|
|
133
|
+
prevItemRef={itemRefs.current[index - 1] ?? null}
|
|
134
|
+
nextItemRef={itemRefs.current[index + 1] ?? null}
|
|
135
|
+
ref={index === 0 ? firstItemRef : itemRef}
|
|
136
|
+
/>
|
|
137
|
+
)
|
|
138
|
+
})}
|
|
139
|
+
</View>
|
|
140
|
+
)}
|
|
141
|
+
</ExpandCollapse>
|
|
142
|
+
</ListboxContext.Provider>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
Listbox.displayName = 'Listbox'
|
|
141
148
|
|
|
142
149
|
Listbox.propTypes = {
|
|
143
150
|
...withLinkRouter.propTypes,
|
|
@@ -65,7 +65,7 @@ const selectDismissButtonContainerStyles = ({ dismissButtonGap }) => ({
|
|
|
65
65
|
})
|
|
66
66
|
|
|
67
67
|
const selectContentContainerStyle = (maxWidth) => ({
|
|
68
|
-
|
|
68
|
+
maxWidth: maxWidth || '100%'
|
|
69
69
|
})
|
|
70
70
|
|
|
71
71
|
const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, dismissible) => {
|
package/src/Radio/Radio.jsx
CHANGED