@telus-uds/components-base 1.51.1 → 1.52.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 +13 -2
- package/component-docs.json +264 -93
- package/lib/Listbox/ListboxContext.js +20 -0
- package/lib/Listbox/PressableItem.js +170 -0
- package/lib/Listbox/index.js +32 -0
- package/lib/Modal/Modal.js +1 -2
- package/lib/MultiSelectFilter/MultiSelectFilter.js +19 -5
- package/lib/Timeline/Timeline.js +2 -2
- package/lib/index.js +14 -0
- package/lib/utils/htmlAttrs.js +33 -0
- package/lib/utils/index.js +10 -1
- package/lib-module/Listbox/ListboxContext.js +6 -0
- package/lib-module/Listbox/PressableItem.js +150 -0
- package/lib-module/Listbox/index.js +2 -0
- package/lib-module/Modal/Modal.js +2 -3
- package/lib-module/MultiSelectFilter/MultiSelectFilter.js +15 -5
- package/lib-module/Timeline/Timeline.js +2 -2
- package/lib-module/index.js +1 -0
- package/lib-module/utils/htmlAttrs.js +22 -0
- package/lib-module/utils/index.js +2 -1
- package/package.json +2 -2
- package/src/Listbox/ListboxContext.js +6 -0
- package/src/Listbox/PressableItem.jsx +143 -0
- package/src/Listbox/index.js +2 -0
- package/src/Modal/Modal.jsx +1 -3
- package/src/MultiSelectFilter/MultiSelectFilter.jsx +10 -4
- package/src/Timeline/Timeline.jsx +2 -2
- package/src/index.js +1 -0
- package/src/utils/htmlAttrs.js +29 -0
- package/src/utils/index.js +1 -0
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"@floating-ui/react-native": "^0.8.1",
|
|
12
12
|
"@gorhom/portal": "^1.0.14",
|
|
13
13
|
"@telus-uds/system-constants": "^1.2.1",
|
|
14
|
-
"@telus-uds/system-theme-tokens": "^2.
|
|
14
|
+
"@telus-uds/system-theme-tokens": "^2.35.0",
|
|
15
15
|
"airbnb-prop-types": "^2.16.0",
|
|
16
16
|
"lodash.debounce": "^4.0.8",
|
|
17
17
|
"lodash.merge": "^4.6.2",
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"standard-engine": {
|
|
73
73
|
"skip": true
|
|
74
74
|
},
|
|
75
|
-
"version": "1.
|
|
75
|
+
"version": "1.52.0"
|
|
76
76
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/* eslint-disable react/require-default-props */
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import { Pressable, Text } from 'react-native'
|
|
5
|
+
import { selectSystemProps, resolvePressableTokens, htmlAttrs } from '../utils'
|
|
6
|
+
import { useListboxContext } from './ListboxContext'
|
|
7
|
+
|
|
8
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
|
|
9
|
+
|
|
10
|
+
const getItemStyles = ({
|
|
11
|
+
groupFontName,
|
|
12
|
+
groupFontWeight,
|
|
13
|
+
itemFontSize,
|
|
14
|
+
itemPaddingTop,
|
|
15
|
+
itemPaddingBottom,
|
|
16
|
+
itemPaddingLeft,
|
|
17
|
+
itemBorderLeftWidth,
|
|
18
|
+
itemPaddingRight,
|
|
19
|
+
itemBackgroundColor,
|
|
20
|
+
itemColor,
|
|
21
|
+
itemDisplay,
|
|
22
|
+
itemOutline,
|
|
23
|
+
itemTextDecoration,
|
|
24
|
+
itemBorderLeftColor,
|
|
25
|
+
itemBorderRightWidth,
|
|
26
|
+
itemBorderRightColor,
|
|
27
|
+
itemBorderTopWidth,
|
|
28
|
+
itemBorderTopColor,
|
|
29
|
+
itemBorderBottomWidth,
|
|
30
|
+
itemBorderBottomColor,
|
|
31
|
+
itemBorderRadius,
|
|
32
|
+
itemHeight
|
|
33
|
+
}) => ({
|
|
34
|
+
fontFamily: `${groupFontName}${groupFontWeight}normal`,
|
|
35
|
+
fontSize: itemFontSize,
|
|
36
|
+
paddingTop: itemPaddingTop - itemBorderTopWidth,
|
|
37
|
+
paddingBottom: itemPaddingBottom - itemBorderBottomWidth,
|
|
38
|
+
paddingLeft: itemPaddingLeft - itemBorderLeftWidth,
|
|
39
|
+
paddingRight: itemPaddingRight - itemBorderRightWidth,
|
|
40
|
+
width: '100%',
|
|
41
|
+
backgroundColor: itemBackgroundColor,
|
|
42
|
+
color: itemColor,
|
|
43
|
+
display: itemDisplay,
|
|
44
|
+
outline: itemOutline,
|
|
45
|
+
textDecoration: itemTextDecoration,
|
|
46
|
+
borderLeft: `${itemBorderLeftWidth}px solid ${itemBorderLeftColor}`,
|
|
47
|
+
borderRight: `${itemBorderRightWidth}px solid ${itemBorderRightColor}`,
|
|
48
|
+
borderTop: `${itemBorderTopWidth}px solid ${itemBorderTopColor}`,
|
|
49
|
+
borderBottom: `${itemBorderBottomWidth}px solid ${itemBorderBottomColor}`,
|
|
50
|
+
borderRadius: itemBorderRadius,
|
|
51
|
+
height: itemHeight,
|
|
52
|
+
justifyContent: 'center'
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const PressableItem = forwardRef(
|
|
56
|
+
(
|
|
57
|
+
{
|
|
58
|
+
children,
|
|
59
|
+
href,
|
|
60
|
+
isChild = false,
|
|
61
|
+
onBlur,
|
|
62
|
+
onPress,
|
|
63
|
+
tabIndex = 0,
|
|
64
|
+
nextItemRef,
|
|
65
|
+
prevItemRef,
|
|
66
|
+
tokens,
|
|
67
|
+
id,
|
|
68
|
+
...rest
|
|
69
|
+
},
|
|
70
|
+
ref
|
|
71
|
+
) => {
|
|
72
|
+
const { selectedId, setSelectedId } = useListboxContext()
|
|
73
|
+
|
|
74
|
+
const selectTextStyles = ({
|
|
75
|
+
groupFontName,
|
|
76
|
+
groupFontWeight,
|
|
77
|
+
itemFontSize,
|
|
78
|
+
itemColor,
|
|
79
|
+
lineHeight
|
|
80
|
+
}) => ({
|
|
81
|
+
fontFamily: `${groupFontName}${groupFontWeight}normal`,
|
|
82
|
+
fontSize: itemFontSize,
|
|
83
|
+
color: itemColor,
|
|
84
|
+
lineHeight: lineHeight * itemFontSize
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const resolveButtonTokens = (pressableState) => {
|
|
88
|
+
const themeTokens = resolvePressableTokens(tokens, pressableState, {
|
|
89
|
+
isChild,
|
|
90
|
+
current: id === selectedId && id !== undefined
|
|
91
|
+
})
|
|
92
|
+
return themeTokens
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const handleKeyPress = (event) => {
|
|
96
|
+
if (['Enter', ' '].includes(event?.key)) {
|
|
97
|
+
onPress?.(event)
|
|
98
|
+
} else if (event?.key === 'ArrowDown') {
|
|
99
|
+
nextItemRef.current.focus()
|
|
100
|
+
} else if (event?.key === 'ArrowUp' && prevItemRef?.current) {
|
|
101
|
+
prevItemRef.current.focus()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<Pressable
|
|
107
|
+
isChild={isChild}
|
|
108
|
+
style={(pressableState) => getItemStyles(resolveButtonTokens(pressableState))}
|
|
109
|
+
onBlur={onBlur}
|
|
110
|
+
onClick={onPress}
|
|
111
|
+
onKeyPress={handleKeyPress}
|
|
112
|
+
ref={ref}
|
|
113
|
+
tabIndex={tabIndex}
|
|
114
|
+
{...(href && { href })}
|
|
115
|
+
{...(onPress && { onClick: onPress })}
|
|
116
|
+
{...selectProps(rest)}
|
|
117
|
+
onPress={() => {
|
|
118
|
+
setSelectedId(id)
|
|
119
|
+
onPress()
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
{(pressableState) => {
|
|
123
|
+
return (
|
|
124
|
+
<Text style={selectTextStyles(resolveButtonTokens(pressableState))}>{children} </Text>
|
|
125
|
+
)
|
|
126
|
+
}}
|
|
127
|
+
</Pressable>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
PressableItem.displayName = 'PressableItem'
|
|
132
|
+
PressableItem.propTypes = {
|
|
133
|
+
...selectedSystemPropTypes,
|
|
134
|
+
href: PropTypes.string,
|
|
135
|
+
isChild: PropTypes.bool,
|
|
136
|
+
children: PropTypes.node.isRequired,
|
|
137
|
+
onBlur: PropTypes.func,
|
|
138
|
+
onPress: PropTypes.func,
|
|
139
|
+
nextItemRef: PropTypes.object,
|
|
140
|
+
prevItemRef: PropTypes.object
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export default PressableItem
|
package/src/Modal/Modal.jsx
CHANGED
|
@@ -16,8 +16,7 @@ import {
|
|
|
16
16
|
selectSystemProps,
|
|
17
17
|
useCopy,
|
|
18
18
|
variantProp,
|
|
19
|
-
viewProps
|
|
20
|
-
selectTokens
|
|
19
|
+
viewProps
|
|
21
20
|
} from '../utils'
|
|
22
21
|
import { useViewport } from '../ViewportProvider'
|
|
23
22
|
import IconButton from '../IconButton'
|
|
@@ -138,7 +137,6 @@ const Modal = forwardRef(
|
|
|
138
137
|
icon={CloseIconComponent}
|
|
139
138
|
accessibilityRole="button"
|
|
140
139
|
accessibilityLabel={closeLabel}
|
|
141
|
-
tokens={selectTokens('IconButton', themeTokens, 'close')}
|
|
142
140
|
/>
|
|
143
141
|
)}
|
|
144
142
|
</View>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
|
|
4
|
+
import { View, StyleSheet } from 'react-native'
|
|
4
5
|
import { useThemeTokens, useThemeTokensCallback, applyTextStyles } from '../ThemeProvider'
|
|
5
6
|
import {
|
|
6
7
|
containUniqueFields,
|
|
@@ -104,7 +105,6 @@ const MultiSelectFilter = ({
|
|
|
104
105
|
if (!containUniqueFields(items, uniqueFields)) {
|
|
105
106
|
throw new Error(`MultiSelectFilter items must have unique ${uniqueFields.join(', ')}`)
|
|
106
107
|
}
|
|
107
|
-
|
|
108
108
|
// Pass an object of relevant component state as first argument for any passed-in press handlers
|
|
109
109
|
const pressHandlers = getPressHandlersWithArgs(rest, [{ id, label, currentValues }])
|
|
110
110
|
|
|
@@ -239,9 +239,11 @@ const MultiSelectFilter = ({
|
|
|
239
239
|
onLayout={onTargetLayout}
|
|
240
240
|
>
|
|
241
241
|
<Row>
|
|
242
|
-
<
|
|
243
|
-
{
|
|
244
|
-
|
|
242
|
+
<View style={styles.textContainerStyle}>
|
|
243
|
+
<Typography tokens={{ ...headerStyles, lineHeight: headerLineHeight }}>
|
|
244
|
+
{getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())}
|
|
245
|
+
</Typography>
|
|
246
|
+
</View>
|
|
245
247
|
</Row>
|
|
246
248
|
{subtitle && (
|
|
247
249
|
<>
|
|
@@ -301,6 +303,10 @@ const MultiSelectFilter = ({
|
|
|
301
303
|
|
|
302
304
|
MultiSelectFilter.displayName = 'MultiSelectFilter'
|
|
303
305
|
|
|
306
|
+
const styles = StyleSheet.create({
|
|
307
|
+
textContainerStyle: { marginRight: 52 }
|
|
308
|
+
})
|
|
309
|
+
|
|
304
310
|
MultiSelectFilter.propTypes = {
|
|
305
311
|
/**
|
|
306
312
|
* The text displayed to the user in a ButtonDropdown.
|
|
@@ -23,10 +23,10 @@ const selectDotStyles = ({ dotWidth, timelineColor, dotBorderWidth, dotColor })
|
|
|
23
23
|
borderColor: timelineColor
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
const selectConnectorStyles = ({
|
|
26
|
+
const selectConnectorStyles = ({ timelineConnectorColor, connectorHeight, connectorWidth }) => ({
|
|
27
27
|
width: connectorWidth,
|
|
28
28
|
height: connectorHeight,
|
|
29
|
-
backgroundColor:
|
|
29
|
+
backgroundColor: timelineConnectorColor
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
const selectTimelineContainerStyle = ({ timelineContainerDirection }) => ({
|
package/src/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export { default as Box } from './Box'
|
|
|
4
4
|
export * from './Button'
|
|
5
5
|
export { default as Card, PressableCardBase } from './Card'
|
|
6
6
|
export * from './Carousel'
|
|
7
|
+
export * from './Listbox'
|
|
7
8
|
export { default as Checkbox } from './Checkbox'
|
|
8
9
|
export * from './Checkbox'
|
|
9
10
|
export { default as Divider } from './Divider'
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
|
|
3
|
+
const htmlAttrTypes = {
|
|
4
|
+
dataSet: PropTypes.object,
|
|
5
|
+
id: PropTypes.string,
|
|
6
|
+
loading: PropTypes.oneOf(['eager', 'lazy']),
|
|
7
|
+
// @todo figure out if we need to enum all the possible roles or maybe use
|
|
8
|
+
// an npm package
|
|
9
|
+
role: PropTypes.string,
|
|
10
|
+
src: PropTypes.string,
|
|
11
|
+
tabIndex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
12
|
+
testID: PropTypes.string,
|
|
13
|
+
title: PropTypes.string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
types: htmlAttrTypes,
|
|
18
|
+
select: (props) =>
|
|
19
|
+
Object.entries(props).reduce(
|
|
20
|
+
(items, [key, value]) =>
|
|
21
|
+
Object.keys(htmlAttrTypes).includes(key) || /^(data|aria)-/.test(key)
|
|
22
|
+
? {
|
|
23
|
+
...items,
|
|
24
|
+
[key]: value
|
|
25
|
+
}
|
|
26
|
+
: items,
|
|
27
|
+
{}
|
|
28
|
+
)
|
|
29
|
+
}
|
package/src/utils/index.js
CHANGED