@telus-uds/components-base 3.23.0 → 3.25.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/Button/ButtonGroup.js +9 -2
- package/lib/cjs/Card/CardBase.js +97 -17
- package/lib/cjs/Card/PressableCardBase.js +12 -8
- package/lib/cjs/Carousel/Carousel.js +35 -4
- package/lib/cjs/FlexGrid/FlexGrid.js +31 -35
- package/lib/cjs/HorizontalScroll/HorizontalScroll.js +5 -2
- package/lib/cjs/Icon/Icon.js +3 -0
- package/lib/cjs/IconButton/IconButton.js +15 -5
- package/lib/cjs/Listbox/GroupControl.js +12 -6
- package/lib/cjs/Listbox/Listbox.js +41 -7
- package/lib/cjs/Listbox/ListboxGroup.js +139 -8
- package/lib/cjs/Listbox/ListboxOverlay.js +10 -5
- package/lib/cjs/Listbox/SecondLevelHeader.js +201 -0
- package/lib/cjs/Listbox/dictionary.js +14 -0
- package/lib/cjs/Shortcuts/Shortcuts.js +169 -0
- package/lib/cjs/Shortcuts/ShortcutsItem.js +280 -0
- package/lib/cjs/Shortcuts/index.js +16 -0
- package/lib/cjs/TextInput/TextInputBase.js +2 -3
- package/lib/cjs/Tooltip/Tooltip.native.js +2 -0
- package/lib/cjs/index.js +15 -0
- package/lib/cjs/utils/index.js +9 -1
- package/lib/cjs/utils/resolveContentMaxWidth.js +30 -0
- package/lib/esm/Button/ButtonGroup.js +9 -2
- package/lib/esm/Card/CardBase.js +97 -17
- package/lib/esm/Card/PressableCardBase.js +10 -8
- package/lib/esm/Carousel/Carousel.js +37 -6
- package/lib/esm/FlexGrid/FlexGrid.js +31 -35
- package/lib/esm/HorizontalScroll/HorizontalScroll.js +6 -3
- package/lib/esm/Icon/Icon.js +3 -0
- package/lib/esm/IconButton/IconButton.js +15 -5
- package/lib/esm/Listbox/GroupControl.js +12 -6
- package/lib/esm/Listbox/Listbox.js +41 -7
- package/lib/esm/Listbox/ListboxGroup.js +141 -10
- package/lib/esm/Listbox/ListboxOverlay.js +10 -5
- package/lib/esm/Listbox/SecondLevelHeader.js +194 -0
- package/lib/esm/Listbox/dictionary.js +8 -0
- package/lib/esm/Shortcuts/Shortcuts.js +160 -0
- package/lib/esm/Shortcuts/ShortcutsItem.js +273 -0
- package/lib/esm/Shortcuts/index.js +3 -0
- package/lib/esm/TextInput/TextInputBase.js +2 -3
- package/lib/esm/Tooltip/Tooltip.native.js +2 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/utils/index.js +2 -1
- package/lib/esm/utils/resolveContentMaxWidth.js +24 -0
- package/lib/package.json +2 -2
- package/package.json +2 -2
- package/src/Button/ButtonGroup.jsx +20 -3
- package/src/Card/CardBase.jsx +113 -14
- package/src/Card/PressableCardBase.jsx +17 -5
- package/src/Carousel/Carousel.jsx +38 -6
- package/src/FlexGrid/FlexGrid.jsx +30 -39
- package/src/HorizontalScroll/HorizontalScroll.jsx +6 -3
- package/src/Icon/Icon.jsx +3 -0
- package/src/IconButton/IconButton.jsx +12 -5
- package/src/Listbox/GroupControl.jsx +41 -33
- package/src/Listbox/Listbox.jsx +41 -2
- package/src/Listbox/ListboxGroup.jsx +158 -26
- package/src/Listbox/ListboxOverlay.jsx +18 -5
- package/src/Listbox/SecondLevelHeader.jsx +182 -0
- package/src/Listbox/dictionary.js +8 -0
- package/src/Shortcuts/Shortcuts.jsx +174 -0
- package/src/Shortcuts/ShortcutsItem.jsx +297 -0
- package/src/Shortcuts/index.js +4 -0
- package/src/TextInput/TextInputBase.jsx +2 -2
- package/src/Tooltip/Tooltip.native.jsx +2 -1
- package/src/index.js +1 -0
- package/src/utils/index.js +1 -0
- package/src/utils/resolveContentMaxWidth.js +28 -0
- package/types/Listbox.d.ts +24 -0
- package/types/Shortcuts.d.ts +136 -0
- package/types/Status.d.ts +42 -0
- package/types/index.d.ts +15 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import { Platform, StyleSheet, View } from 'react-native'
|
|
4
|
+
import { viewports } from '@telus-uds/system-constants'
|
|
5
|
+
|
|
6
|
+
import { useTheme, useThemeTokens } from '../ThemeProvider'
|
|
7
|
+
import { useViewport } from '../ViewportProvider'
|
|
8
|
+
import {
|
|
9
|
+
a11yProps,
|
|
10
|
+
getTokensPropType,
|
|
11
|
+
selectSystemProps,
|
|
12
|
+
useResponsiveProp,
|
|
13
|
+
variantProp,
|
|
14
|
+
viewProps
|
|
15
|
+
} from '../utils'
|
|
16
|
+
|
|
17
|
+
import HorizontalScroll, {
|
|
18
|
+
horizontalScrollUtils,
|
|
19
|
+
HorizontalScrollButton
|
|
20
|
+
} from '../HorizontalScroll'
|
|
21
|
+
|
|
22
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
23
|
+
|
|
24
|
+
const { selectHorizontalScrollTokens, useItemPositions } = horizontalScrollUtils
|
|
25
|
+
|
|
26
|
+
const selectStyles = (themeTokens, maxWidth, viewport) => {
|
|
27
|
+
const isDesktop =
|
|
28
|
+
viewport === viewports.md || viewport === viewports.lg || viewport === viewports.xl
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
wrapper: {
|
|
32
|
+
alignItems: isDesktop ? 'center' : 'flex-start'
|
|
33
|
+
},
|
|
34
|
+
scrollContainer: {
|
|
35
|
+
width: '100%',
|
|
36
|
+
...(isDesktop && { maxWidth })
|
|
37
|
+
},
|
|
38
|
+
container: {
|
|
39
|
+
paddingTop: themeTokens.mainContainerTopPadding,
|
|
40
|
+
paddingBottom: themeTokens.mainContainerBottomPadding,
|
|
41
|
+
paddingLeft: themeTokens.mainContainerLeftPadding,
|
|
42
|
+
paddingRight: themeTokens.mainContainerRightPadding,
|
|
43
|
+
gap: themeTokens.mainContainerGap,
|
|
44
|
+
...(isDesktop && {
|
|
45
|
+
alignItems: 'flex-start',
|
|
46
|
+
justifyContent: 'center'
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A horizontal scrollable shortcuts component that displays a collection of shortcut items.
|
|
54
|
+
* This component automatically injects shared configuration props to all ShortcutsItem children
|
|
55
|
+
* via React.cloneElement, including variant settings, hideLabels, and iconVariant.
|
|
56
|
+
*
|
|
57
|
+
* @component
|
|
58
|
+
* @param {Object} props - Component properties
|
|
59
|
+
* @param {Object} [props.tokens] - Theme tokens to customize the component's appearance
|
|
60
|
+
* @param {Object} [props.variant] - Visual variant configuration for the shortcuts container and its items
|
|
61
|
+
* @param {string} [props.variant.width] - Width variant to apply to all items (e.g., 'equal', 'dynamic')
|
|
62
|
+
* @param {Object} [props.scrollButtonTokens] - Tokens to customize scroll button appearance
|
|
63
|
+
* @param {boolean} [props.hideLabels=false] - Whether to hide labels on all shortcut items (can be overridden per item)
|
|
64
|
+
* @param {Object} [props.iconVariant] - Icon variant to apply to all shortcut items (can be overridden per item)
|
|
65
|
+
* @param {React.ReactNode} props.children - ShortcutsItem components to render
|
|
66
|
+
* @param {React.Ref} ref - Forwarded ref to the component's root element
|
|
67
|
+
* @returns {React.ReactElement} Rendered shortcuts component with horizontal scroll functionality
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* <Shortcuts hideLabels={false} variant={{ width: 'equal' }}>
|
|
71
|
+
* <ShortcutsItem icon={HomeIcon} label="Home" href="/home" />
|
|
72
|
+
* <ShortcutsItem icon={SettingsIcon} label="Settings" href="/settings" />
|
|
73
|
+
* </Shortcuts>
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // Item-level props override container props
|
|
77
|
+
* <Shortcuts hideLabels iconVariant={{ size: 'small' }}>
|
|
78
|
+
* <ShortcutsItem icon={HomeIcon} label="Home" hideLabel={false} />
|
|
79
|
+
* <ShortcutsItem icon={SettingsIcon} label="Settings" />
|
|
80
|
+
* </Shortcuts>
|
|
81
|
+
*/
|
|
82
|
+
const Shortcuts = React.forwardRef(
|
|
83
|
+
(
|
|
84
|
+
{ tokens, variant, scrollButtonTokens, hideLabels = false, iconVariant, children, ...rest },
|
|
85
|
+
ref
|
|
86
|
+
) => {
|
|
87
|
+
const viewport = useViewport()
|
|
88
|
+
const themeTokens = useThemeTokens('Shortcuts', tokens, variant, {
|
|
89
|
+
viewport
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const { themeOptions } = useTheme()
|
|
93
|
+
const maxWidth = useResponsiveProp(
|
|
94
|
+
themeOptions?.contentMaxWidth,
|
|
95
|
+
viewports.map.get(viewports.xl)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
const [itemPositions] = useItemPositions()
|
|
99
|
+
|
|
100
|
+
const [maxItemWidth, setMaxItemWidth] = React.useState(null)
|
|
101
|
+
|
|
102
|
+
const registerWidth = React.useCallback(
|
|
103
|
+
(width) => setMaxItemWidth((prev) => (prev == null || width > prev ? width : prev)),
|
|
104
|
+
[]
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
const styles = selectStyles(themeTokens, maxWidth, viewport)
|
|
108
|
+
|
|
109
|
+
const childrenWithProps = React.Children.map(children, (child) => {
|
|
110
|
+
if (!React.isValidElement(child)) {
|
|
111
|
+
return child
|
|
112
|
+
}
|
|
113
|
+
return React.cloneElement(child, {
|
|
114
|
+
maxWidth: maxItemWidth,
|
|
115
|
+
registerWidth,
|
|
116
|
+
containerVariant: variant,
|
|
117
|
+
containerHideLabels: hideLabels,
|
|
118
|
+
containerIconVariant: iconVariant
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<View style={[staticStyles.wrapper, styles.wrapper]} ref={ref} {...selectProps(rest)}>
|
|
124
|
+
<View style={styles.scrollContainer}>
|
|
125
|
+
<HorizontalScroll
|
|
126
|
+
ScrollButton={HorizontalScrollButton}
|
|
127
|
+
itemPositions={itemPositions}
|
|
128
|
+
tokens={selectHorizontalScrollTokens(themeTokens)}
|
|
129
|
+
scrollButtonTokens={scrollButtonTokens}
|
|
130
|
+
variant={{ hideNavigationButtons: Platform.OS !== 'web' }}
|
|
131
|
+
>
|
|
132
|
+
<View style={[staticStyles.container, styles.container]}>{childrenWithProps}</View>
|
|
133
|
+
</HorizontalScroll>
|
|
134
|
+
</View>
|
|
135
|
+
</View>
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
Shortcuts.displayName = 'Shortcuts'
|
|
141
|
+
|
|
142
|
+
Shortcuts.propTypes = {
|
|
143
|
+
...selectedSystemPropTypes,
|
|
144
|
+
tokens: getTokensPropType('Shortcuts'),
|
|
145
|
+
variant: variantProp.propType,
|
|
146
|
+
/**
|
|
147
|
+
* Custom tokens for `HorizontalScrollButton`
|
|
148
|
+
*/
|
|
149
|
+
scrollButtonTokens: getTokensPropType('HorizontalScrollButton'),
|
|
150
|
+
/**
|
|
151
|
+
* Hide labels for all ShortcutsItem children. When true, labels are visually hidden but remain accessible to screen readers via the icon's accessibilityLabel.
|
|
152
|
+
*/
|
|
153
|
+
hideLabels: PropTypes.bool,
|
|
154
|
+
/**
|
|
155
|
+
* Icon variant to apply to all ShortcutsItem children.
|
|
156
|
+
*/
|
|
157
|
+
iconVariant: variantProp.propType,
|
|
158
|
+
/**
|
|
159
|
+
* ShortcutsItem components to be rendered within the Shortcuts container
|
|
160
|
+
*/
|
|
161
|
+
children: PropTypes.node
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const staticStyles = StyleSheet.create({
|
|
165
|
+
wrapper: {
|
|
166
|
+
flexGrow: 1
|
|
167
|
+
},
|
|
168
|
+
container: {
|
|
169
|
+
flexDirection: 'row',
|
|
170
|
+
flex: 1
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
export default Shortcuts
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Image, Platform, Pressable, StyleSheet, View } from 'react-native'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
|
|
5
|
+
import { applyTextStyles, useThemeTokensCallback } from '../ThemeProvider'
|
|
6
|
+
import {
|
|
7
|
+
a11yProps,
|
|
8
|
+
clickProps,
|
|
9
|
+
getTokensPropType,
|
|
10
|
+
hrefAttrsProp,
|
|
11
|
+
linkProps,
|
|
12
|
+
resolvePressableState,
|
|
13
|
+
selectSystemProps,
|
|
14
|
+
variantProp,
|
|
15
|
+
viewProps,
|
|
16
|
+
wrapStringsInText
|
|
17
|
+
} from '../utils'
|
|
18
|
+
import Icon from '../Icon'
|
|
19
|
+
|
|
20
|
+
const DYNAMIC_WIDTH_VARIANT = 'dynamic'
|
|
21
|
+
const EQUAL_WIDTH_VARIANT = 'equal'
|
|
22
|
+
|
|
23
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps, viewProps])
|
|
24
|
+
|
|
25
|
+
const selectPressableStyles = (tokens, widthVariant, equalWidth) => {
|
|
26
|
+
const styles = {
|
|
27
|
+
borderColor: tokens.borderColor,
|
|
28
|
+
borderRadius: tokens.borderRadius,
|
|
29
|
+
borderWidth: tokens.borderWidth,
|
|
30
|
+
...Platform.select({
|
|
31
|
+
web: {
|
|
32
|
+
outline: 'none'
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (widthVariant === DYNAMIC_WIDTH_VARIANT) {
|
|
38
|
+
styles.width = 'auto'
|
|
39
|
+
} else if (widthVariant === EQUAL_WIDTH_VARIANT) {
|
|
40
|
+
if (equalWidth) {
|
|
41
|
+
styles.width = equalWidth
|
|
42
|
+
} else {
|
|
43
|
+
styles.minWidth = tokens.width
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
styles.width = tokens.width
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return styles
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const selectIconContainerStyles = (tokens) => ({
|
|
53
|
+
paddingBottom: tokens.iconContainerPaddingBottom,
|
|
54
|
+
paddingLeft: tokens.iconContainerPaddingLeft,
|
|
55
|
+
paddingRight: tokens.iconContainerPaddingRight,
|
|
56
|
+
paddingTop: tokens.iconContainerPaddingTop
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const selectIconVariant = () => ({
|
|
60
|
+
background: true,
|
|
61
|
+
padding: 'medium'
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const selectIconTokens = (tokens) => ({
|
|
65
|
+
backgroundColor: tokens.iconBackgroundColor,
|
|
66
|
+
color: tokens.iconColor,
|
|
67
|
+
size: tokens.iconSize,
|
|
68
|
+
width: tokens.iconWidth
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const selectImageStyles = (tokens) => ({
|
|
72
|
+
width: tokens.imageWidth,
|
|
73
|
+
height: tokens.imageHeight
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const selectLabelContainerStyles = (tokens) => ({
|
|
77
|
+
paddingBottom: tokens.labelContainerPaddingBottom,
|
|
78
|
+
paddingLeft: tokens.labelContainerPaddingLeft,
|
|
79
|
+
paddingRight: tokens.labelContainerPaddingRight,
|
|
80
|
+
paddingTop: tokens.labelContainerPaddingTop
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const selectTitleTextStyles = (tokens) =>
|
|
84
|
+
applyTextStyles({
|
|
85
|
+
fontColor: tokens.labelFontColor,
|
|
86
|
+
fontName: tokens.labelFontName,
|
|
87
|
+
fontSize: tokens.labelFontSize,
|
|
88
|
+
fontWeight: tokens.labelFontWeight,
|
|
89
|
+
lineHeight: tokens.labelLineHeight,
|
|
90
|
+
textDecorationLine: tokens.labelUnderline,
|
|
91
|
+
textAlign: tokens.labelTextAlign
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* A clickable shortcut item component that displays an icon or image with an optional label.
|
|
96
|
+
* Can be used within a Shortcuts container to create a grid of navigation shortcuts.
|
|
97
|
+
*
|
|
98
|
+
* @component
|
|
99
|
+
* @param {Object} props - Component props
|
|
100
|
+
* @param {string} [props.icon] - Icon identifier to display
|
|
101
|
+
* @param {Object} [props.image={ src: '', alt: '' }] - Image object with src and alt properties
|
|
102
|
+
* @param {string} [props.image.src] - Image source URL
|
|
103
|
+
* @param {string} [props.image.alt] - Image alt text for accessibility
|
|
104
|
+
* @param {string|React.ReactNode} props.label - Label text or content to display below the icon/image
|
|
105
|
+
* @param {boolean} [props.hideLabel=false] - Whether to hide the label for this specific item
|
|
106
|
+
* @param {string} [props.href] - Link URL for navigation
|
|
107
|
+
* @param {Object} [props.iconVariant] - Icon variant to apply to this specific item
|
|
108
|
+
* @param {Object} [props.tokens] - Theme tokens to customize appearance
|
|
109
|
+
* @param {Object} [props.variant] - Variant configuration object for this specific item
|
|
110
|
+
* @param {string} [props.variant.width] - Width variant (e.g., 'dynamic', 'equal')
|
|
111
|
+
* @param {Function} [props.onPressableStateChange] - Callback function that receives the pressable state object (pressed, hovered, focused)
|
|
112
|
+
* @param {number} [props.maxWidth] - Maximum width for equal width variant (injected by Shortcuts container)
|
|
113
|
+
* @param {Function} [props.registerWidth] - Callback to register width for equal width variant (injected by Shortcuts container)
|
|
114
|
+
* @param {Object} [props.containerVariant] - Variant configuration from Shortcuts container (injected by Shortcuts container)
|
|
115
|
+
* @param {boolean} [props.containerHideLabels] - Hide labels setting from Shortcuts container (injected by Shortcuts container)
|
|
116
|
+
* @param {Object} [props.containerIconVariant] - Icon variant from Shortcuts container (injected by Shortcuts container)
|
|
117
|
+
* @param {React.Ref} ref - Forwarded ref to the Pressable component
|
|
118
|
+
* @returns {React.ReactElement} The rendered shortcut item
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* <ShortcutsItem
|
|
122
|
+
* icon={HomeIcon}
|
|
123
|
+
* label="Home"
|
|
124
|
+
* href="/home"
|
|
125
|
+
* onPressableStateChange={(state) => console.log(state)}
|
|
126
|
+
* />
|
|
127
|
+
*/
|
|
128
|
+
const ShortcutsItem = React.forwardRef(
|
|
129
|
+
(
|
|
130
|
+
{
|
|
131
|
+
icon,
|
|
132
|
+
image = { src: '', alt: '' },
|
|
133
|
+
label,
|
|
134
|
+
hideLabel = false,
|
|
135
|
+
href,
|
|
136
|
+
iconVariant,
|
|
137
|
+
tokens,
|
|
138
|
+
variant,
|
|
139
|
+
onPressableStateChange,
|
|
140
|
+
maxWidth,
|
|
141
|
+
registerWidth,
|
|
142
|
+
containerVariant,
|
|
143
|
+
containerHideLabels,
|
|
144
|
+
containerIconVariant,
|
|
145
|
+
...rest
|
|
146
|
+
},
|
|
147
|
+
ref
|
|
148
|
+
) => {
|
|
149
|
+
const mergedVariant = { ...containerVariant, ...variant }
|
|
150
|
+
const widthVariant = mergedVariant?.width
|
|
151
|
+
const shouldHideLabel = hideLabel || containerHideLabels
|
|
152
|
+
const mergedIconVariant = iconVariant ?? containerIconVariant
|
|
153
|
+
|
|
154
|
+
const getThemeTokens = useThemeTokensCallback('ShortcutsItem', tokens, mergedVariant)
|
|
155
|
+
const getTokens = (pressableState) => getThemeTokens(resolvePressableState(pressableState))
|
|
156
|
+
|
|
157
|
+
const { onPress, ...props } = clickProps.toPressProps(rest)
|
|
158
|
+
const { hrefAttrs, rawRest } = hrefAttrsProp.bundle(props)
|
|
159
|
+
const selectedProps = selectProps({
|
|
160
|
+
href,
|
|
161
|
+
onPress: linkProps.handleHref({ href, onPress }),
|
|
162
|
+
hrefAttrs,
|
|
163
|
+
...rawRest
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
const handleLayout = (event) => {
|
|
167
|
+
if (widthVariant === EQUAL_WIDTH_VARIANT && registerWidth) {
|
|
168
|
+
const { width } = event.nativeEvent.layout
|
|
169
|
+
registerWidth(width)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<Pressable
|
|
175
|
+
ref={ref}
|
|
176
|
+
style={(pressableState) =>
|
|
177
|
+
selectPressableStyles(getTokens(pressableState), widthVariant, maxWidth)
|
|
178
|
+
}
|
|
179
|
+
onLayout={handleLayout}
|
|
180
|
+
{...selectedProps}
|
|
181
|
+
>
|
|
182
|
+
{(pressableState) => {
|
|
183
|
+
const themeTokens = getTokens(pressableState)
|
|
184
|
+
|
|
185
|
+
if (onPressableStateChange) {
|
|
186
|
+
onPressableStateChange(resolvePressableState(pressableState))
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<View style={staticStyles.container}>
|
|
191
|
+
{icon && (
|
|
192
|
+
<View style={selectIconContainerStyles(themeTokens)}>
|
|
193
|
+
<Icon
|
|
194
|
+
icon={icon}
|
|
195
|
+
variant={mergedIconVariant ?? selectIconVariant()}
|
|
196
|
+
tokens={mergedIconVariant ? {} : selectIconTokens(themeTokens)}
|
|
197
|
+
{...(Platform.OS === 'web' && { accessibilityLabel: label })}
|
|
198
|
+
/>
|
|
199
|
+
</View>
|
|
200
|
+
)}
|
|
201
|
+
{!icon && image && (
|
|
202
|
+
<Image
|
|
203
|
+
source={image.src}
|
|
204
|
+
alt={image.alt}
|
|
205
|
+
style={selectImageStyles(themeTokens)}
|
|
206
|
+
resizeMethod="resize"
|
|
207
|
+
accessibilityIgnoresInvertColors
|
|
208
|
+
/>
|
|
209
|
+
)}
|
|
210
|
+
{label && !shouldHideLabel && (
|
|
211
|
+
<View style={[staticStyles.label, selectLabelContainerStyles(themeTokens)]}>
|
|
212
|
+
{wrapStringsInText(label, { style: selectTitleTextStyles(themeTokens) })}
|
|
213
|
+
</View>
|
|
214
|
+
)}
|
|
215
|
+
</View>
|
|
216
|
+
)
|
|
217
|
+
}}
|
|
218
|
+
</Pressable>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
ShortcutsItem.displayName = 'ShortcutsItem'
|
|
224
|
+
|
|
225
|
+
ShortcutsItem.propTypes = {
|
|
226
|
+
...selectedSystemPropTypes,
|
|
227
|
+
tokens: getTokensPropType('ShortcutsItem'),
|
|
228
|
+
variant: variantProp.propType,
|
|
229
|
+
/**
|
|
230
|
+
* Icon for the ShortcutsItem
|
|
231
|
+
*/
|
|
232
|
+
icon: PropTypes.elementType,
|
|
233
|
+
/**
|
|
234
|
+
* Image for the ShortcutsItem
|
|
235
|
+
*/
|
|
236
|
+
image: PropTypes.shape({
|
|
237
|
+
src: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]),
|
|
238
|
+
alt: PropTypes.string
|
|
239
|
+
}),
|
|
240
|
+
/**
|
|
241
|
+
* Label for the ShortcutsItem
|
|
242
|
+
*/
|
|
243
|
+
label: PropTypes.string,
|
|
244
|
+
/**
|
|
245
|
+
* Hide the label for this specific ShortcutsItem. When true, the label is visually hidden but remains accessible to screen readers via the icon's accessibilityLabel.
|
|
246
|
+
*/
|
|
247
|
+
hideLabel: PropTypes.bool,
|
|
248
|
+
/**
|
|
249
|
+
* href for the ShortcutsItem
|
|
250
|
+
*/
|
|
251
|
+
href: PropTypes.string,
|
|
252
|
+
/**
|
|
253
|
+
* Icon variant for this specific ShortcutsItem
|
|
254
|
+
*/
|
|
255
|
+
iconVariant: variantProp.propType,
|
|
256
|
+
/**
|
|
257
|
+
* Callback function that receives the pressable state object containing pressed, hovered, and focused boolean properties
|
|
258
|
+
*/
|
|
259
|
+
onPressableStateChange: PropTypes.func,
|
|
260
|
+
/**
|
|
261
|
+
* Maximum width for equal width variant (automatically injected by Shortcuts container)
|
|
262
|
+
* @private
|
|
263
|
+
*/
|
|
264
|
+
maxWidth: PropTypes.number,
|
|
265
|
+
/**
|
|
266
|
+
* Callback to register width for equal width variant (automatically injected by Shortcuts container)
|
|
267
|
+
* @private
|
|
268
|
+
*/
|
|
269
|
+
registerWidth: PropTypes.func,
|
|
270
|
+
/**
|
|
271
|
+
* Variant configuration from Shortcuts container (automatically injected by Shortcuts container)
|
|
272
|
+
* @private
|
|
273
|
+
*/
|
|
274
|
+
containerVariant: variantProp.propType,
|
|
275
|
+
/**
|
|
276
|
+
* Hide labels setting from Shortcuts container (automatically injected by Shortcuts container)
|
|
277
|
+
* @private
|
|
278
|
+
*/
|
|
279
|
+
containerHideLabels: PropTypes.bool,
|
|
280
|
+
/**
|
|
281
|
+
* Icon variant from Shortcuts container (automatically injected by Shortcuts container)
|
|
282
|
+
* @private
|
|
283
|
+
*/
|
|
284
|
+
containerIconVariant: variantProp.propType
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const staticStyles = StyleSheet.create({
|
|
288
|
+
container: {
|
|
289
|
+
alignItems: 'center',
|
|
290
|
+
justifyContent: 'center'
|
|
291
|
+
},
|
|
292
|
+
label: {
|
|
293
|
+
flexWrap: 'wrap'
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
export default ShortcutsItem
|
|
@@ -313,7 +313,7 @@ const TextInputBase = React.forwardRef(
|
|
|
313
313
|
icon={ClearButtonIcon}
|
|
314
314
|
key="clear"
|
|
315
315
|
onPress={handleClear}
|
|
316
|
-
variant={{
|
|
316
|
+
variant={{ subtle: true }}
|
|
317
317
|
/>
|
|
318
318
|
)
|
|
319
319
|
}
|
|
@@ -329,7 +329,7 @@ const TextInputBase = React.forwardRef(
|
|
|
329
329
|
icon={!showPassword ? passwordShowButtonIcon : passwordHideButtonIcon}
|
|
330
330
|
key={!showPassword ? 'hide' : 'show'}
|
|
331
331
|
onPress={handleShowOrHide}
|
|
332
|
-
variant={{
|
|
332
|
+
variant={{ subtle: true, inactive: variant.inactive, size: 'large' }}
|
|
333
333
|
tokens={{ width: 40, height: 40 }}
|
|
334
334
|
/>
|
|
335
335
|
)
|
|
@@ -127,12 +127,12 @@ const Tooltip = React.forwardRef(
|
|
|
127
127
|
nativeID,
|
|
128
128
|
activateOnHover = false,
|
|
129
129
|
tooltipButtonTokens,
|
|
130
|
+
testID,
|
|
130
131
|
...rest
|
|
131
132
|
},
|
|
132
133
|
ref
|
|
133
134
|
) => {
|
|
134
135
|
const [isOpen, setIsOpen] = React.useState(false)
|
|
135
|
-
|
|
136
136
|
const controlRef = React.useRef()
|
|
137
137
|
const [controlLayout, setControlLayout] = React.useState(null)
|
|
138
138
|
const [tooltipDimensions, setTooltipDimensions] = React.useState(null)
|
|
@@ -276,6 +276,7 @@ const Tooltip = React.forwardRef(
|
|
|
276
276
|
}
|
|
277
277
|
})
|
|
278
278
|
]}
|
|
279
|
+
testID={testID}
|
|
279
280
|
{...selectProps(rest)}
|
|
280
281
|
>
|
|
281
282
|
<Pressable
|
package/src/index.js
CHANGED
|
@@ -51,6 +51,7 @@ export { default as RadioCard, RadioCardGroup } from './RadioCard'
|
|
|
51
51
|
export { default as Responsive } from './Responsive'
|
|
52
52
|
export { default as Search } from './Search'
|
|
53
53
|
export { default as Select } from './Select'
|
|
54
|
+
export { default as Shortcuts, ShortcutsItem } from './Shortcuts'
|
|
54
55
|
export { default as SideNav } from './SideNav'
|
|
55
56
|
export { default as Skeleton } from './Skeleton'
|
|
56
57
|
export { default as SkipLink } from './SkipLink'
|
package/src/utils/index.js
CHANGED
|
@@ -27,3 +27,4 @@ export { default as formatImageSource } from './formatImageSource'
|
|
|
27
27
|
export { default as getSpacingScale } from './getSpacingScale'
|
|
28
28
|
export { default as useVariants } from './useVariants'
|
|
29
29
|
export { default as isTouchDevice } from './isTouchDevice'
|
|
30
|
+
export { default as resolveContentMaxWidth } from './resolveContentMaxWidth'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const CONTENT_MAX_WIDTH = 'max'
|
|
2
|
+
const CONTENT_FULL_WIDTH = 'full'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the maximum width for content based on the provided value and responsive width.
|
|
6
|
+
*
|
|
7
|
+
* @param {number|string|null|undefined} contentMaxWidthValue - The maximum width value for the content.
|
|
8
|
+
* Can be a number, a special string constant (e.g., CONTENT_FULL_WIDTH, CONTENT_MAX_WIDTH), or null/undefined.
|
|
9
|
+
* @param {number} responsiveWidth - The responsive width to use when contentMaxWidthValue is CONTENT_MAX_WIDTH.
|
|
10
|
+
* @returns {number|string|null} The resolved maximum width value, or null if full width is desired.
|
|
11
|
+
*/
|
|
12
|
+
const resolveContentMaxWidth = (contentMaxWidthValue, responsiveWidth) => {
|
|
13
|
+
if (!contentMaxWidthValue || contentMaxWidthValue === CONTENT_FULL_WIDTH) {
|
|
14
|
+
return null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (Number.isFinite(contentMaxWidthValue)) {
|
|
18
|
+
return contentMaxWidthValue
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (contentMaxWidthValue === CONTENT_MAX_WIDTH) {
|
|
22
|
+
return responsiveWidth
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return contentMaxWidthValue
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default resolveContentMaxWidth
|
package/types/Listbox.d.ts
CHANGED
|
@@ -40,6 +40,29 @@ type ListboxTokens = {
|
|
|
40
40
|
itemHeight?: number
|
|
41
41
|
groupHeight?: number
|
|
42
42
|
lineHeight?: number
|
|
43
|
+
secondLevelHeaderBackgroundColor?: string
|
|
44
|
+
secondLevelHeaderPaddingTop?: number
|
|
45
|
+
secondLevelHeaderPaddingBottom?: number
|
|
46
|
+
secondLevelHeaderPaddingLeft?: number
|
|
47
|
+
secondLevelHeaderPaddingRight?: number
|
|
48
|
+
secondLevelBackIcon?: string
|
|
49
|
+
secondLevelBackIconColor?: string
|
|
50
|
+
secondLevelBackIconSize?: number
|
|
51
|
+
secondLevelBackLinkColor?: string
|
|
52
|
+
secondLevelBackLinkFontSize?: number
|
|
53
|
+
secondLevelBackLinkFontName?: string
|
|
54
|
+
secondLevelBackLinkFontWeight?: string
|
|
55
|
+
secondLevelCloseIcon?: string
|
|
56
|
+
secondLevelCloseIconColor?: string
|
|
57
|
+
secondLevelCloseIconSize?: number
|
|
58
|
+
secondLevelCloseButtonBackgroundColor?: string
|
|
59
|
+
secondLevelCloseButtonBorderColor?: string
|
|
60
|
+
secondLevelCloseButtonBorderWidth?: number | string
|
|
61
|
+
secondLevelCloseButtonBorderRadius?: number | string
|
|
62
|
+
secondLevelCloseButtonPadding?: number
|
|
63
|
+
secondLevelDividerColor?: string
|
|
64
|
+
secondLevelDividerWidth?: number
|
|
65
|
+
secondLevelParentIcon?: string
|
|
43
66
|
}
|
|
44
67
|
|
|
45
68
|
type ListboxItems = {
|
|
@@ -55,6 +78,7 @@ export interface ListboxProps {
|
|
|
55
78
|
LinkRouter?: React.ElementType
|
|
56
79
|
linkRouterProps?: object
|
|
57
80
|
tokens?: ListboxTokens
|
|
81
|
+
variant?: { secondLevel?: boolean }
|
|
58
82
|
selectedId?: string
|
|
59
83
|
onClose?: () => void
|
|
60
84
|
}
|