@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,160 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
4
|
+
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
5
|
+
import View from "react-native-web/dist/exports/View";
|
|
6
|
+
import { viewports } from '@telus-uds/system-constants';
|
|
7
|
+
import { useTheme, useThemeTokens } from '../ThemeProvider';
|
|
8
|
+
import { useViewport } from '../ViewportProvider';
|
|
9
|
+
import { a11yProps, getTokensPropType, selectSystemProps, useResponsiveProp, variantProp, viewProps } from '../utils';
|
|
10
|
+
import HorizontalScroll, { horizontalScrollUtils, HorizontalScrollButton } from '../HorizontalScroll';
|
|
11
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
13
|
+
const {
|
|
14
|
+
selectHorizontalScrollTokens,
|
|
15
|
+
useItemPositions
|
|
16
|
+
} = horizontalScrollUtils;
|
|
17
|
+
const selectStyles = (themeTokens, maxWidth, viewport) => {
|
|
18
|
+
const isDesktop = viewport === viewports.md || viewport === viewports.lg || viewport === viewports.xl;
|
|
19
|
+
return {
|
|
20
|
+
wrapper: {
|
|
21
|
+
alignItems: isDesktop ? 'center' : 'flex-start'
|
|
22
|
+
},
|
|
23
|
+
scrollContainer: {
|
|
24
|
+
width: '100%',
|
|
25
|
+
...(isDesktop && {
|
|
26
|
+
maxWidth
|
|
27
|
+
})
|
|
28
|
+
},
|
|
29
|
+
container: {
|
|
30
|
+
paddingTop: themeTokens.mainContainerTopPadding,
|
|
31
|
+
paddingBottom: themeTokens.mainContainerBottomPadding,
|
|
32
|
+
paddingLeft: themeTokens.mainContainerLeftPadding,
|
|
33
|
+
paddingRight: themeTokens.mainContainerRightPadding,
|
|
34
|
+
gap: themeTokens.mainContainerGap,
|
|
35
|
+
...(isDesktop && {
|
|
36
|
+
alignItems: 'flex-start',
|
|
37
|
+
justifyContent: 'center'
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A horizontal scrollable shortcuts component that displays a collection of shortcut items.
|
|
45
|
+
* This component automatically injects shared configuration props to all ShortcutsItem children
|
|
46
|
+
* via React.cloneElement, including variant settings, hideLabels, and iconVariant.
|
|
47
|
+
*
|
|
48
|
+
* @component
|
|
49
|
+
* @param {Object} props - Component properties
|
|
50
|
+
* @param {Object} [props.tokens] - Theme tokens to customize the component's appearance
|
|
51
|
+
* @param {Object} [props.variant] - Visual variant configuration for the shortcuts container and its items
|
|
52
|
+
* @param {string} [props.variant.width] - Width variant to apply to all items (e.g., 'equal', 'dynamic')
|
|
53
|
+
* @param {Object} [props.scrollButtonTokens] - Tokens to customize scroll button appearance
|
|
54
|
+
* @param {boolean} [props.hideLabels=false] - Whether to hide labels on all shortcut items (can be overridden per item)
|
|
55
|
+
* @param {Object} [props.iconVariant] - Icon variant to apply to all shortcut items (can be overridden per item)
|
|
56
|
+
* @param {React.ReactNode} props.children - ShortcutsItem components to render
|
|
57
|
+
* @param {React.Ref} ref - Forwarded ref to the component's root element
|
|
58
|
+
* @returns {React.ReactElement} Rendered shortcuts component with horizontal scroll functionality
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* <Shortcuts hideLabels={false} variant={{ width: 'equal' }}>
|
|
62
|
+
* <ShortcutsItem icon={HomeIcon} label="Home" href="/home" />
|
|
63
|
+
* <ShortcutsItem icon={SettingsIcon} label="Settings" href="/settings" />
|
|
64
|
+
* </Shortcuts>
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // Item-level props override container props
|
|
68
|
+
* <Shortcuts hideLabels iconVariant={{ size: 'small' }}>
|
|
69
|
+
* <ShortcutsItem icon={HomeIcon} label="Home" hideLabel={false} />
|
|
70
|
+
* <ShortcutsItem icon={SettingsIcon} label="Settings" />
|
|
71
|
+
* </Shortcuts>
|
|
72
|
+
*/
|
|
73
|
+
const Shortcuts = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
74
|
+
let {
|
|
75
|
+
tokens,
|
|
76
|
+
variant,
|
|
77
|
+
scrollButtonTokens,
|
|
78
|
+
hideLabels = false,
|
|
79
|
+
iconVariant,
|
|
80
|
+
children,
|
|
81
|
+
...rest
|
|
82
|
+
} = _ref;
|
|
83
|
+
const viewport = useViewport();
|
|
84
|
+
const themeTokens = useThemeTokens('Shortcuts', tokens, variant, {
|
|
85
|
+
viewport
|
|
86
|
+
});
|
|
87
|
+
const {
|
|
88
|
+
themeOptions
|
|
89
|
+
} = useTheme();
|
|
90
|
+
const maxWidth = useResponsiveProp(themeOptions?.contentMaxWidth, viewports.map.get(viewports.xl));
|
|
91
|
+
const [itemPositions] = useItemPositions();
|
|
92
|
+
const [maxItemWidth, setMaxItemWidth] = React.useState(null);
|
|
93
|
+
const registerWidth = React.useCallback(width => setMaxItemWidth(prev => prev == null || width > prev ? width : prev), []);
|
|
94
|
+
const styles = selectStyles(themeTokens, maxWidth, viewport);
|
|
95
|
+
const childrenWithProps = React.Children.map(children, child => {
|
|
96
|
+
if (! /*#__PURE__*/React.isValidElement(child)) {
|
|
97
|
+
return child;
|
|
98
|
+
}
|
|
99
|
+
return /*#__PURE__*/React.cloneElement(child, {
|
|
100
|
+
maxWidth: maxItemWidth,
|
|
101
|
+
registerWidth,
|
|
102
|
+
containerVariant: variant,
|
|
103
|
+
containerHideLabels: hideLabels,
|
|
104
|
+
containerIconVariant: iconVariant
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
return /*#__PURE__*/_jsx(View, {
|
|
108
|
+
style: [staticStyles.wrapper, styles.wrapper],
|
|
109
|
+
ref: ref,
|
|
110
|
+
...selectProps(rest),
|
|
111
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
112
|
+
style: styles.scrollContainer,
|
|
113
|
+
children: /*#__PURE__*/_jsx(HorizontalScroll, {
|
|
114
|
+
ScrollButton: HorizontalScrollButton,
|
|
115
|
+
itemPositions: itemPositions,
|
|
116
|
+
tokens: selectHorizontalScrollTokens(themeTokens),
|
|
117
|
+
scrollButtonTokens: scrollButtonTokens,
|
|
118
|
+
variant: {
|
|
119
|
+
hideNavigationButtons: Platform.OS !== 'web'
|
|
120
|
+
},
|
|
121
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
122
|
+
style: [staticStyles.container, styles.container],
|
|
123
|
+
children: childrenWithProps
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
Shortcuts.displayName = 'Shortcuts';
|
|
130
|
+
Shortcuts.propTypes = {
|
|
131
|
+
...selectedSystemPropTypes,
|
|
132
|
+
tokens: getTokensPropType('Shortcuts'),
|
|
133
|
+
variant: variantProp.propType,
|
|
134
|
+
/**
|
|
135
|
+
* Custom tokens for `HorizontalScrollButton`
|
|
136
|
+
*/
|
|
137
|
+
scrollButtonTokens: getTokensPropType('HorizontalScrollButton'),
|
|
138
|
+
/**
|
|
139
|
+
* Hide labels for all ShortcutsItem children. When true, labels are visually hidden but remain accessible to screen readers via the icon's accessibilityLabel.
|
|
140
|
+
*/
|
|
141
|
+
hideLabels: PropTypes.bool,
|
|
142
|
+
/**
|
|
143
|
+
* Icon variant to apply to all ShortcutsItem children.
|
|
144
|
+
*/
|
|
145
|
+
iconVariant: variantProp.propType,
|
|
146
|
+
/**
|
|
147
|
+
* ShortcutsItem components to be rendered within the Shortcuts container
|
|
148
|
+
*/
|
|
149
|
+
children: PropTypes.node
|
|
150
|
+
};
|
|
151
|
+
const staticStyles = StyleSheet.create({
|
|
152
|
+
wrapper: {
|
|
153
|
+
flexGrow: 1
|
|
154
|
+
},
|
|
155
|
+
container: {
|
|
156
|
+
flexDirection: 'row',
|
|
157
|
+
flex: 1
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
export default Shortcuts;
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Image from "react-native-web/dist/exports/Image";
|
|
3
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
4
|
+
import Pressable from "react-native-web/dist/exports/Pressable";
|
|
5
|
+
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
6
|
+
import View from "react-native-web/dist/exports/View";
|
|
7
|
+
import PropTypes from 'prop-types';
|
|
8
|
+
import { applyTextStyles, useThemeTokensCallback } from '../ThemeProvider';
|
|
9
|
+
import { a11yProps, clickProps, getTokensPropType, hrefAttrsProp, linkProps, resolvePressableState, selectSystemProps, variantProp, viewProps, wrapStringsInText } from '../utils';
|
|
10
|
+
import Icon from '../Icon';
|
|
11
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
12
|
+
const DYNAMIC_WIDTH_VARIANT = 'dynamic';
|
|
13
|
+
const EQUAL_WIDTH_VARIANT = 'equal';
|
|
14
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps, viewProps]);
|
|
15
|
+
const selectPressableStyles = (tokens, widthVariant, equalWidth) => {
|
|
16
|
+
const styles = {
|
|
17
|
+
borderColor: tokens.borderColor,
|
|
18
|
+
borderRadius: tokens.borderRadius,
|
|
19
|
+
borderWidth: tokens.borderWidth,
|
|
20
|
+
...Platform.select({
|
|
21
|
+
web: {
|
|
22
|
+
outline: 'none'
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
};
|
|
26
|
+
if (widthVariant === DYNAMIC_WIDTH_VARIANT) {
|
|
27
|
+
styles.width = 'auto';
|
|
28
|
+
} else if (widthVariant === EQUAL_WIDTH_VARIANT) {
|
|
29
|
+
if (equalWidth) {
|
|
30
|
+
styles.width = equalWidth;
|
|
31
|
+
} else {
|
|
32
|
+
styles.minWidth = tokens.width;
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
styles.width = tokens.width;
|
|
36
|
+
}
|
|
37
|
+
return styles;
|
|
38
|
+
};
|
|
39
|
+
const selectIconContainerStyles = tokens => ({
|
|
40
|
+
paddingBottom: tokens.iconContainerPaddingBottom,
|
|
41
|
+
paddingLeft: tokens.iconContainerPaddingLeft,
|
|
42
|
+
paddingRight: tokens.iconContainerPaddingRight,
|
|
43
|
+
paddingTop: tokens.iconContainerPaddingTop
|
|
44
|
+
});
|
|
45
|
+
const selectIconVariant = () => ({
|
|
46
|
+
background: true,
|
|
47
|
+
padding: 'medium'
|
|
48
|
+
});
|
|
49
|
+
const selectIconTokens = tokens => ({
|
|
50
|
+
backgroundColor: tokens.iconBackgroundColor,
|
|
51
|
+
color: tokens.iconColor,
|
|
52
|
+
size: tokens.iconSize,
|
|
53
|
+
width: tokens.iconWidth
|
|
54
|
+
});
|
|
55
|
+
const selectImageStyles = tokens => ({
|
|
56
|
+
width: tokens.imageWidth,
|
|
57
|
+
height: tokens.imageHeight
|
|
58
|
+
});
|
|
59
|
+
const selectLabelContainerStyles = tokens => ({
|
|
60
|
+
paddingBottom: tokens.labelContainerPaddingBottom,
|
|
61
|
+
paddingLeft: tokens.labelContainerPaddingLeft,
|
|
62
|
+
paddingRight: tokens.labelContainerPaddingRight,
|
|
63
|
+
paddingTop: tokens.labelContainerPaddingTop
|
|
64
|
+
});
|
|
65
|
+
const selectTitleTextStyles = tokens => applyTextStyles({
|
|
66
|
+
fontColor: tokens.labelFontColor,
|
|
67
|
+
fontName: tokens.labelFontName,
|
|
68
|
+
fontSize: tokens.labelFontSize,
|
|
69
|
+
fontWeight: tokens.labelFontWeight,
|
|
70
|
+
lineHeight: tokens.labelLineHeight,
|
|
71
|
+
textDecorationLine: tokens.labelUnderline,
|
|
72
|
+
textAlign: tokens.labelTextAlign
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A clickable shortcut item component that displays an icon or image with an optional label.
|
|
77
|
+
* Can be used within a Shortcuts container to create a grid of navigation shortcuts.
|
|
78
|
+
*
|
|
79
|
+
* @component
|
|
80
|
+
* @param {Object} props - Component props
|
|
81
|
+
* @param {string} [props.icon] - Icon identifier to display
|
|
82
|
+
* @param {Object} [props.image={ src: '', alt: '' }] - Image object with src and alt properties
|
|
83
|
+
* @param {string} [props.image.src] - Image source URL
|
|
84
|
+
* @param {string} [props.image.alt] - Image alt text for accessibility
|
|
85
|
+
* @param {string|React.ReactNode} props.label - Label text or content to display below the icon/image
|
|
86
|
+
* @param {boolean} [props.hideLabel=false] - Whether to hide the label for this specific item
|
|
87
|
+
* @param {string} [props.href] - Link URL for navigation
|
|
88
|
+
* @param {Object} [props.iconVariant] - Icon variant to apply to this specific item
|
|
89
|
+
* @param {Object} [props.tokens] - Theme tokens to customize appearance
|
|
90
|
+
* @param {Object} [props.variant] - Variant configuration object for this specific item
|
|
91
|
+
* @param {string} [props.variant.width] - Width variant (e.g., 'dynamic', 'equal')
|
|
92
|
+
* @param {Function} [props.onPressableStateChange] - Callback function that receives the pressable state object (pressed, hovered, focused)
|
|
93
|
+
* @param {number} [props.maxWidth] - Maximum width for equal width variant (injected by Shortcuts container)
|
|
94
|
+
* @param {Function} [props.registerWidth] - Callback to register width for equal width variant (injected by Shortcuts container)
|
|
95
|
+
* @param {Object} [props.containerVariant] - Variant configuration from Shortcuts container (injected by Shortcuts container)
|
|
96
|
+
* @param {boolean} [props.containerHideLabels] - Hide labels setting from Shortcuts container (injected by Shortcuts container)
|
|
97
|
+
* @param {Object} [props.containerIconVariant] - Icon variant from Shortcuts container (injected by Shortcuts container)
|
|
98
|
+
* @param {React.Ref} ref - Forwarded ref to the Pressable component
|
|
99
|
+
* @returns {React.ReactElement} The rendered shortcut item
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* <ShortcutsItem
|
|
103
|
+
* icon={HomeIcon}
|
|
104
|
+
* label="Home"
|
|
105
|
+
* href="/home"
|
|
106
|
+
* onPressableStateChange={(state) => console.log(state)}
|
|
107
|
+
* />
|
|
108
|
+
*/
|
|
109
|
+
const ShortcutsItem = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
110
|
+
let {
|
|
111
|
+
icon,
|
|
112
|
+
image = {
|
|
113
|
+
src: '',
|
|
114
|
+
alt: ''
|
|
115
|
+
},
|
|
116
|
+
label,
|
|
117
|
+
hideLabel = false,
|
|
118
|
+
href,
|
|
119
|
+
iconVariant,
|
|
120
|
+
tokens,
|
|
121
|
+
variant,
|
|
122
|
+
onPressableStateChange,
|
|
123
|
+
maxWidth,
|
|
124
|
+
registerWidth,
|
|
125
|
+
containerVariant,
|
|
126
|
+
containerHideLabels,
|
|
127
|
+
containerIconVariant,
|
|
128
|
+
...rest
|
|
129
|
+
} = _ref;
|
|
130
|
+
const mergedVariant = {
|
|
131
|
+
...containerVariant,
|
|
132
|
+
...variant
|
|
133
|
+
};
|
|
134
|
+
const widthVariant = mergedVariant?.width;
|
|
135
|
+
const shouldHideLabel = hideLabel || containerHideLabels;
|
|
136
|
+
const mergedIconVariant = iconVariant ?? containerIconVariant;
|
|
137
|
+
const getThemeTokens = useThemeTokensCallback('ShortcutsItem', tokens, mergedVariant);
|
|
138
|
+
const getTokens = pressableState => getThemeTokens(resolvePressableState(pressableState));
|
|
139
|
+
const {
|
|
140
|
+
onPress,
|
|
141
|
+
...props
|
|
142
|
+
} = clickProps.toPressProps(rest);
|
|
143
|
+
const {
|
|
144
|
+
hrefAttrs,
|
|
145
|
+
rawRest
|
|
146
|
+
} = hrefAttrsProp.bundle(props);
|
|
147
|
+
const selectedProps = selectProps({
|
|
148
|
+
href,
|
|
149
|
+
onPress: linkProps.handleHref({
|
|
150
|
+
href,
|
|
151
|
+
onPress
|
|
152
|
+
}),
|
|
153
|
+
hrefAttrs,
|
|
154
|
+
...rawRest
|
|
155
|
+
});
|
|
156
|
+
const handleLayout = event => {
|
|
157
|
+
if (widthVariant === EQUAL_WIDTH_VARIANT && registerWidth) {
|
|
158
|
+
const {
|
|
159
|
+
width
|
|
160
|
+
} = event.nativeEvent.layout;
|
|
161
|
+
registerWidth(width);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
return /*#__PURE__*/_jsx(Pressable, {
|
|
165
|
+
ref: ref,
|
|
166
|
+
style: pressableState => selectPressableStyles(getTokens(pressableState), widthVariant, maxWidth),
|
|
167
|
+
onLayout: handleLayout,
|
|
168
|
+
...selectedProps,
|
|
169
|
+
children: pressableState => {
|
|
170
|
+
const themeTokens = getTokens(pressableState);
|
|
171
|
+
if (onPressableStateChange) {
|
|
172
|
+
onPressableStateChange(resolvePressableState(pressableState));
|
|
173
|
+
}
|
|
174
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
175
|
+
style: staticStyles.container,
|
|
176
|
+
children: [icon && /*#__PURE__*/_jsx(View, {
|
|
177
|
+
style: selectIconContainerStyles(themeTokens),
|
|
178
|
+
children: /*#__PURE__*/_jsx(Icon, {
|
|
179
|
+
icon: icon,
|
|
180
|
+
variant: mergedIconVariant ?? selectIconVariant(),
|
|
181
|
+
tokens: mergedIconVariant ? {} : selectIconTokens(themeTokens),
|
|
182
|
+
...(Platform.OS === 'web' && {
|
|
183
|
+
accessibilityLabel: label
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
}), !icon && image && /*#__PURE__*/_jsx(Image, {
|
|
187
|
+
source: image.src,
|
|
188
|
+
alt: image.alt,
|
|
189
|
+
style: selectImageStyles(themeTokens),
|
|
190
|
+
resizeMethod: "resize",
|
|
191
|
+
accessibilityIgnoresInvertColors: true
|
|
192
|
+
}), label && !shouldHideLabel && /*#__PURE__*/_jsx(View, {
|
|
193
|
+
style: [staticStyles.label, selectLabelContainerStyles(themeTokens)],
|
|
194
|
+
children: wrapStringsInText(label, {
|
|
195
|
+
style: selectTitleTextStyles(themeTokens)
|
|
196
|
+
})
|
|
197
|
+
})]
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
ShortcutsItem.displayName = 'ShortcutsItem';
|
|
203
|
+
ShortcutsItem.propTypes = {
|
|
204
|
+
...selectedSystemPropTypes,
|
|
205
|
+
tokens: getTokensPropType('ShortcutsItem'),
|
|
206
|
+
variant: variantProp.propType,
|
|
207
|
+
/**
|
|
208
|
+
* Icon for the ShortcutsItem
|
|
209
|
+
*/
|
|
210
|
+
icon: PropTypes.elementType,
|
|
211
|
+
/**
|
|
212
|
+
* Image for the ShortcutsItem
|
|
213
|
+
*/
|
|
214
|
+
image: PropTypes.shape({
|
|
215
|
+
src: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]),
|
|
216
|
+
alt: PropTypes.string
|
|
217
|
+
}),
|
|
218
|
+
/**
|
|
219
|
+
* Label for the ShortcutsItem
|
|
220
|
+
*/
|
|
221
|
+
label: PropTypes.string,
|
|
222
|
+
/**
|
|
223
|
+
* 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.
|
|
224
|
+
*/
|
|
225
|
+
hideLabel: PropTypes.bool,
|
|
226
|
+
/**
|
|
227
|
+
* href for the ShortcutsItem
|
|
228
|
+
*/
|
|
229
|
+
href: PropTypes.string,
|
|
230
|
+
/**
|
|
231
|
+
* Icon variant for this specific ShortcutsItem
|
|
232
|
+
*/
|
|
233
|
+
iconVariant: variantProp.propType,
|
|
234
|
+
/**
|
|
235
|
+
* Callback function that receives the pressable state object containing pressed, hovered, and focused boolean properties
|
|
236
|
+
*/
|
|
237
|
+
onPressableStateChange: PropTypes.func,
|
|
238
|
+
/**
|
|
239
|
+
* Maximum width for equal width variant (automatically injected by Shortcuts container)
|
|
240
|
+
* @private
|
|
241
|
+
*/
|
|
242
|
+
maxWidth: PropTypes.number,
|
|
243
|
+
/**
|
|
244
|
+
* Callback to register width for equal width variant (automatically injected by Shortcuts container)
|
|
245
|
+
* @private
|
|
246
|
+
*/
|
|
247
|
+
registerWidth: PropTypes.func,
|
|
248
|
+
/**
|
|
249
|
+
* Variant configuration from Shortcuts container (automatically injected by Shortcuts container)
|
|
250
|
+
* @private
|
|
251
|
+
*/
|
|
252
|
+
containerVariant: variantProp.propType,
|
|
253
|
+
/**
|
|
254
|
+
* Hide labels setting from Shortcuts container (automatically injected by Shortcuts container)
|
|
255
|
+
* @private
|
|
256
|
+
*/
|
|
257
|
+
containerHideLabels: PropTypes.bool,
|
|
258
|
+
/**
|
|
259
|
+
* Icon variant from Shortcuts container (automatically injected by Shortcuts container)
|
|
260
|
+
* @private
|
|
261
|
+
*/
|
|
262
|
+
containerIconVariant: variantProp.propType
|
|
263
|
+
};
|
|
264
|
+
const staticStyles = StyleSheet.create({
|
|
265
|
+
container: {
|
|
266
|
+
alignItems: 'center',
|
|
267
|
+
justifyContent: 'center'
|
|
268
|
+
},
|
|
269
|
+
label: {
|
|
270
|
+
flexWrap: 'wrap'
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
export default ShortcutsItem;
|
|
@@ -325,7 +325,7 @@ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref8, ref) => {
|
|
|
325
325
|
icon: ClearButtonIcon,
|
|
326
326
|
onPress: handleClear,
|
|
327
327
|
variant: {
|
|
328
|
-
|
|
328
|
+
subtle: true
|
|
329
329
|
}
|
|
330
330
|
}, "clear"));
|
|
331
331
|
}
|
|
@@ -335,8 +335,7 @@ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref8, ref) => {
|
|
|
335
335
|
icon: !showPassword ? passwordShowButtonIcon : passwordHideButtonIcon,
|
|
336
336
|
onPress: handleShowOrHide,
|
|
337
337
|
variant: {
|
|
338
|
-
|
|
339
|
-
password: true,
|
|
338
|
+
subtle: true,
|
|
340
339
|
inactive: variant.inactive,
|
|
341
340
|
size: 'large'
|
|
342
341
|
},
|
|
@@ -162,6 +162,7 @@ const Tooltip = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
|
|
|
162
162
|
nativeID,
|
|
163
163
|
activateOnHover = false,
|
|
164
164
|
tooltipButtonTokens,
|
|
165
|
+
testID,
|
|
165
166
|
...rest
|
|
166
167
|
} = _ref7;
|
|
167
168
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
@@ -305,6 +306,7 @@ const Tooltip = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
|
|
|
305
306
|
display: inline ? 'inline-block' : 'flex'
|
|
306
307
|
}
|
|
307
308
|
})],
|
|
309
|
+
testID: testID,
|
|
308
310
|
...selectProps(rest),
|
|
309
311
|
children: [/*#__PURE__*/_jsx(Pressable, {
|
|
310
312
|
onPress: toggleIsOpen,
|
package/lib/esm/index.js
CHANGED
|
@@ -47,6 +47,7 @@ export { default as RadioCard, RadioCardGroup } from './RadioCard';
|
|
|
47
47
|
export { default as Responsive } from './Responsive';
|
|
48
48
|
export { default as Search } from './Search';
|
|
49
49
|
export { default as Select } from './Select';
|
|
50
|
+
export { default as Shortcuts, ShortcutsItem } from './Shortcuts';
|
|
50
51
|
export { default as SideNav } from './SideNav';
|
|
51
52
|
export { default as Skeleton } from './Skeleton';
|
|
52
53
|
export { default as SkipLink } from './SkipLink';
|
package/lib/esm/utils/index.js
CHANGED
|
@@ -26,4 +26,5 @@ export { default as convertFromMegaByteToByte } from './convertFromMegaByteToByt
|
|
|
26
26
|
export { default as formatImageSource } from './formatImageSource';
|
|
27
27
|
export { default as getSpacingScale } from './getSpacingScale';
|
|
28
28
|
export { default as useVariants } from './useVariants';
|
|
29
|
-
export { default as isTouchDevice } from './isTouchDevice';
|
|
29
|
+
export { default as isTouchDevice } from './isTouchDevice';
|
|
30
|
+
export { default as resolveContentMaxWidth } from './resolveContentMaxWidth';
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
if (Number.isFinite(contentMaxWidthValue)) {
|
|
17
|
+
return contentMaxWidthValue;
|
|
18
|
+
}
|
|
19
|
+
if (contentMaxWidthValue === CONTENT_MAX_WIDTH) {
|
|
20
|
+
return responsiveWidth;
|
|
21
|
+
}
|
|
22
|
+
return contentMaxWidthValue;
|
|
23
|
+
};
|
|
24
|
+
export default resolveContentMaxWidth;
|
package/lib/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@gorhom/portal": "^1.0.14",
|
|
13
13
|
"@react-native-picker/picker": "^2.9.0",
|
|
14
14
|
"@telus-uds/system-constants": "^3.0.0",
|
|
15
|
-
"@telus-uds/system-theme-tokens": "^4.
|
|
15
|
+
"@telus-uds/system-theme-tokens": "^4.18.0",
|
|
16
16
|
"airbnb-prop-types": "^2.16.0",
|
|
17
17
|
"css-mediaquery": "^0.1.2",
|
|
18
18
|
"expo-document-picker": "^13.0.1",
|
|
@@ -84,6 +84,6 @@
|
|
|
84
84
|
"standard-engine": {
|
|
85
85
|
"skip": true
|
|
86
86
|
},
|
|
87
|
-
"version": "3.
|
|
87
|
+
"version": "3.25.0",
|
|
88
88
|
"types": "types/index.d.ts"
|
|
89
89
|
}
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@gorhom/portal": "^1.0.14",
|
|
13
13
|
"@react-native-picker/picker": "^2.9.0",
|
|
14
14
|
"@telus-uds/system-constants": "^3.0.0",
|
|
15
|
-
"@telus-uds/system-theme-tokens": "^4.
|
|
15
|
+
"@telus-uds/system-theme-tokens": "^4.18.0",
|
|
16
16
|
"airbnb-prop-types": "^2.16.0",
|
|
17
17
|
"css-mediaquery": "^0.1.2",
|
|
18
18
|
"expo-document-picker": "^13.0.1",
|
|
@@ -84,6 +84,6 @@
|
|
|
84
84
|
"standard-engine": {
|
|
85
85
|
"skip": true
|
|
86
86
|
},
|
|
87
|
-
"version": "3.
|
|
87
|
+
"version": "3.25.0",
|
|
88
88
|
"types": "types/index.d.ts"
|
|
89
89
|
}
|
|
@@ -151,7 +151,17 @@ const ButtonGroup = React.forwardRef(
|
|
|
151
151
|
>
|
|
152
152
|
<View accessibilityRole={innerRole} style={viewStyles}>
|
|
153
153
|
{items.map(
|
|
154
|
-
(
|
|
154
|
+
(
|
|
155
|
+
{
|
|
156
|
+
label,
|
|
157
|
+
id = label,
|
|
158
|
+
accessibilityLabel,
|
|
159
|
+
ref: itemRef,
|
|
160
|
+
inactive: itemInactive,
|
|
161
|
+
...itemRest
|
|
162
|
+
},
|
|
163
|
+
index
|
|
164
|
+
) => {
|
|
155
165
|
const isSelected = currentValues.includes(id)
|
|
156
166
|
|
|
157
167
|
// Pass an object of relevant component state as first argument for any passed-in press handlers
|
|
@@ -171,6 +181,8 @@ const ButtonGroup = React.forwardRef(
|
|
|
171
181
|
...a11yProps.getPositionInSet(items.length, index)
|
|
172
182
|
}
|
|
173
183
|
|
|
184
|
+
const isInactive = itemInactive !== undefined ? itemInactive : inactive
|
|
185
|
+
|
|
174
186
|
// Ensure button is direct child of group as MacOS voiceover only applies "X of Y" to
|
|
175
187
|
// "radio" if it's a direct child of "radiogroup", even if aria-posinset etc exists
|
|
176
188
|
return (
|
|
@@ -182,7 +194,7 @@ const ButtonGroup = React.forwardRef(
|
|
|
182
194
|
onPress={handlePress}
|
|
183
195
|
tokens={getButtonTokens}
|
|
184
196
|
selected={isSelected}
|
|
185
|
-
inactive={
|
|
197
|
+
inactive={isInactive}
|
|
186
198
|
icon={iconProp}
|
|
187
199
|
{...selectItemProps({
|
|
188
200
|
...itemRest,
|
|
@@ -243,7 +255,12 @@ ButtonGroup.propTypes = {
|
|
|
243
255
|
/**
|
|
244
256
|
* An optional ref for one individual button in the ButtonGroup
|
|
245
257
|
*/
|
|
246
|
-
ref: ABBPropTypes.ref()
|
|
258
|
+
ref: ABBPropTypes.ref(),
|
|
259
|
+
/**
|
|
260
|
+
* If true, this individual button cannot be interacted with. Takes precedence
|
|
261
|
+
* over the group-level `inactive` prop. Useful for disabling specific options.
|
|
262
|
+
*/
|
|
263
|
+
inactive: PropTypes.bool
|
|
247
264
|
})
|
|
248
265
|
),
|
|
249
266
|
/**
|