@telus-uds/components-base 3.23.0 → 3.24.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 +12 -1
- package/lib/cjs/Card/CardBase.js +97 -17
- package/lib/cjs/Card/PressableCardBase.js +12 -8
- package/lib/cjs/HorizontalScroll/HorizontalScroll.js +5 -2
- package/lib/cjs/Icon/Icon.js +3 -0
- 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/Tooltip/Tooltip.native.js +2 -0
- package/lib/cjs/index.js +15 -0
- package/lib/esm/Card/CardBase.js +97 -17
- package/lib/esm/Card/PressableCardBase.js +10 -8
- package/lib/esm/HorizontalScroll/HorizontalScroll.js +6 -3
- package/lib/esm/Icon/Icon.js +3 -0
- 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/Tooltip/Tooltip.native.js +2 -0
- package/lib/esm/index.js +1 -0
- package/lib/package.json +2 -2
- package/package.json +2 -2
- package/src/Card/CardBase.jsx +113 -14
- package/src/Card/PressableCardBase.jsx +17 -5
- package/src/HorizontalScroll/HorizontalScroll.jsx +6 -3
- package/src/Icon/Icon.jsx +3 -0
- 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/Tooltip/Tooltip.native.jsx +2 -1
- package/src/index.js +1 -0
- package/types/Listbox.d.ts +24 -0
- package/types/Shortcuts.d.ts +136 -0
- package/types/index.d.ts +12 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _Image = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Image"));
|
|
9
|
+
var _Platform = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Platform"));
|
|
10
|
+
var _Pressable = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Pressable"));
|
|
11
|
+
var _StyleSheet = _interopRequireDefault(require("react-native-web/dist/cjs/exports/StyleSheet"));
|
|
12
|
+
var _View = _interopRequireDefault(require("react-native-web/dist/cjs/exports/View"));
|
|
13
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
14
|
+
var _ThemeProvider = require("../ThemeProvider");
|
|
15
|
+
var _utils = require("../utils");
|
|
16
|
+
var _Icon = _interopRequireDefault(require("../Icon"));
|
|
17
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
18
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
19
|
+
const DYNAMIC_WIDTH_VARIANT = 'dynamic';
|
|
20
|
+
const EQUAL_WIDTH_VARIANT = 'equal';
|
|
21
|
+
const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.linkProps, _utils.viewProps]);
|
|
22
|
+
const selectPressableStyles = (tokens, widthVariant, equalWidth) => {
|
|
23
|
+
const styles = {
|
|
24
|
+
borderColor: tokens.borderColor,
|
|
25
|
+
borderRadius: tokens.borderRadius,
|
|
26
|
+
borderWidth: tokens.borderWidth,
|
|
27
|
+
..._Platform.default.select({
|
|
28
|
+
web: {
|
|
29
|
+
outline: 'none'
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
};
|
|
33
|
+
if (widthVariant === DYNAMIC_WIDTH_VARIANT) {
|
|
34
|
+
styles.width = 'auto';
|
|
35
|
+
} else if (widthVariant === EQUAL_WIDTH_VARIANT) {
|
|
36
|
+
if (equalWidth) {
|
|
37
|
+
styles.width = equalWidth;
|
|
38
|
+
} else {
|
|
39
|
+
styles.minWidth = tokens.width;
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
styles.width = tokens.width;
|
|
43
|
+
}
|
|
44
|
+
return styles;
|
|
45
|
+
};
|
|
46
|
+
const selectIconContainerStyles = tokens => ({
|
|
47
|
+
paddingBottom: tokens.iconContainerPaddingBottom,
|
|
48
|
+
paddingLeft: tokens.iconContainerPaddingLeft,
|
|
49
|
+
paddingRight: tokens.iconContainerPaddingRight,
|
|
50
|
+
paddingTop: tokens.iconContainerPaddingTop
|
|
51
|
+
});
|
|
52
|
+
const selectIconVariant = () => ({
|
|
53
|
+
background: true,
|
|
54
|
+
padding: 'medium'
|
|
55
|
+
});
|
|
56
|
+
const selectIconTokens = tokens => ({
|
|
57
|
+
backgroundColor: tokens.iconBackgroundColor,
|
|
58
|
+
color: tokens.iconColor,
|
|
59
|
+
size: tokens.iconSize,
|
|
60
|
+
width: tokens.iconWidth
|
|
61
|
+
});
|
|
62
|
+
const selectImageStyles = tokens => ({
|
|
63
|
+
width: tokens.imageWidth,
|
|
64
|
+
height: tokens.imageHeight
|
|
65
|
+
});
|
|
66
|
+
const selectLabelContainerStyles = tokens => ({
|
|
67
|
+
paddingBottom: tokens.labelContainerPaddingBottom,
|
|
68
|
+
paddingLeft: tokens.labelContainerPaddingLeft,
|
|
69
|
+
paddingRight: tokens.labelContainerPaddingRight,
|
|
70
|
+
paddingTop: tokens.labelContainerPaddingTop
|
|
71
|
+
});
|
|
72
|
+
const selectTitleTextStyles = tokens => (0, _ThemeProvider.applyTextStyles)({
|
|
73
|
+
fontColor: tokens.labelFontColor,
|
|
74
|
+
fontName: tokens.labelFontName,
|
|
75
|
+
fontSize: tokens.labelFontSize,
|
|
76
|
+
fontWeight: tokens.labelFontWeight,
|
|
77
|
+
lineHeight: tokens.labelLineHeight,
|
|
78
|
+
textDecorationLine: tokens.labelUnderline,
|
|
79
|
+
textAlign: tokens.labelTextAlign
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A clickable shortcut item component that displays an icon or image with an optional label.
|
|
84
|
+
* Can be used within a Shortcuts container to create a grid of navigation shortcuts.
|
|
85
|
+
*
|
|
86
|
+
* @component
|
|
87
|
+
* @param {Object} props - Component props
|
|
88
|
+
* @param {string} [props.icon] - Icon identifier to display
|
|
89
|
+
* @param {Object} [props.image={ src: '', alt: '' }] - Image object with src and alt properties
|
|
90
|
+
* @param {string} [props.image.src] - Image source URL
|
|
91
|
+
* @param {string} [props.image.alt] - Image alt text for accessibility
|
|
92
|
+
* @param {string|React.ReactNode} props.label - Label text or content to display below the icon/image
|
|
93
|
+
* @param {boolean} [props.hideLabel=false] - Whether to hide the label for this specific item
|
|
94
|
+
* @param {string} [props.href] - Link URL for navigation
|
|
95
|
+
* @param {Object} [props.iconVariant] - Icon variant to apply to this specific item
|
|
96
|
+
* @param {Object} [props.tokens] - Theme tokens to customize appearance
|
|
97
|
+
* @param {Object} [props.variant] - Variant configuration object for this specific item
|
|
98
|
+
* @param {string} [props.variant.width] - Width variant (e.g., 'dynamic', 'equal')
|
|
99
|
+
* @param {Function} [props.onPressableStateChange] - Callback function that receives the pressable state object (pressed, hovered, focused)
|
|
100
|
+
* @param {number} [props.maxWidth] - Maximum width for equal width variant (injected by Shortcuts container)
|
|
101
|
+
* @param {Function} [props.registerWidth] - Callback to register width for equal width variant (injected by Shortcuts container)
|
|
102
|
+
* @param {Object} [props.containerVariant] - Variant configuration from Shortcuts container (injected by Shortcuts container)
|
|
103
|
+
* @param {boolean} [props.containerHideLabels] - Hide labels setting from Shortcuts container (injected by Shortcuts container)
|
|
104
|
+
* @param {Object} [props.containerIconVariant] - Icon variant from Shortcuts container (injected by Shortcuts container)
|
|
105
|
+
* @param {React.Ref} ref - Forwarded ref to the Pressable component
|
|
106
|
+
* @returns {React.ReactElement} The rendered shortcut item
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* <ShortcutsItem
|
|
110
|
+
* icon={HomeIcon}
|
|
111
|
+
* label="Home"
|
|
112
|
+
* href="/home"
|
|
113
|
+
* onPressableStateChange={(state) => console.log(state)}
|
|
114
|
+
* />
|
|
115
|
+
*/
|
|
116
|
+
const ShortcutsItem = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
117
|
+
let {
|
|
118
|
+
icon,
|
|
119
|
+
image = {
|
|
120
|
+
src: '',
|
|
121
|
+
alt: ''
|
|
122
|
+
},
|
|
123
|
+
label,
|
|
124
|
+
hideLabel = false,
|
|
125
|
+
href,
|
|
126
|
+
iconVariant,
|
|
127
|
+
tokens,
|
|
128
|
+
variant,
|
|
129
|
+
onPressableStateChange,
|
|
130
|
+
maxWidth,
|
|
131
|
+
registerWidth,
|
|
132
|
+
containerVariant,
|
|
133
|
+
containerHideLabels,
|
|
134
|
+
containerIconVariant,
|
|
135
|
+
...rest
|
|
136
|
+
} = _ref;
|
|
137
|
+
const mergedVariant = {
|
|
138
|
+
...containerVariant,
|
|
139
|
+
...variant
|
|
140
|
+
};
|
|
141
|
+
const widthVariant = mergedVariant?.width;
|
|
142
|
+
const shouldHideLabel = hideLabel || containerHideLabels;
|
|
143
|
+
const mergedIconVariant = iconVariant ?? containerIconVariant;
|
|
144
|
+
const getThemeTokens = (0, _ThemeProvider.useThemeTokensCallback)('ShortcutsItem', tokens, mergedVariant);
|
|
145
|
+
const getTokens = pressableState => getThemeTokens((0, _utils.resolvePressableState)(pressableState));
|
|
146
|
+
const {
|
|
147
|
+
onPress,
|
|
148
|
+
...props
|
|
149
|
+
} = _utils.clickProps.toPressProps(rest);
|
|
150
|
+
const {
|
|
151
|
+
hrefAttrs,
|
|
152
|
+
rawRest
|
|
153
|
+
} = _utils.hrefAttrsProp.bundle(props);
|
|
154
|
+
const selectedProps = selectProps({
|
|
155
|
+
href,
|
|
156
|
+
onPress: _utils.linkProps.handleHref({
|
|
157
|
+
href,
|
|
158
|
+
onPress
|
|
159
|
+
}),
|
|
160
|
+
hrefAttrs,
|
|
161
|
+
...rawRest
|
|
162
|
+
});
|
|
163
|
+
const handleLayout = event => {
|
|
164
|
+
if (widthVariant === EQUAL_WIDTH_VARIANT && registerWidth) {
|
|
165
|
+
const {
|
|
166
|
+
width
|
|
167
|
+
} = event.nativeEvent.layout;
|
|
168
|
+
registerWidth(width);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Pressable.default, {
|
|
172
|
+
ref: ref,
|
|
173
|
+
style: pressableState => selectPressableStyles(getTokens(pressableState), widthVariant, maxWidth),
|
|
174
|
+
onLayout: handleLayout,
|
|
175
|
+
...selectedProps,
|
|
176
|
+
children: pressableState => {
|
|
177
|
+
const themeTokens = getTokens(pressableState);
|
|
178
|
+
if (onPressableStateChange) {
|
|
179
|
+
onPressableStateChange((0, _utils.resolvePressableState)(pressableState));
|
|
180
|
+
}
|
|
181
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
|
|
182
|
+
style: staticStyles.container,
|
|
183
|
+
children: [icon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
|
|
184
|
+
style: selectIconContainerStyles(themeTokens),
|
|
185
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
|
|
186
|
+
icon: icon,
|
|
187
|
+
variant: mergedIconVariant ?? selectIconVariant(),
|
|
188
|
+
tokens: mergedIconVariant ? {} : selectIconTokens(themeTokens),
|
|
189
|
+
...(_Platform.default.OS === 'web' && {
|
|
190
|
+
accessibilityLabel: label
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
}), !icon && image && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Image.default, {
|
|
194
|
+
source: image.src,
|
|
195
|
+
alt: image.alt,
|
|
196
|
+
style: selectImageStyles(themeTokens),
|
|
197
|
+
resizeMethod: "resize",
|
|
198
|
+
accessibilityIgnoresInvertColors: true
|
|
199
|
+
}), label && !shouldHideLabel && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
|
|
200
|
+
style: [staticStyles.label, selectLabelContainerStyles(themeTokens)],
|
|
201
|
+
children: (0, _utils.wrapStringsInText)(label, {
|
|
202
|
+
style: selectTitleTextStyles(themeTokens)
|
|
203
|
+
})
|
|
204
|
+
})]
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
ShortcutsItem.displayName = 'ShortcutsItem';
|
|
210
|
+
ShortcutsItem.propTypes = {
|
|
211
|
+
...selectedSystemPropTypes,
|
|
212
|
+
tokens: (0, _utils.getTokensPropType)('ShortcutsItem'),
|
|
213
|
+
variant: _utils.variantProp.propType,
|
|
214
|
+
/**
|
|
215
|
+
* Icon for the ShortcutsItem
|
|
216
|
+
*/
|
|
217
|
+
icon: _propTypes.default.elementType,
|
|
218
|
+
/**
|
|
219
|
+
* Image for the ShortcutsItem
|
|
220
|
+
*/
|
|
221
|
+
image: _propTypes.default.shape({
|
|
222
|
+
src: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number, _propTypes.default.object]),
|
|
223
|
+
alt: _propTypes.default.string
|
|
224
|
+
}),
|
|
225
|
+
/**
|
|
226
|
+
* Label for the ShortcutsItem
|
|
227
|
+
*/
|
|
228
|
+
label: _propTypes.default.string,
|
|
229
|
+
/**
|
|
230
|
+
* 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.
|
|
231
|
+
*/
|
|
232
|
+
hideLabel: _propTypes.default.bool,
|
|
233
|
+
/**
|
|
234
|
+
* href for the ShortcutsItem
|
|
235
|
+
*/
|
|
236
|
+
href: _propTypes.default.string,
|
|
237
|
+
/**
|
|
238
|
+
* Icon variant for this specific ShortcutsItem
|
|
239
|
+
*/
|
|
240
|
+
iconVariant: _utils.variantProp.propType,
|
|
241
|
+
/**
|
|
242
|
+
* Callback function that receives the pressable state object containing pressed, hovered, and focused boolean properties
|
|
243
|
+
*/
|
|
244
|
+
onPressableStateChange: _propTypes.default.func,
|
|
245
|
+
/**
|
|
246
|
+
* Maximum width for equal width variant (automatically injected by Shortcuts container)
|
|
247
|
+
* @private
|
|
248
|
+
*/
|
|
249
|
+
maxWidth: _propTypes.default.number,
|
|
250
|
+
/**
|
|
251
|
+
* Callback to register width for equal width variant (automatically injected by Shortcuts container)
|
|
252
|
+
* @private
|
|
253
|
+
*/
|
|
254
|
+
registerWidth: _propTypes.default.func,
|
|
255
|
+
/**
|
|
256
|
+
* Variant configuration from Shortcuts container (automatically injected by Shortcuts container)
|
|
257
|
+
* @private
|
|
258
|
+
*/
|
|
259
|
+
containerVariant: _utils.variantProp.propType,
|
|
260
|
+
/**
|
|
261
|
+
* Hide labels setting from Shortcuts container (automatically injected by Shortcuts container)
|
|
262
|
+
* @private
|
|
263
|
+
*/
|
|
264
|
+
containerHideLabels: _propTypes.default.bool,
|
|
265
|
+
/**
|
|
266
|
+
* Icon variant from Shortcuts container (automatically injected by Shortcuts container)
|
|
267
|
+
* @private
|
|
268
|
+
*/
|
|
269
|
+
containerIconVariant: _utils.variantProp.propType
|
|
270
|
+
};
|
|
271
|
+
const staticStyles = _StyleSheet.default.create({
|
|
272
|
+
container: {
|
|
273
|
+
alignItems: 'center',
|
|
274
|
+
justifyContent: 'center'
|
|
275
|
+
},
|
|
276
|
+
label: {
|
|
277
|
+
flexWrap: 'wrap'
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
var _default = exports.default = ShortcutsItem;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "ShortcutsItem", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _ShortcutsItem.default;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
exports.default = void 0;
|
|
13
|
+
var _Shortcuts = _interopRequireDefault(require("./Shortcuts"));
|
|
14
|
+
var _ShortcutsItem = _interopRequireDefault(require("./ShortcutsItem"));
|
|
15
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
|
+
var _default = exports.default = _Shortcuts.default;
|
|
@@ -169,6 +169,7 @@ const Tooltip = /*#__PURE__*/_react.default.forwardRef((_ref7, ref) => {
|
|
|
169
169
|
nativeID,
|
|
170
170
|
activateOnHover = false,
|
|
171
171
|
tooltipButtonTokens,
|
|
172
|
+
testID,
|
|
172
173
|
...rest
|
|
173
174
|
} = _ref7;
|
|
174
175
|
const [isOpen, setIsOpen] = _react.default.useState(false);
|
|
@@ -312,6 +313,7 @@ const Tooltip = /*#__PURE__*/_react.default.forwardRef((_ref7, ref) => {
|
|
|
312
313
|
display: inline ? 'inline-block' : 'flex'
|
|
313
314
|
}
|
|
314
315
|
})],
|
|
316
|
+
testID: testID,
|
|
315
317
|
...selectProps(rest),
|
|
316
318
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Pressable.default, {
|
|
317
319
|
onPress: toggleIsOpen,
|
package/lib/cjs/index.js
CHANGED
|
@@ -59,6 +59,8 @@ var _exportNames = {
|
|
|
59
59
|
Responsive: true,
|
|
60
60
|
Search: true,
|
|
61
61
|
Select: true,
|
|
62
|
+
Shortcuts: true,
|
|
63
|
+
ShortcutsItem: true,
|
|
62
64
|
SideNav: true,
|
|
63
65
|
Skeleton: true,
|
|
64
66
|
SkipLink: true,
|
|
@@ -432,6 +434,18 @@ Object.defineProperty(exports, "Select", {
|
|
|
432
434
|
return _Select.default;
|
|
433
435
|
}
|
|
434
436
|
});
|
|
437
|
+
Object.defineProperty(exports, "Shortcuts", {
|
|
438
|
+
enumerable: true,
|
|
439
|
+
get: function () {
|
|
440
|
+
return _Shortcuts.default;
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
Object.defineProperty(exports, "ShortcutsItem", {
|
|
444
|
+
enumerable: true,
|
|
445
|
+
get: function () {
|
|
446
|
+
return _Shortcuts.ShortcutsItem;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
435
449
|
Object.defineProperty(exports, "SideNav", {
|
|
436
450
|
enumerable: true,
|
|
437
451
|
get: function () {
|
|
@@ -744,6 +758,7 @@ var _RadioCard = _interopRequireWildcard(require("./RadioCard"));
|
|
|
744
758
|
var _Responsive = _interopRequireDefault(require("./Responsive"));
|
|
745
759
|
var _Search = _interopRequireDefault(require("./Search"));
|
|
746
760
|
var _Select = _interopRequireDefault(require("./Select"));
|
|
761
|
+
var _Shortcuts = _interopRequireWildcard(require("./Shortcuts"));
|
|
747
762
|
var _SideNav = _interopRequireDefault(require("./SideNav"));
|
|
748
763
|
var _Skeleton = _interopRequireDefault(require("./Skeleton"));
|
|
749
764
|
var _SkipLink = _interopRequireDefault(require("./SkipLink"));
|
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);
|
|
@@ -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;
|