@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
package/lib/esm/Card/CardBase.js
CHANGED
|
@@ -9,8 +9,15 @@ import { applyShadowToken } from '../ThemeProvider';
|
|
|
9
9
|
import { getTokensPropType, responsiveProps, useResponsiveProp, formatImageSource } from '../utils';
|
|
10
10
|
import { a11yProps, viewProps, selectSystemProps } from '../utils/props';
|
|
11
11
|
import backgroundImageStylesMap from './backgroundImageStylesMap';
|
|
12
|
-
import
|
|
12
|
+
import FlexGrid from '../FlexGrid/FlexGrid';
|
|
13
|
+
import FlexGridRow from '../FlexGrid/Row';
|
|
14
|
+
import FlexGridCol from '../FlexGrid/Col';
|
|
15
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
16
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
17
|
+
const GRID_COLUMNS = 12;
|
|
18
|
+
const isOverlayColor = color => {
|
|
19
|
+
return color && typeof color === 'string' && color.startsWith('rgba(');
|
|
20
|
+
};
|
|
14
21
|
const setBackgroundImage = _ref => {
|
|
15
22
|
let {
|
|
16
23
|
src,
|
|
@@ -24,12 +31,9 @@ const setBackgroundImage = _ref => {
|
|
|
24
31
|
const borderRadius = cardStyle?.borderRadius || 0;
|
|
25
32
|
const borderWidth = cardStyle?.borderWidth || 0;
|
|
26
33
|
const adjustedBorderRadius = Math.max(0, borderRadius - borderWidth);
|
|
27
|
-
|
|
28
|
-
// For contain mode with position and align, use CSS background properties for web
|
|
29
34
|
if (backgroundImageResizeMode === 'contain' && backgroundImagePosition && backgroundImageAlign) {
|
|
30
35
|
const positionKey = `${backgroundImagePosition}-${backgroundImageAlign}`;
|
|
31
36
|
if (Platform.OS === 'web') {
|
|
32
|
-
// Create background position based on position and align
|
|
33
37
|
let backgroundPosition;
|
|
34
38
|
switch (positionKey) {
|
|
35
39
|
case 'top-start':
|
|
@@ -73,7 +77,6 @@ const setBackgroundImage = _ref => {
|
|
|
73
77
|
children: content
|
|
74
78
|
});
|
|
75
79
|
}
|
|
76
|
-
// For React Native, apply positioning styles with full dimensions
|
|
77
80
|
const positionStyles = backgroundImageStylesMap[positionKey] || {};
|
|
78
81
|
return /*#__PURE__*/_jsxs(View, {
|
|
79
82
|
style: [staticStyles.containContainer, {
|
|
@@ -92,8 +95,6 @@ const setBackgroundImage = _ref => {
|
|
|
92
95
|
})]
|
|
93
96
|
});
|
|
94
97
|
}
|
|
95
|
-
|
|
96
|
-
// Use ImageBackground for all other resize modes and React Native
|
|
97
98
|
return /*#__PURE__*/_jsx(ImageBackground, {
|
|
98
99
|
source: src,
|
|
99
100
|
imageStyle: {
|
|
@@ -119,6 +120,10 @@ export const selectStyles = _ref2 => {
|
|
|
119
120
|
paddingLeft,
|
|
120
121
|
paddingRight,
|
|
121
122
|
paddingTop,
|
|
123
|
+
marginTop,
|
|
124
|
+
marginBottom,
|
|
125
|
+
marginLeft,
|
|
126
|
+
marginRight,
|
|
122
127
|
minWidth,
|
|
123
128
|
shadow,
|
|
124
129
|
backgroundGradient,
|
|
@@ -126,9 +131,18 @@ export const selectStyles = _ref2 => {
|
|
|
126
131
|
maxHeight,
|
|
127
132
|
overflowY
|
|
128
133
|
} = _ref2;
|
|
134
|
+
const hasGradient = (gradient || backgroundGradient) && Platform.OS === 'web';
|
|
135
|
+
let backgroundImageValue = null;
|
|
136
|
+
if (hasGradient) {
|
|
137
|
+
const gradientObj = gradient || backgroundGradient;
|
|
138
|
+
const gradientString = `linear-gradient(${gradientObj.angle}deg, ${gradientObj.stops[0].color}, ${gradientObj.stops[1].color})`;
|
|
139
|
+
const shouldApplyOverlay = (gradient || backgroundGradient && backgroundColor && backgroundColor !== 'transparent') && isOverlayColor(backgroundColor);
|
|
140
|
+
backgroundImageValue = shouldApplyOverlay ? `linear-gradient(${backgroundColor}, ${backgroundColor}), ${gradientString}` : gradientString;
|
|
141
|
+
}
|
|
142
|
+
const boxShadowColor = isOverlayColor(backgroundColor) ? backgroundColor : 'white';
|
|
129
143
|
return {
|
|
130
144
|
flex,
|
|
131
|
-
backgroundColor,
|
|
145
|
+
backgroundColor: hasGradient ? 'transparent' : backgroundColor,
|
|
132
146
|
borderColor,
|
|
133
147
|
borderRadius,
|
|
134
148
|
borderWidth,
|
|
@@ -136,16 +150,20 @@ export const selectStyles = _ref2 => {
|
|
|
136
150
|
paddingLeft,
|
|
137
151
|
paddingRight,
|
|
138
152
|
paddingTop,
|
|
153
|
+
marginTop,
|
|
154
|
+
marginBottom,
|
|
155
|
+
marginLeft,
|
|
156
|
+
marginRight,
|
|
139
157
|
minWidth,
|
|
140
158
|
...applyShadowToken(shadow),
|
|
141
159
|
...(gradient && Platform.OS === 'web' ? {
|
|
142
|
-
backgroundImage:
|
|
160
|
+
backgroundImage: backgroundImageValue,
|
|
143
161
|
backgroundOrigin: `border-box`,
|
|
144
|
-
boxShadow: `inset 0 1000px
|
|
162
|
+
boxShadow: `inset 0 1000px ${boxShadowColor}`,
|
|
145
163
|
border: `${borderWidth}px solid transparent`
|
|
146
164
|
} : {}),
|
|
147
165
|
...(backgroundGradient && Platform.OS === 'web' ? {
|
|
148
|
-
backgroundImage:
|
|
166
|
+
backgroundImage: backgroundImageValue
|
|
149
167
|
} : {}),
|
|
150
168
|
...(Platform.OS === 'web' ? {
|
|
151
169
|
maxHeight,
|
|
@@ -164,9 +182,11 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
164
182
|
tokens,
|
|
165
183
|
dataSet,
|
|
166
184
|
backgroundImage,
|
|
185
|
+
fullBleedContent,
|
|
186
|
+
cardState,
|
|
167
187
|
...rest
|
|
168
188
|
} = _ref3;
|
|
169
|
-
const cardStyle = selectStyles(typeof tokens === 'function' ? tokens() : tokens);
|
|
189
|
+
const cardStyle = selectStyles(typeof tokens === 'function' ? tokens(cardState) : tokens);
|
|
170
190
|
const props = selectProps(rest);
|
|
171
191
|
let content = children;
|
|
172
192
|
const {
|
|
@@ -180,9 +200,13 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
180
200
|
const backgroundImagePosition = useResponsiveProp(position);
|
|
181
201
|
const backgroundImageAlign = useResponsiveProp(align);
|
|
182
202
|
const imageSourceViewport = formatImageSource(useResponsiveProp(src));
|
|
203
|
+
const {
|
|
204
|
+
content: fullBleedImageContent,
|
|
205
|
+
position: fullBleedContentPosition,
|
|
206
|
+
imgCol
|
|
207
|
+
} = fullBleedContent || {};
|
|
208
|
+
const fullBleedPosition = useResponsiveProp(fullBleedContentPosition, 'bottom');
|
|
183
209
|
if (backgroundImage && src) {
|
|
184
|
-
// When there's a background image, separate the padding from the container style
|
|
185
|
-
// so the image can fill the entire container without padding interference
|
|
186
210
|
const {
|
|
187
211
|
paddingTop,
|
|
188
212
|
paddingBottom,
|
|
@@ -190,8 +214,6 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
190
214
|
paddingRight,
|
|
191
215
|
...containerStyle
|
|
192
216
|
} = cardStyle;
|
|
193
|
-
|
|
194
|
-
// Only create padding wrapper if there's actually padding defined
|
|
195
217
|
const hasPadding = paddingTop || paddingBottom || paddingLeft || paddingRight;
|
|
196
218
|
const paddedContent = hasPadding ? /*#__PURE__*/_jsx(View, {
|
|
197
219
|
style: {
|
|
@@ -219,6 +241,53 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
219
241
|
children: content
|
|
220
242
|
});
|
|
221
243
|
}
|
|
244
|
+
if (fullBleedContent && fullBleedImageContent) {
|
|
245
|
+
const {
|
|
246
|
+
paddingTop,
|
|
247
|
+
paddingBottom,
|
|
248
|
+
paddingLeft,
|
|
249
|
+
paddingRight,
|
|
250
|
+
...containerStyle
|
|
251
|
+
} = cardStyle;
|
|
252
|
+
const imageColumns = imgCol || {
|
|
253
|
+
xs: GRID_COLUMNS
|
|
254
|
+
};
|
|
255
|
+
const textColumns = {};
|
|
256
|
+
Object.keys(imageColumns).forEach(breakpoint => {
|
|
257
|
+
textColumns[breakpoint] = GRID_COLUMNS - (imageColumns[breakpoint] || GRID_COLUMNS);
|
|
258
|
+
});
|
|
259
|
+
const imageFirst = fullBleedPosition === 'top' || fullBleedPosition === 'left';
|
|
260
|
+
const imageColContent = /*#__PURE__*/_jsx(FlexGridCol, {
|
|
261
|
+
...imageColumns,
|
|
262
|
+
style: staticStyles.fullBleedImageCol,
|
|
263
|
+
children: fullBleedImageContent
|
|
264
|
+
});
|
|
265
|
+
const textColContent = /*#__PURE__*/_jsx(FlexGridCol, {
|
|
266
|
+
...textColumns,
|
|
267
|
+
style: {
|
|
268
|
+
paddingTop,
|
|
269
|
+
paddingBottom,
|
|
270
|
+
paddingLeft,
|
|
271
|
+
paddingRight
|
|
272
|
+
},
|
|
273
|
+
children: children
|
|
274
|
+
});
|
|
275
|
+
return /*#__PURE__*/_jsx(View, {
|
|
276
|
+
style: containerStyle,
|
|
277
|
+
dataSet: dataSet,
|
|
278
|
+
ref: ref,
|
|
279
|
+
...props,
|
|
280
|
+
children: /*#__PURE__*/_jsx(FlexGrid, {
|
|
281
|
+
children: /*#__PURE__*/_jsx(FlexGridRow, {
|
|
282
|
+
children: imageFirst ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
283
|
+
children: [imageColContent, textColContent]
|
|
284
|
+
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
285
|
+
children: [textColContent, imageColContent]
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
})
|
|
289
|
+
});
|
|
290
|
+
}
|
|
222
291
|
return /*#__PURE__*/_jsx(View, {
|
|
223
292
|
style: cardStyle,
|
|
224
293
|
dataSet: dataSet,
|
|
@@ -228,6 +297,13 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
228
297
|
});
|
|
229
298
|
});
|
|
230
299
|
CardBase.displayName = 'CardBase';
|
|
300
|
+
export const fullBleedContentPropTypes = PropTypes.shape({
|
|
301
|
+
content: PropTypes.node.isRequired,
|
|
302
|
+
alt: PropTypes.string,
|
|
303
|
+
position: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['bottom', 'left', 'right', 'top'])),
|
|
304
|
+
align: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['start', 'end', 'center', 'stretch'])),
|
|
305
|
+
imgCol: PropTypes.object
|
|
306
|
+
});
|
|
231
307
|
const staticStyles = StyleSheet.create({
|
|
232
308
|
imageBackground: {
|
|
233
309
|
width: '100%',
|
|
@@ -249,6 +325,9 @@ const staticStyles = StyleSheet.create({
|
|
|
249
325
|
position: 'absolute',
|
|
250
326
|
width: '100%',
|
|
251
327
|
height: '100%'
|
|
328
|
+
},
|
|
329
|
+
fullBleedImageCol: {
|
|
330
|
+
padding: 0
|
|
252
331
|
}
|
|
253
332
|
});
|
|
254
333
|
CardBase.propTypes = {
|
|
@@ -266,6 +345,7 @@ CardBase.propTypes = {
|
|
|
266
345
|
resizeMode: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center'])),
|
|
267
346
|
position: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['bottom', 'left', 'right', 'top'])),
|
|
268
347
|
align: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['start', 'end', 'center', 'stretch']))
|
|
269
|
-
})
|
|
348
|
+
}),
|
|
349
|
+
fullBleedContent: fullBleedContentPropTypes
|
|
270
350
|
};
|
|
271
351
|
export default CardBase;
|
|
@@ -7,10 +7,10 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
|
7
7
|
import { useViewport } from '../ViewportProvider';
|
|
8
8
|
import { applyOuterBorder, validateThemeTokens } from '../ThemeProvider';
|
|
9
9
|
import { a11yProps, clickProps, focusHandlerProps, getTokensSetPropType, linkProps, resolvePressableState, resolvePressableTokens, selectSystemProps, selectTokens, variantProp, viewProps, withLinkRouter } from '../utils';
|
|
10
|
-
import CardBase from './CardBase';
|
|
10
|
+
import CardBase, { fullBleedContentPropTypes } from './CardBase';
|
|
11
11
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
12
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, viewProps]);
|
|
13
|
-
const tokenKeys = ['flex', 'backgroundColor', 'borderColor', 'gradient', 'borderRadius', 'borderWidth', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'minWidth', 'shadow', 'contentAlignItems', 'contentJustifyContent', 'contentFlexGrow', 'contentFlexShrink',
|
|
13
|
+
const tokenKeys = ['flex', 'backgroundColor', 'borderColor', 'gradient', 'borderRadius', 'borderWidth', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'marginTop', 'marginBottom', 'marginLeft', 'marginRight', 'minWidth', 'shadow', 'contentAlignItems', 'contentJustifyContent', 'contentFlexGrow', 'contentFlexShrink',
|
|
14
14
|
// Outer border tokens. TODO: centralise common token sets like these as part of
|
|
15
15
|
// https://github.com/telus/universal-design-system/issues/782
|
|
16
16
|
'outerBorderColor', 'outerBorderWidth', 'outerBorderGap', 'icon', 'iconBackgroundColor', 'iconColor', 'iconSize', 'inputBackgroundColor', 'inputBorderColor', 'inputBorderRadius', 'inputBorderWidth', 'inputHeight', 'inputShadow', 'inputWidth'];
|
|
@@ -32,6 +32,7 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
32
32
|
hrefAttrs,
|
|
33
33
|
dataSet,
|
|
34
34
|
backgroundImage,
|
|
35
|
+
fullBleedContent,
|
|
35
36
|
accessibilityRole = href ? 'link' : undefined,
|
|
36
37
|
...rawRest
|
|
37
38
|
} = _ref;
|
|
@@ -125,10 +126,7 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
125
126
|
setFocused(false);
|
|
126
127
|
setPressed(false);
|
|
127
128
|
},
|
|
128
|
-
style:
|
|
129
|
-
...staticStyles.linkContainer,
|
|
130
|
-
textDecoration: 'none'
|
|
131
|
-
},
|
|
129
|
+
style: staticStyles.linkContainer,
|
|
132
130
|
...(hrefAttrs || {}),
|
|
133
131
|
role: accessibilityRole,
|
|
134
132
|
children: /*#__PURE__*/_jsx(CardBase, {
|
|
@@ -138,6 +136,7 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
138
136
|
hovered
|
|
139
137
|
}),
|
|
140
138
|
backgroundImage: backgroundImage,
|
|
139
|
+
fullBleedContent: fullBleedContent,
|
|
141
140
|
children: typeof children === 'function' ? children(getCardState({
|
|
142
141
|
pressed,
|
|
143
142
|
focused,
|
|
@@ -162,6 +161,7 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
162
161
|
children: pressableState => /*#__PURE__*/_jsx(CardBase, {
|
|
163
162
|
tokens: getCardTokens(pressableState),
|
|
164
163
|
backgroundImage: backgroundImage,
|
|
164
|
+
fullBleedContent: fullBleedContent,
|
|
165
165
|
children: typeof children === 'function' ? children(getCardState(pressableState)) : children
|
|
166
166
|
})
|
|
167
167
|
});
|
|
@@ -175,7 +175,8 @@ const staticStyles = StyleSheet.create({
|
|
|
175
175
|
flex: 1,
|
|
176
176
|
display: 'flex',
|
|
177
177
|
alignItems: 'stretch',
|
|
178
|
-
justifyContent: 'flex-start'
|
|
178
|
+
justifyContent: 'flex-start',
|
|
179
|
+
textDecorationLine: 'none'
|
|
179
180
|
}
|
|
180
181
|
});
|
|
181
182
|
PressableCardBase.displayName = 'PressableCardBase';
|
|
@@ -195,6 +196,7 @@ PressableCardBase.propTypes = {
|
|
|
195
196
|
resizeMode: PropTypes.oneOfType([PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center']), PropTypes.object]),
|
|
196
197
|
position: PropTypes.oneOfType([PropTypes.oneOf(['bottom', 'left', 'right', 'top']), PropTypes.object]),
|
|
197
198
|
align: PropTypes.oneOfType([PropTypes.oneOf(['start', 'end', 'center', 'stretch']), PropTypes.object])
|
|
198
|
-
})
|
|
199
|
+
}),
|
|
200
|
+
fullBleedContent: fullBleedContentPropTypes
|
|
199
201
|
};
|
|
200
202
|
export default withLinkRouter(PressableCardBase);
|
|
@@ -6,9 +6,9 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
|
6
6
|
import Platform from "react-native-web/dist/exports/Platform";
|
|
7
7
|
import Dimensions from "react-native-web/dist/exports/Dimensions";
|
|
8
8
|
import PropTypes from 'prop-types';
|
|
9
|
-
import { useThemeTokens } from '../ThemeProvider';
|
|
9
|
+
import { useThemeTokens, useTheme } from '../ThemeProvider';
|
|
10
10
|
import { useViewport } from '../ViewportProvider';
|
|
11
|
-
import { getTokensPropType, getA11yPropsFromHtmlTag, layoutTags, variantProp, selectSystemProps, a11yProps, viewProps, useCopy, unpackFragment, isTouchDevice } from '../utils';
|
|
11
|
+
import { getTokensPropType, getA11yPropsFromHtmlTag, layoutTags, variantProp, selectSystemProps, a11yProps, viewProps, useCopy, unpackFragment, isTouchDevice, useResponsiveProp, resolveContentMaxWidth } from '../utils';
|
|
12
12
|
import { useA11yInfo } from '../A11yInfoProvider';
|
|
13
13
|
import { CarouselProvider } from './CarouselContext';
|
|
14
14
|
import CarouselItem from './CarouselItem';
|
|
@@ -203,11 +203,18 @@ const selectRootContainerStyles = (enableHero, viewport) => {
|
|
|
203
203
|
}
|
|
204
204
|
return {};
|
|
205
205
|
};
|
|
206
|
-
const selectMainContainerStyles = (enableHero, viewport) => {
|
|
206
|
+
const selectMainContainerStyles = (enableHero, viewport, maxWidth) => {
|
|
207
207
|
if (enableHero && viewport === 'xl' && Platform.OS === 'web') {
|
|
208
208
|
return {
|
|
209
209
|
width: '100%',
|
|
210
|
-
maxWidth: 1200
|
|
210
|
+
maxWidth: maxWidth || 1200
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (maxWidth !== null && maxWidth !== undefined) {
|
|
214
|
+
return {
|
|
215
|
+
maxWidth,
|
|
216
|
+
alignSelf: 'center',
|
|
217
|
+
width: '100%'
|
|
211
218
|
};
|
|
212
219
|
}
|
|
213
220
|
return {};
|
|
@@ -354,11 +361,18 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
354
361
|
loopDuration = transitionDuration,
|
|
355
362
|
autoPlay = false,
|
|
356
363
|
enablePeeking = false,
|
|
364
|
+
contentMaxWidth,
|
|
357
365
|
...rest
|
|
358
366
|
} = _ref3;
|
|
359
367
|
let childrenArray = unpackFragment(children);
|
|
360
368
|
const isTransitioningRef = React.useRef(false);
|
|
361
369
|
const viewport = useViewport();
|
|
370
|
+
const {
|
|
371
|
+
themeOptions
|
|
372
|
+
} = useTheme();
|
|
373
|
+
const contentMaxWidthValue = useResponsiveProp(contentMaxWidth);
|
|
374
|
+
const responsiveWidth = useResponsiveProp(themeOptions?.contentMaxWidth);
|
|
375
|
+
const maxWidth = resolveContentMaxWidth(contentMaxWidthValue, responsiveWidth);
|
|
362
376
|
const totalItems = getTotalItems(enableDisplayMultipleItemsPerSlide, childrenArray, viewport);
|
|
363
377
|
const autoPlayFeatureEnabled = autoPlay && slideDuration > 0 && transitionDuration > 0 && totalItems > 1;
|
|
364
378
|
// if `Carousel` only has one `Carousel.Item`, convert this to a single-item array
|
|
@@ -889,7 +903,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
889
903
|
return /*#__PURE__*/_jsxs(View, {
|
|
890
904
|
style: selectRootContainerStyles(enableHero, viewport),
|
|
891
905
|
children: [/*#__PURE__*/_jsx(View, {
|
|
892
|
-
style: selectMainContainerStyles(enableHero, viewport),
|
|
906
|
+
style: selectMainContainerStyles(enableHero, viewport, maxWidth),
|
|
893
907
|
children: /*#__PURE__*/_jsxs(CarouselProvider, {
|
|
894
908
|
activeIndex: activeIndex,
|
|
895
909
|
goTo: goTo,
|
|
@@ -1247,7 +1261,24 @@ Carousel.propTypes = {
|
|
|
1247
1261
|
* If set to `true`, the Carousel will show multiple slides at once
|
|
1248
1262
|
* - Default value is `false`
|
|
1249
1263
|
*/
|
|
1250
|
-
enableDisplayMultipleItemsPerSlide: PropTypes.bool
|
|
1264
|
+
enableDisplayMultipleItemsPerSlide: PropTypes.bool,
|
|
1265
|
+
/**
|
|
1266
|
+
* The maximum width of the content in the Carousel.
|
|
1267
|
+
* This prop accepts responsive values for different viewports. If a number is provided,
|
|
1268
|
+
* it will be the max content width for the desired viewport.
|
|
1269
|
+
* - `xs`: 'max' | 'full' | <number>
|
|
1270
|
+
* - `sm`: 'max' | 'full' | <number>
|
|
1271
|
+
* - `md`: 'max' | 'full' | <number>
|
|
1272
|
+
* - `lg`: 'max' | 'full' | <number>
|
|
1273
|
+
* - `xl`: 'max' | 'full' | <number>
|
|
1274
|
+
*/
|
|
1275
|
+
contentMaxWidth: PropTypes.shape({
|
|
1276
|
+
xl: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
1277
|
+
lg: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
1278
|
+
md: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
1279
|
+
sm: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
1280
|
+
xs: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number])
|
|
1281
|
+
})
|
|
1251
1282
|
};
|
|
1252
1283
|
Carousel.Item = CarouselItem;
|
|
1253
1284
|
Carousel.displayName = 'Carousel';
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { viewports } from '@telus-uds/system-constants';
|
|
4
4
|
import { a11yProps, viewProps, getA11yPropsFromHtmlTag, layoutTags, selectSystemProps, BaseView, StyleSheet, createMediaQueryStyles, useResponsiveProp } from '../utils';
|
|
5
|
+
import resolveContentMaxWidth from '../utils/resolveContentMaxWidth';
|
|
5
6
|
import Row from './Row';
|
|
6
7
|
import Col from './Col';
|
|
7
8
|
import GutterContext from './providers/GutterContext';
|
|
@@ -10,47 +11,24 @@ import { useTheme } from '../ThemeProvider';
|
|
|
10
11
|
import { useViewport } from '../ViewportProvider';
|
|
11
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
13
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
13
|
-
const CONTENT_MAX_WIDTH = 'max';
|
|
14
|
-
const CONTENT_FULL_WIDTH = 'full';
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @param {number|string|null|undefined} contentMinWidthValue - The minimum width value for the content.
|
|
20
|
-
* Can be a number, a special string constant (e.g., CONTENT_FULL_WIDTH, CONTENT_MAX_WIDTH), or null/undefined.
|
|
21
|
-
* @param {number} responsiveWidth - The responsive width to use when contentMinWidthValue is CONTENT_MAX_WIDTH.
|
|
22
|
-
* @returns {number|string|null} The resolved maximum width value, or null if full width is desired.
|
|
23
|
-
*/
|
|
24
|
-
const resolveContentMaxWidth = (contentMinWidthValue, responsiveWidth) => {
|
|
25
|
-
if (!contentMinWidthValue || contentMinWidthValue === CONTENT_FULL_WIDTH) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
if (Number.isFinite(contentMinWidthValue)) {
|
|
29
|
-
return contentMinWidthValue;
|
|
30
|
-
}
|
|
31
|
-
if (contentMinWidthValue === CONTENT_MAX_WIDTH) {
|
|
32
|
-
return responsiveWidth;
|
|
33
|
-
}
|
|
34
|
-
return contentMinWidthValue;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Calculates the maximum width for a given viewport based on limitWidth and contentMinWidth settings.
|
|
16
|
+
* Calculates the maximum width for a given viewport based on limitWidth and contentMaxWidth settings.
|
|
39
17
|
*
|
|
40
18
|
* @param {string} viewportKey - The viewport key ('xs', 'sm', 'md', 'lg', 'xl')
|
|
41
19
|
* @param {boolean} limitWidth - Whether to limit the width to viewport breakpoints
|
|
42
|
-
* @param {any}
|
|
20
|
+
* @param {any} contentWidthProp - The contentMaxWidth (or contentMinWidth) prop value
|
|
43
21
|
* @param {number|string|null} maxWidth - The resolved max width value
|
|
44
22
|
* @returns {number|string|null} The calculated maximum width for the viewport
|
|
45
23
|
*/
|
|
46
|
-
const getMaxWidthForViewport = (viewportKey, limitWidth,
|
|
24
|
+
const getMaxWidthForViewport = (viewportKey, limitWidth, contentWidthProp, maxWidth) => {
|
|
47
25
|
if (limitWidth) {
|
|
48
26
|
if (viewportKey === 'xs') {
|
|
49
27
|
return null;
|
|
50
28
|
}
|
|
51
29
|
return viewports.map.get(viewportKey);
|
|
52
30
|
}
|
|
53
|
-
if (
|
|
31
|
+
if (contentWidthProp) {
|
|
54
32
|
return maxWidth;
|
|
55
33
|
}
|
|
56
34
|
return null;
|
|
@@ -74,6 +52,7 @@ const FlexGrid = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
74
52
|
accessibilityRole,
|
|
75
53
|
children,
|
|
76
54
|
dataSet,
|
|
55
|
+
contentMaxWidth,
|
|
77
56
|
contentMinWidth,
|
|
78
57
|
...rest
|
|
79
58
|
} = _ref;
|
|
@@ -87,28 +66,31 @@ const FlexGrid = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
87
66
|
} = useTheme();
|
|
88
67
|
let flexgridStyles;
|
|
89
68
|
let mediaIds;
|
|
90
|
-
|
|
69
|
+
|
|
70
|
+
// Support both contentMaxWidth and deprecated contentMinWidth for backwards compatibility
|
|
71
|
+
const contentWidthProp = contentMaxWidth || contentMinWidth;
|
|
72
|
+
const contentWidthValue = useResponsiveProp(contentWidthProp);
|
|
91
73
|
const responsiveWidth = useResponsiveProp(themeOptions?.contentMaxWidth);
|
|
92
|
-
const maxWidth = resolveContentMaxWidth(
|
|
74
|
+
const maxWidth = resolveContentMaxWidth(contentWidthValue, responsiveWidth);
|
|
93
75
|
const stylesByViewport = {
|
|
94
76
|
xs: {
|
|
95
|
-
maxWidth: getMaxWidthForViewport('xs', limitWidth,
|
|
77
|
+
maxWidth: getMaxWidthForViewport('xs', limitWidth, contentWidthProp, maxWidth),
|
|
96
78
|
flexDirection: reverseLevel[0] ? 'column-reverse' : 'column'
|
|
97
79
|
},
|
|
98
80
|
sm: {
|
|
99
|
-
maxWidth: getMaxWidthForViewport('sm', limitWidth,
|
|
81
|
+
maxWidth: getMaxWidthForViewport('sm', limitWidth, contentWidthProp, maxWidth),
|
|
100
82
|
flexDirection: reverseLevel[1] ? 'column-reverse' : 'column'
|
|
101
83
|
},
|
|
102
84
|
md: {
|
|
103
|
-
maxWidth: getMaxWidthForViewport('md', limitWidth,
|
|
85
|
+
maxWidth: getMaxWidthForViewport('md', limitWidth, contentWidthProp, maxWidth),
|
|
104
86
|
flexDirection: reverseLevel[2] ? 'column-reverse' : 'column'
|
|
105
87
|
},
|
|
106
88
|
lg: {
|
|
107
|
-
maxWidth: getMaxWidthForViewport('lg', limitWidth,
|
|
89
|
+
maxWidth: getMaxWidthForViewport('lg', limitWidth, contentWidthProp, maxWidth),
|
|
108
90
|
flexDirection: reverseLevel[3] ? 'column-reverse' : 'column'
|
|
109
91
|
},
|
|
110
92
|
xl: {
|
|
111
|
-
maxWidth: getMaxWidthForViewport('xl', limitWidth,
|
|
93
|
+
maxWidth: getMaxWidthForViewport('xl', limitWidth, contentWidthProp, maxWidth),
|
|
112
94
|
flexDirection: reverseLevel[4] ? 'column-reverse' : 'column'
|
|
113
95
|
}
|
|
114
96
|
};
|
|
@@ -204,7 +186,7 @@ FlexGrid.propTypes = {
|
|
|
204
186
|
*/
|
|
205
187
|
children: PropTypes.node.isRequired,
|
|
206
188
|
/**
|
|
207
|
-
* The
|
|
189
|
+
* The maximum width of the content in the FlexGrid.
|
|
208
190
|
* This prop accepts responsive values for different viewports. If a number is provided,
|
|
209
191
|
* it will be the max content width for the desired viewport.
|
|
210
192
|
* - `xs`: 'max' | 'full' | <number>
|
|
@@ -213,6 +195,20 @@ FlexGrid.propTypes = {
|
|
|
213
195
|
* - `lg`: 'max' | 'full' | <number>
|
|
214
196
|
* - `xl`: 'max' | 'full' | <number>
|
|
215
197
|
*/
|
|
198
|
+
contentMaxWidth: PropTypes.shape({
|
|
199
|
+
xl: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
200
|
+
lg: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
201
|
+
md: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
202
|
+
sm: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
203
|
+
xs: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number])
|
|
204
|
+
}),
|
|
205
|
+
/**
|
|
206
|
+
* @deprecated Use `contentMaxWidth` instead. This prop will be removed in a future version.
|
|
207
|
+
*
|
|
208
|
+
* The minimum width of the content in the FlexGrid.
|
|
209
|
+
* This prop accepts responsive values for different viewports. If a number is provided,
|
|
210
|
+
* it will be the max content width for the desired viewport.
|
|
211
|
+
*/
|
|
216
212
|
contentMinWidth: PropTypes.shape({
|
|
217
213
|
xl: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
218
214
|
lg: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
|
|
@@ -4,7 +4,7 @@ import Platform from "react-native-web/dist/exports/Platform";
|
|
|
4
4
|
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
5
5
|
import View from "react-native-web/dist/exports/View";
|
|
6
6
|
import { validateThemeTokens, resolveThemeTokens } from '../ThemeProvider';
|
|
7
|
-
import { a11yProps, getTokensSetPropType, selectSystemProps, selectTokens, viewProps } from '../utils';
|
|
7
|
+
import { a11yProps, getTokensSetPropType, selectSystemProps, selectTokens, variantProp, viewProps } from '../utils';
|
|
8
8
|
import ScrollViewEnd from './ScrollViewEnd';
|
|
9
9
|
import { getItemPositionScrollTarget, itemPositionsPropType } from './itemPositions';
|
|
10
10
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -27,6 +27,7 @@ const HorizontalScroll = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
27
27
|
ScrollButton,
|
|
28
28
|
tokens,
|
|
29
29
|
itemPositions,
|
|
30
|
+
variant,
|
|
30
31
|
children,
|
|
31
32
|
...rest
|
|
32
33
|
} = _ref;
|
|
@@ -70,8 +71,9 @@ const HorizontalScroll = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
70
71
|
setScrollOffset(x);
|
|
71
72
|
};
|
|
72
73
|
const scrollMax = Math.max(0, contentWidth - containerWidth);
|
|
73
|
-
const
|
|
74
|
-
const
|
|
74
|
+
const hideNavigationButtons = variant?.hideNavigationButtons || false;
|
|
75
|
+
const showNextButton = scrollOffset < scrollMax && !hideNavigationButtons;
|
|
76
|
+
const showPreviousButton = scrollOffset > 0 && !hideNavigationButtons;
|
|
75
77
|
const scrollRef = React.useRef(null);
|
|
76
78
|
const scrollTo = targetX => {
|
|
77
79
|
if (typeof scrollRef.current?.scrollTo === 'function') {
|
|
@@ -162,6 +164,7 @@ HorizontalScroll.propTypes = {
|
|
|
162
164
|
tokens: getTokensSetPropType(tokenKeys, {
|
|
163
165
|
allowFunction: true
|
|
164
166
|
}),
|
|
167
|
+
variant: variantProp.propType,
|
|
165
168
|
children: PropTypes.node
|
|
166
169
|
};
|
|
167
170
|
export default HorizontalScroll;
|
package/lib/esm/Icon/Icon.js
CHANGED
|
@@ -14,6 +14,7 @@ const Icon = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
14
14
|
tokens,
|
|
15
15
|
scalesWithText = false,
|
|
16
16
|
style = {},
|
|
17
|
+
testID,
|
|
17
18
|
dataSet
|
|
18
19
|
} = _ref;
|
|
19
20
|
const themeTokens = useThemeTokens('Icon', tokens, variant);
|
|
@@ -37,6 +38,7 @@ const Icon = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
37
38
|
};
|
|
38
39
|
const getIconContentForMobile = () => {
|
|
39
40
|
return /*#__PURE__*/_jsx(View, {
|
|
41
|
+
testID: testID,
|
|
40
42
|
style: {
|
|
41
43
|
backgroundColor: themeTokens.backgroundColor,
|
|
42
44
|
borderRadius: themeTokens.borderRadius,
|
|
@@ -46,6 +48,7 @@ const Icon = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
46
48
|
});
|
|
47
49
|
};
|
|
48
50
|
return Platform.OS === 'web' ? /*#__PURE__*/_jsx(View, {
|
|
51
|
+
testID: testID,
|
|
49
52
|
ref: ref
|
|
50
53
|
// eslint-disable-next-line react-native/no-inline-styles
|
|
51
54
|
,
|
|
@@ -123,6 +123,7 @@ const IconButton = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
123
123
|
hrefAttrs,
|
|
124
124
|
testID,
|
|
125
125
|
accessibilityRole = href ? 'link' : 'button',
|
|
126
|
+
inactive = false,
|
|
126
127
|
...rawRest
|
|
127
128
|
} = _ref3;
|
|
128
129
|
const {
|
|
@@ -143,8 +144,12 @@ const IconButton = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
143
144
|
}
|
|
144
145
|
});
|
|
145
146
|
};
|
|
146
|
-
const
|
|
147
|
-
|
|
147
|
+
const mergedVariant = inactive ? {
|
|
148
|
+
...variant,
|
|
149
|
+
inactive: true
|
|
150
|
+
} : variant;
|
|
151
|
+
const getTokens = useThemeTokensCallback('IconButton', tokens, mergedVariant);
|
|
152
|
+
const getOuterStyle = pressableState => selectOuterStyle(getTokens(resolvePressableState(pressableState), mergedVariant.password));
|
|
148
153
|
return /*#__PURE__*/_jsx(Pressable, {
|
|
149
154
|
ref: ref,
|
|
150
155
|
href: href,
|
|
@@ -153,15 +158,16 @@ const IconButton = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
|
|
|
153
158
|
style: getOuterStyle,
|
|
154
159
|
...selectedProps,
|
|
155
160
|
testID: testID,
|
|
161
|
+
disabled: inactive,
|
|
156
162
|
children: pressableState => {
|
|
157
163
|
const themeTokens = getTokens(resolvePressableState(pressableState));
|
|
158
164
|
return /*#__PURE__*/_jsx(View, {
|
|
159
|
-
style: selectInnerStyle(themeTokens,
|
|
165
|
+
style: selectInnerStyle(themeTokens, mergedVariant.password),
|
|
160
166
|
children: /*#__PURE__*/_jsx(Icon, {
|
|
161
167
|
icon: IconComponent || themeTokens.icon,
|
|
162
168
|
title: selectedProps.accessibilityLabel,
|
|
163
169
|
tokens: selectTokens('Icon', themeTokens, 'icon'),
|
|
164
|
-
variant:
|
|
170
|
+
variant: mergedVariant
|
|
165
171
|
})
|
|
166
172
|
});
|
|
167
173
|
}
|
|
@@ -192,7 +198,11 @@ IconButton.propTypes = {
|
|
|
192
198
|
/**
|
|
193
199
|
* Function to execute when the `Iconbutton` is pressed
|
|
194
200
|
*/
|
|
195
|
-
onPress: PropTypes.func
|
|
201
|
+
onPress: PropTypes.func,
|
|
202
|
+
/**
|
|
203
|
+
* When true, applies the inactive variant styling
|
|
204
|
+
*/
|
|
205
|
+
inactive: PropTypes.bool
|
|
196
206
|
};
|
|
197
207
|
const staticStyles = StyleSheet.create({
|
|
198
208
|
outer: {
|