@telus-uds/components-base 1.81.0 → 1.82.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 +17 -2
- package/lib/Autocomplete/Autocomplete.js +3 -1
- package/lib/Icon/Icon.js +24 -2
- package/lib/Listbox/Listbox.js +7 -1
- package/lib/Modal/Modal.js +40 -4
- package/lib/Modal/WebModal.js +73 -0
- package/lib/PriceLockup/PriceLockup.js +4 -1
- package/lib/PriceLockup/utils/renderFootnoteContent.js +2 -2
- package/lib/PriceLockup/utils/renderFootnoteLinks.js +2 -2
- package/lib/PriceLockup/utils/renderPrice.js +2 -2
- package/lib/PriceLockup/utils/renderTypography.js +1 -1
- package/lib/ProductCard/ProductCard.js +238 -0
- package/lib/ProductCard/dictionary.js +45 -0
- package/lib/ProductCard/index.js +10 -0
- package/lib/ProductCardGroup/ProductCardGroup.js +79 -0
- package/lib/ProductCardGroup/index.js +10 -0
- package/lib/index.js +16 -0
- package/lib-module/Autocomplete/Autocomplete.js +3 -1
- package/lib-module/Icon/Icon.js +24 -2
- package/lib-module/Listbox/Listbox.js +7 -1
- package/lib-module/Modal/Modal.js +42 -5
- package/lib-module/Modal/WebModal.js +65 -0
- package/lib-module/PriceLockup/PriceLockup.js +4 -1
- package/lib-module/PriceLockup/utils/renderFootnoteContent.js +2 -2
- package/lib-module/PriceLockup/utils/renderFootnoteLinks.js +2 -2
- package/lib-module/PriceLockup/utils/renderPrice.js +2 -2
- package/lib-module/PriceLockup/utils/renderTypography.js +1 -1
- package/lib-module/ProductCard/ProductCard.js +231 -0
- package/lib-module/ProductCard/dictionary.js +38 -0
- package/lib-module/ProductCard/index.js +2 -0
- package/lib-module/ProductCardGroup/ProductCardGroup.js +69 -0
- package/lib-module/ProductCardGroup/index.js +2 -0
- package/lib-module/index.js +2 -0
- package/package.json +2 -2
- package/src/Autocomplete/Autocomplete.jsx +4 -1
- package/src/Icon/Icon.jsx +30 -2
- package/src/Listbox/Listbox.jsx +6 -1
- package/src/Modal/Modal.jsx +42 -3
- package/src/Modal/WebModal.jsx +60 -0
- package/src/PriceLockup/PriceLockup.jsx +8 -2
- package/src/PriceLockup/utils/renderFootnoteContent.jsx +2 -2
- package/src/PriceLockup/utils/renderFootnoteLinks.jsx +2 -2
- package/src/PriceLockup/utils/renderPrice.jsx +2 -2
- package/src/PriceLockup/utils/renderTypography.jsx +1 -1
- package/src/ProductCard/ProductCard.jsx +193 -0
- package/src/ProductCard/dictionary.js +38 -0
- package/src/ProductCard/index.js +3 -0
- package/src/ProductCardGroup/ProductCardGroup.jsx +75 -0
- package/src/ProductCardGroup/index.js +3 -0
- package/src/index.js +2 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
9
|
+
var _View = _interopRequireDefault(require("react-native-web/dist/cjs/exports/View"));
|
|
10
|
+
var _utils = require("../utils");
|
|
11
|
+
var _ProductCard = _interopRequireDefault(require("../ProductCard"));
|
|
12
|
+
var _StackView = require("../StackView");
|
|
13
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
16
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
17
|
+
const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.htmlAttrs, _utils.viewProps, _utils.a11yProps]);
|
|
18
|
+
const ProductCardGroup = _ref => {
|
|
19
|
+
let {
|
|
20
|
+
productCards,
|
|
21
|
+
maxSelection = 1,
|
|
22
|
+
...rest
|
|
23
|
+
} = _ref;
|
|
24
|
+
const [selectedCardIds, setSelectedCardIds] = (0, _react.useState)([]);
|
|
25
|
+
const handleSelect = id => {
|
|
26
|
+
const isAlreadySelected = selectedCardIds.includes(id);
|
|
27
|
+
let updatedSelectedCardIds;
|
|
28
|
+
if (isAlreadySelected) {
|
|
29
|
+
updatedSelectedCardIds = selectedCardIds.filter(cardId => cardId !== id);
|
|
30
|
+
} else if (maxSelection && selectedCardIds.length >= maxSelection) {
|
|
31
|
+
updatedSelectedCardIds = selectedCardIds.filter((_, index) => index !== 0).concat(id);
|
|
32
|
+
} else {
|
|
33
|
+
updatedSelectedCardIds = [...selectedCardIds, id];
|
|
34
|
+
}
|
|
35
|
+
setSelectedCardIds(updatedSelectedCardIds);
|
|
36
|
+
};
|
|
37
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
|
|
38
|
+
...selectProps(rest),
|
|
39
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_StackView.StackWrap, {
|
|
40
|
+
direction: {
|
|
41
|
+
xs: 'column',
|
|
42
|
+
lg: 'row'
|
|
43
|
+
},
|
|
44
|
+
space: 4,
|
|
45
|
+
children: productCards.map((cardProperties, index) => {
|
|
46
|
+
const cardId = cardProperties.id || index;
|
|
47
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
|
|
48
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ProductCard.default, {
|
|
49
|
+
cardId: cardId,
|
|
50
|
+
isSelected: selectedCardIds.includes(cardId),
|
|
51
|
+
onSelect: handleSelect,
|
|
52
|
+
...cardProperties
|
|
53
|
+
}, cardId)
|
|
54
|
+
}, cardId);
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
ProductCardGroup.displayName = 'ProductCardGroup';
|
|
60
|
+
ProductCardGroup.propTypes = {
|
|
61
|
+
...selectedSystemPropTypes,
|
|
62
|
+
/**
|
|
63
|
+
* The maximum number of ProductCards a user may select at once. Defaults to 1.
|
|
64
|
+
* To have no limit and allow any number of selections, pass `null`.
|
|
65
|
+
*/
|
|
66
|
+
maxSelection: _propTypes.default.number,
|
|
67
|
+
/**
|
|
68
|
+
* Props to be passed to the `ProductCard` component.
|
|
69
|
+
* id is required for each card.
|
|
70
|
+
* You may also pass in a custom dictionary object.
|
|
71
|
+
*/
|
|
72
|
+
productCards: _propTypes.default.arrayOf(_propTypes.default.shape({
|
|
73
|
+
id: _propTypes.default.string.isRequired,
|
|
74
|
+
image: _propTypes.default.object,
|
|
75
|
+
dictionary: _propTypes.default.object
|
|
76
|
+
})).isRequired
|
|
77
|
+
};
|
|
78
|
+
var _default = ProductCardGroup;
|
|
79
|
+
exports.default = _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _ProductCardGroup = _interopRequireDefault(require("./ProductCardGroup"));
|
|
8
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
|
+
var _default = _ProductCardGroup.default;
|
|
10
|
+
exports.default = _default;
|
package/lib/index.js
CHANGED
|
@@ -37,6 +37,8 @@ var _exportNames = {
|
|
|
37
37
|
OrderedList: true,
|
|
38
38
|
Pagination: true,
|
|
39
39
|
PriceLockup: true,
|
|
40
|
+
ProductCard: true,
|
|
41
|
+
ProductCardGroup: true,
|
|
40
42
|
Progress: true,
|
|
41
43
|
QuickLinks: true,
|
|
42
44
|
QuickLinksFeature: true,
|
|
@@ -292,6 +294,18 @@ Object.defineProperty(exports, "PriceLockup", {
|
|
|
292
294
|
return _PriceLockup.default;
|
|
293
295
|
}
|
|
294
296
|
});
|
|
297
|
+
Object.defineProperty(exports, "ProductCard", {
|
|
298
|
+
enumerable: true,
|
|
299
|
+
get: function () {
|
|
300
|
+
return _ProductCard.default;
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
Object.defineProperty(exports, "ProductCardGroup", {
|
|
304
|
+
enumerable: true,
|
|
305
|
+
get: function () {
|
|
306
|
+
return _ProductCardGroup.default;
|
|
307
|
+
}
|
|
308
|
+
});
|
|
295
309
|
Object.defineProperty(exports, "Progress", {
|
|
296
310
|
enumerable: true,
|
|
297
311
|
get: function () {
|
|
@@ -600,6 +614,8 @@ var _Notification = _interopRequireDefault(require("./Notification"));
|
|
|
600
614
|
var _OrderedList = _interopRequireDefault(require("./OrderedList"));
|
|
601
615
|
var _Pagination = _interopRequireDefault(require("./Pagination"));
|
|
602
616
|
var _PriceLockup = _interopRequireDefault(require("./PriceLockup"));
|
|
617
|
+
var _ProductCard = _interopRequireDefault(require("./ProductCard"));
|
|
618
|
+
var _ProductCardGroup = _interopRequireDefault(require("./ProductCardGroup"));
|
|
603
619
|
var _Progress = _interopRequireDefault(require("./Progress"));
|
|
604
620
|
var _QuickLinks = _interopRequireDefault(require("./QuickLinks"));
|
|
605
621
|
var _QuickLinksFeature = _interopRequireDefault(require("./QuickLinksFeature"));
|
|
@@ -239,6 +239,7 @@ const Autocomplete = /*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
|
239
239
|
setCurrentValue(newValue);
|
|
240
240
|
if (!isControlled && inputRef !== null && inputRef !== void 0 && inputRef.current) inputRef.current.value = newValue;
|
|
241
241
|
if (nested) setNestedSelectedValue(newValue);
|
|
242
|
+
inputRef.current.focus();
|
|
242
243
|
};
|
|
243
244
|
|
|
244
245
|
/**
|
|
@@ -268,7 +269,8 @@ const Autocomplete = /*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
|
268
269
|
if (event.type === 'keydown' && (event.key === 'Escape' || event.key === '27') || event.type === 'click' && !(openOverlayRef !== null && openOverlayRef !== void 0 && (_openOverlayRef$curre = openOverlayRef.current) !== null && _openOverlayRef$curre !== void 0 && _openOverlayRef$curre.contains(event.target)) || event.type === 'touchstart' && openOverlayRef !== null && openOverlayRef !== void 0 && openOverlayRef.current && event.touches[0].target && !(openOverlayRef !== null && openOverlayRef !== void 0 && (_openOverlayRef$curre2 = openOverlayRef.current) !== null && _openOverlayRef$curre2 !== void 0 && _openOverlayRef$curre2.contains(event.touches[0].target))) {
|
|
269
270
|
setIsExpanded(false);
|
|
270
271
|
setNestedSelectedValue(null);
|
|
271
|
-
} else if (event.type === 'keydown' && event.key === 'ArrowDown' && isExpanded && !isLoading && targetRef !== null && targetRef !== void 0 && targetRef.current) {
|
|
272
|
+
} else if (event.type === 'keydown' && (event.key === 'ArrowDown' || event.key === 'Tab') && isExpanded && !isLoading && targetRef !== null && targetRef !== void 0 && targetRef.current) {
|
|
273
|
+
event.preventDefault();
|
|
272
274
|
targetRef.current.focus();
|
|
273
275
|
}
|
|
274
276
|
};
|
package/lib-module/Icon/Icon.js
CHANGED
|
@@ -22,6 +22,25 @@ const Icon = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
22
22
|
size: size,
|
|
23
23
|
color: themeTokens.color
|
|
24
24
|
});
|
|
25
|
+
const paddingStyles = variant !== null && variant !== void 0 && variant.padding ? {
|
|
26
|
+
padding: themeTokens.width,
|
|
27
|
+
width: themeTokens.size + themeTokens.width * 2,
|
|
28
|
+
// sets the diameter of the circle which is the size of the icon plus twice the general padding established to obtain a perfect circle
|
|
29
|
+
height: themeTokens.size + themeTokens.width * 2
|
|
30
|
+
} : {};
|
|
31
|
+
const getIconContentForMobile = () => {
|
|
32
|
+
if (Object.keys(paddingStyles).length) {
|
|
33
|
+
return /*#__PURE__*/_jsx(View, {
|
|
34
|
+
style: {
|
|
35
|
+
backgroundColor: themeTokens.backgroundColor,
|
|
36
|
+
borderRadius: themeTokens.borderRadius,
|
|
37
|
+
...paddingStyles
|
|
38
|
+
},
|
|
39
|
+
children: iconContent
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return iconContent;
|
|
43
|
+
};
|
|
25
44
|
return Platform.OS === 'web' ? /*#__PURE__*/_jsx(View, {
|
|
26
45
|
ref: ref
|
|
27
46
|
// eslint-disable-next-line react-native/no-inline-styles
|
|
@@ -31,11 +50,14 @@ const Icon = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
31
50
|
// https://github.com/telus/universal-design-system/issues/487
|
|
32
51
|
transition: 'transform 200ms, color 200ms',
|
|
33
52
|
transform: [themeTokens.scale ? `scale(${themeTokens.scale})` : '', themeTokens.translateX ? `translateX(${themeTokens.translateX}px)` : '', themeTokens.translateY ? `translateY(${themeTokens.translateY}px)` : ''].filter(exists => exists).join(' '),
|
|
34
|
-
...style
|
|
53
|
+
...style,
|
|
54
|
+
backgroundColor: themeTokens.backgroundColor,
|
|
55
|
+
borderRadius: themeTokens.borderRadius,
|
|
56
|
+
...paddingStyles
|
|
35
57
|
},
|
|
36
58
|
dataSet: dataSet,
|
|
37
59
|
children: iconContent
|
|
38
|
-
}) :
|
|
60
|
+
}) : getIconContentForMobile();
|
|
39
61
|
});
|
|
40
62
|
Icon.displayName = 'Icon';
|
|
41
63
|
export const iconComponentPropTypes = {
|
|
@@ -67,8 +67,14 @@ const Listbox = _ref => {
|
|
|
67
67
|
// Return focus to the dropdown control after leaving the last item
|
|
68
68
|
parentRef === null || parentRef === void 0 ? void 0 : (_parentRef$current3 = parentRef.current) === null || _parentRef$current3 === void 0 ? void 0 : _parentRef$current3.focus();
|
|
69
69
|
if (onClose) onClose(event);
|
|
70
|
+
} else if (!nextItemRef && firstItemRef) {
|
|
71
|
+
var _firstItemRef$current;
|
|
72
|
+
// If the last item is focused, move the focus to the first one
|
|
73
|
+
event.preventDefault();
|
|
74
|
+
setFocusedIndex(0);
|
|
75
|
+
(_firstItemRef$current = firstItemRef.current) === null || _firstItemRef$current === void 0 ? void 0 : _firstItemRef$current.focus();
|
|
70
76
|
}
|
|
71
|
-
}, [focusedIndex, onClose, parentRef]);
|
|
77
|
+
}, [focusedIndex, onClose, parentRef, firstItemRef]);
|
|
72
78
|
|
|
73
79
|
// Add listeners for mouse clicks outside and for key presses
|
|
74
80
|
useEffect(() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef } from 'react';
|
|
1
|
+
import React, { forwardRef, useEffect, useRef } from 'react';
|
|
2
2
|
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
3
3
|
import TouchableWithoutFeedback from "react-native-web/dist/exports/TouchableWithoutFeedback";
|
|
4
4
|
import View from "react-native-web/dist/exports/View";
|
|
@@ -13,8 +13,10 @@ import IconButton from '../IconButton';
|
|
|
13
13
|
import dictionary from './dictionary';
|
|
14
14
|
import useScrollBlocking from '../utils/useScrollBlocking';
|
|
15
15
|
import ModalContent from './ModalContent';
|
|
16
|
+
import WebModal from './WebModal';
|
|
16
17
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
17
18
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
|
+
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
18
20
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
19
21
|
const selectContainerStyles = _ref => {
|
|
20
22
|
let {
|
|
@@ -143,12 +145,32 @@ const Modal = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
143
145
|
// Show the custom react node passed to `closedButton` or the default close button if `closeButton` is `undefined`.
|
|
144
146
|
// Hide the close button if `closeButton` is `null`.
|
|
145
147
|
const showCloseButton = closeButton !== null;
|
|
148
|
+
|
|
149
|
+
// These refs are used to manage focus in the web modal container
|
|
150
|
+
const focusTrapRef = useRef(null);
|
|
151
|
+
const closeButtonRef = useRef(null);
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (Platform.OS === 'web') {
|
|
154
|
+
const handleFocus = () => {
|
|
155
|
+
// If the focus is on the last item of the web modal container, move it to the close button
|
|
156
|
+
if (document.activeElement === focusTrapRef.current) {
|
|
157
|
+
closeButtonRef.current.focus();
|
|
158
|
+
}
|
|
159
|
+
return undefined;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Add an event listener to manage focus in the web modal container
|
|
163
|
+
document.addEventListener('focusin', handleFocus);
|
|
164
|
+
|
|
165
|
+
// Clean up the event listener
|
|
166
|
+
return () => document.removeEventListener('focusin', handleFocus);
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}, []);
|
|
146
170
|
if (!isOpen) {
|
|
147
171
|
return null;
|
|
148
172
|
}
|
|
149
|
-
|
|
150
|
-
transparent: true,
|
|
151
|
-
...selectProps(rest),
|
|
173
|
+
const content = /*#__PURE__*/_jsx(_Fragment, {
|
|
152
174
|
children: /*#__PURE__*/_jsxs(ScrollView, {
|
|
153
175
|
contentContainerStyle: [staticStyles.positioningContainer],
|
|
154
176
|
ref: modalRef,
|
|
@@ -166,7 +188,8 @@ const Modal = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
166
188
|
onPress: handleClose,
|
|
167
189
|
icon: CloseIconComponent,
|
|
168
190
|
accessibilityRole: "button",
|
|
169
|
-
accessibilityLabel: closeLabel
|
|
191
|
+
accessibilityLabel: closeLabel,
|
|
192
|
+
ref: closeButtonRef
|
|
170
193
|
})
|
|
171
194
|
}), /*#__PURE__*/_jsx(ModalContent, {
|
|
172
195
|
tokens: tokens,
|
|
@@ -198,6 +221,20 @@ const Modal = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
198
221
|
})]
|
|
199
222
|
})
|
|
200
223
|
});
|
|
224
|
+
if (Platform.OS === 'web') {
|
|
225
|
+
return /*#__PURE__*/_jsxs(WebModal, {
|
|
226
|
+
...selectProps(rest),
|
|
227
|
+
children: [content, /*#__PURE__*/_jsx(View, {
|
|
228
|
+
accessibilityRole: "button",
|
|
229
|
+
ref: focusTrapRef
|
|
230
|
+
})]
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return /*#__PURE__*/_jsx(NativeModal, {
|
|
234
|
+
transparent: true,
|
|
235
|
+
...selectProps(rest),
|
|
236
|
+
children: content
|
|
237
|
+
});
|
|
201
238
|
});
|
|
202
239
|
Modal.displayName = 'Modal';
|
|
203
240
|
Modal.propTypes = {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import View from "react-native-web/dist/exports/View";
|
|
4
|
+
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
5
|
+
import { a11yProps, selectSystemProps, viewProps } from '../utils';
|
|
6
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* WebModal component.
|
|
11
|
+
*
|
|
12
|
+
* @component
|
|
13
|
+
* @param {Object} props - The component props.
|
|
14
|
+
* @param {ReactNode} props.children - The content of the modal.
|
|
15
|
+
* @returns {JSX.Element} The rendered WebModal component.
|
|
16
|
+
*/
|
|
17
|
+
const WebModal = _ref => {
|
|
18
|
+
let {
|
|
19
|
+
children,
|
|
20
|
+
...rest
|
|
21
|
+
} = _ref;
|
|
22
|
+
return /*#__PURE__*/_jsx(View, {
|
|
23
|
+
style: staticStyles.container,
|
|
24
|
+
...selectProps(rest),
|
|
25
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
26
|
+
style: staticStyles.content,
|
|
27
|
+
children: children
|
|
28
|
+
})
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
WebModal.propTypes = {
|
|
32
|
+
...selectedSystemPropTypes,
|
|
33
|
+
// children to be rendered within the modal
|
|
34
|
+
children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)])
|
|
35
|
+
};
|
|
36
|
+
const staticStyles = StyleSheet.create({
|
|
37
|
+
container: {
|
|
38
|
+
position: 'fixed',
|
|
39
|
+
backgroundColor: 'rgba(0, 0, 0, 0)',
|
|
40
|
+
top: 0,
|
|
41
|
+
right: 0,
|
|
42
|
+
left: 0,
|
|
43
|
+
bottom: 0,
|
|
44
|
+
alignItems: 'stretch',
|
|
45
|
+
boxSizing: 'border-box',
|
|
46
|
+
display: 'flex',
|
|
47
|
+
flexBasis: 'auto',
|
|
48
|
+
flexDirection: 'column',
|
|
49
|
+
flexShrink: 0,
|
|
50
|
+
listStyle: 'none',
|
|
51
|
+
margin: 0,
|
|
52
|
+
minHeight: 0,
|
|
53
|
+
minWidth: 0,
|
|
54
|
+
padding: 0,
|
|
55
|
+
textDecoration: 'none',
|
|
56
|
+
zIndex: 1
|
|
57
|
+
},
|
|
58
|
+
content: {
|
|
59
|
+
flex: 1,
|
|
60
|
+
flexGrow: 1,
|
|
61
|
+
flexShrink: 1,
|
|
62
|
+
flexBasis: 0
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
export default WebModal;
|
|
@@ -112,7 +112,6 @@ const PriceLockup = _ref7 => {
|
|
|
112
112
|
bottomTextMarginTop,
|
|
113
113
|
priceMarginBottom,
|
|
114
114
|
bottomLinksMarginLeft,
|
|
115
|
-
topTextMarginBottom,
|
|
116
115
|
fontColor,
|
|
117
116
|
dividerColor,
|
|
118
117
|
...themeTokens
|
|
@@ -134,6 +133,7 @@ const PriceLockup = _ref7 => {
|
|
|
134
133
|
...selectProps(rest)
|
|
135
134
|
}],
|
|
136
135
|
children: [topText ? /*#__PURE__*/_jsx(View, {
|
|
136
|
+
style: staticStyles.topText,
|
|
137
137
|
children: renderTypography(topText, topTextTypographyTokens)
|
|
138
138
|
}) : null, renderPrice(price, rateText, ratePosition, signDirection, currencySymbol, currencySymbolTypographyTokens, amountTypographyTokens, centsTypographyTokens, rateTypographyTokens, fontColor, strikeThrough, a11yText, bottomText, bottomLinksMarginLeft, footnoteLinks, onClickFootnote, themeTokens), bottomText ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
139
139
|
children: [/*#__PURE__*/_jsx(Divider, {
|
|
@@ -210,5 +210,8 @@ export default PriceLockup;
|
|
|
210
210
|
const staticStyles = StyleSheet.create({
|
|
211
211
|
priceLockupContainer: {
|
|
212
212
|
alignSelf: 'flex-start'
|
|
213
|
+
},
|
|
214
|
+
topText: {
|
|
215
|
+
marginBottom: 4
|
|
213
216
|
}
|
|
214
217
|
});
|
|
@@ -44,13 +44,13 @@ const renderFootnoteContent = (footnoteMarginTop, bottomTextMarginTop, bottomTex
|
|
|
44
44
|
bottomTextMarginTop
|
|
45
45
|
}),
|
|
46
46
|
children: [renderTypography(bottomText, bottomTextTypographyTokens, undefined, fontColor), ' ']
|
|
47
|
-
}), footnoteLinks.length <= MAX_FOOTNOTE_LINKS_ALLOWED ? /*#__PURE__*/_jsx(View, {
|
|
47
|
+
}), (footnoteLinks === null || footnoteLinks === void 0 ? void 0 : footnoteLinks.length) <= MAX_FOOTNOTE_LINKS_ALLOWED ? /*#__PURE__*/_jsx(View, {
|
|
48
48
|
style: [staticStyles.footnoteLinkContainer, selectFootnoteLinksStyles({
|
|
49
49
|
bottomLinksMarginLeft
|
|
50
50
|
})],
|
|
51
51
|
children: renderFootnoteLinks(footnoteLinks, themeTokens, onClickFootnote)
|
|
52
52
|
}) : null]
|
|
53
|
-
}), footnoteLinks.length > MAX_FOOTNOTE_LINKS_ALLOWED ? /*#__PURE__*/_jsx(View, {
|
|
53
|
+
}), (footnoteLinks === null || footnoteLinks === void 0 ? void 0 : footnoteLinks.length) > MAX_FOOTNOTE_LINKS_ALLOWED ? /*#__PURE__*/_jsx(View, {
|
|
54
54
|
style: staticStyles.verticalFootnoteLinkContainer,
|
|
55
55
|
children: renderFootnoteLinks(footnoteLinks, themeTokens, onClickFootnote)
|
|
56
56
|
}) : null]
|
|
@@ -11,7 +11,7 @@ const selectFootnoteLinkStyles = (_ref, footnoteLinks) => {
|
|
|
11
11
|
} = _ref;
|
|
12
12
|
// This is used to apply the proper line height when there is 4 or more footnote links
|
|
13
13
|
const MAX_FOOTNOTE_LINKS_ALLOWED = 3;
|
|
14
|
-
const lineHeight = footnoteLinks.length > MAX_FOOTNOTE_LINKS_ALLOWED ? footnoteLinkFontSize * footnoteLinkLineHeight : undefined;
|
|
14
|
+
const lineHeight = (footnoteLinks === null || footnoteLinks === void 0 ? void 0 : footnoteLinks.length) > MAX_FOOTNOTE_LINKS_ALLOWED ? footnoteLinkFontSize * footnoteLinkLineHeight : undefined;
|
|
15
15
|
return {
|
|
16
16
|
color: footnoteLinkColor,
|
|
17
17
|
fontName: footnoteLinkFontName,
|
|
@@ -20,7 +20,7 @@ const selectFootnoteLinkStyles = (_ref, footnoteLinks) => {
|
|
|
20
20
|
fontSize: footnoteLinkFontSize
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
|
-
const renderFootnoteLinks = (footnoteLinks, themeTokens, onClickFootnote) => footnoteLinks
|
|
23
|
+
const renderFootnoteLinks = (footnoteLinks, themeTokens, onClickFootnote) => (footnoteLinks === null || footnoteLinks === void 0 ? void 0 : footnoteLinks.length) > 0 ? /*#__PURE__*/_jsx(FootnoteLink, {
|
|
24
24
|
tokens: selectFootnoteLinkStyles(themeTokens, footnoteLinks),
|
|
25
25
|
content: footnoteLinks,
|
|
26
26
|
onClick: onClickFootnote
|
|
@@ -68,13 +68,13 @@ const renderPrice = (price, rateText, ratePosition, signDirection, currencySymbo
|
|
|
68
68
|
}), rateText ? /*#__PURE__*/_jsx(Text, {
|
|
69
69
|
style: ratePosition === 'bottom' ? staticStyles.rateTextVerticalPosition : [staticStyles.rateTextPosition, staticStyles.rateTextVerticalPosition],
|
|
70
70
|
children: renderTypography(rateText, rateTypographyTokens, ratePosition, fontColor)
|
|
71
|
-
}) : null, !bottomText && footnoteLinks.length <= MAX_FOOTNOTE_LINKS_ALLOWED ? /*#__PURE__*/_jsx(Text, {
|
|
71
|
+
}) : null, !bottomText && (footnoteLinks === null || footnoteLinks === void 0 ? void 0 : footnoteLinks.length) <= MAX_FOOTNOTE_LINKS_ALLOWED ? /*#__PURE__*/_jsx(Text, {
|
|
72
72
|
style: [footnoteLinkPositionStyles, selectFootnoteLinksStyles({
|
|
73
73
|
bottomLinksMarginLeft
|
|
74
74
|
})],
|
|
75
75
|
children: renderFootnoteLinks(footnoteLinks, themeTokens, onClickFootnote)
|
|
76
76
|
}) : null]
|
|
77
|
-
}), !bottomText && footnoteLinks.length > MAX_FOOTNOTE_LINKS_ALLOWED ? /*#__PURE__*/_jsx(View, {
|
|
77
|
+
}), !bottomText && (footnoteLinks === null || footnoteLinks === void 0 ? void 0 : footnoteLinks.length) > MAX_FOOTNOTE_LINKS_ALLOWED ? /*#__PURE__*/_jsx(View, {
|
|
78
78
|
style: staticStyles.verticalFootnoteLinkContainer,
|
|
79
79
|
children: renderFootnoteLinks(footnoteLinks, themeTokens, onClickFootnote)
|
|
80
80
|
}) : null]
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import Typography from '../../Typography';
|
|
3
3
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
4
4
|
const renderTypography = (value, themeTokens, ratePosition, fontColor) => {
|
|
5
|
-
const customProps = ratePosition === 'bottom' ? {
|
|
5
|
+
const customProps = ratePosition === 'bottom' && value !== '$' ? {
|
|
6
6
|
variant: {
|
|
7
7
|
size: 'micro'
|
|
8
8
|
},
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
4
|
+
import View from "react-native-web/dist/exports/View";
|
|
5
|
+
import Image from "react-native-web/dist/exports/Image";
|
|
6
|
+
import { useViewport } from '../ViewportProvider';
|
|
7
|
+
import { useThemeTokens } from '../ThemeProvider';
|
|
8
|
+
import defaultDictionary from './dictionary';
|
|
9
|
+
import { selectSystemProps, getTokensPropType, htmlAttrs, viewProps, useInputValue, useCopy, a11yProps } from '../utils';
|
|
10
|
+
import Badge from '../Badge';
|
|
11
|
+
import PriceLockup from '../PriceLockup';
|
|
12
|
+
import Typography from '../Typography';
|
|
13
|
+
import { Button } from '../Button';
|
|
14
|
+
import StackView from '../StackView';
|
|
15
|
+
import Box from '../Box';
|
|
16
|
+
import Icon from '../Icon';
|
|
17
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs, viewProps, a11yProps]);
|
|
20
|
+
const selectProductCardTokens = _ref => {
|
|
21
|
+
let {
|
|
22
|
+
borderStyle,
|
|
23
|
+
borderColor,
|
|
24
|
+
borderWidth,
|
|
25
|
+
borderRadius,
|
|
26
|
+
paddingHorizontal,
|
|
27
|
+
paddingVertical
|
|
28
|
+
} = _ref;
|
|
29
|
+
return {
|
|
30
|
+
borderStyle,
|
|
31
|
+
borderColor,
|
|
32
|
+
borderWidth,
|
|
33
|
+
borderRadius,
|
|
34
|
+
paddingHorizontal,
|
|
35
|
+
paddingVertical
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const ProductCard = _ref2 => {
|
|
39
|
+
var _getCopy;
|
|
40
|
+
let {
|
|
41
|
+
copy = 'en',
|
|
42
|
+
dictionary = defaultDictionary,
|
|
43
|
+
image = {
|
|
44
|
+
src: '',
|
|
45
|
+
alt: ''
|
|
46
|
+
},
|
|
47
|
+
cardId,
|
|
48
|
+
isSelected,
|
|
49
|
+
onSelect,
|
|
50
|
+
tokens,
|
|
51
|
+
...rest
|
|
52
|
+
} = _ref2;
|
|
53
|
+
const viewport = useViewport();
|
|
54
|
+
const themeTokens = useThemeTokens('ProductCard', tokens, {
|
|
55
|
+
viewport
|
|
56
|
+
});
|
|
57
|
+
const getCopy = useCopy({
|
|
58
|
+
copy,
|
|
59
|
+
dictionary
|
|
60
|
+
});
|
|
61
|
+
const {
|
|
62
|
+
currentValue,
|
|
63
|
+
setValue
|
|
64
|
+
} = useInputValue();
|
|
65
|
+
const hasClicked = isSelected || currentValue;
|
|
66
|
+
const handlePress = event => {
|
|
67
|
+
if (cardId) {
|
|
68
|
+
onSelect(cardId);
|
|
69
|
+
} else {
|
|
70
|
+
setValue(!currentValue, event);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const renderButton = hasClicked ? /*#__PURE__*/_jsx(Box, {
|
|
74
|
+
vertical: 1,
|
|
75
|
+
children: /*#__PURE__*/_jsxs(StackView, {
|
|
76
|
+
space: 2,
|
|
77
|
+
direction: "row",
|
|
78
|
+
children: [/*#__PURE__*/_jsx(Icon, {
|
|
79
|
+
icon: themeTokens.selectedButtonIcon,
|
|
80
|
+
variant: {
|
|
81
|
+
color: 'success'
|
|
82
|
+
}
|
|
83
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
|
84
|
+
variant: {
|
|
85
|
+
size: 'h4'
|
|
86
|
+
},
|
|
87
|
+
tokens: {
|
|
88
|
+
fontWeight: 400
|
|
89
|
+
},
|
|
90
|
+
children: getCopy('selectedButtonLabel')
|
|
91
|
+
})]
|
|
92
|
+
})
|
|
93
|
+
}) : /*#__PURE__*/_jsx(Button, {
|
|
94
|
+
onPress: handlePress,
|
|
95
|
+
variant: {
|
|
96
|
+
purpose: 'primary',
|
|
97
|
+
size: 'small',
|
|
98
|
+
width: 'full'
|
|
99
|
+
},
|
|
100
|
+
children: getCopy('buttonLabel')
|
|
101
|
+
});
|
|
102
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
103
|
+
...selectProps(rest),
|
|
104
|
+
style: [selectProductCardTokens(themeTokens), staticStyles.container],
|
|
105
|
+
children: [image !== null && image !== void 0 && image.src ? /*#__PURE__*/_jsx(View, {
|
|
106
|
+
style: staticStyles.imageContainer,
|
|
107
|
+
children: /*#__PURE__*/_jsx(Image, {
|
|
108
|
+
source: image.src,
|
|
109
|
+
style: staticStyles.image,
|
|
110
|
+
alt: image.alt,
|
|
111
|
+
accessibilityLabel: image.alt,
|
|
112
|
+
resizeMethod: "resize",
|
|
113
|
+
accessibilityIgnoresInvertColors: true
|
|
114
|
+
})
|
|
115
|
+
}) : null, /*#__PURE__*/_jsx(View, {
|
|
116
|
+
style: staticStyles.textContainer,
|
|
117
|
+
children: /*#__PURE__*/_jsx(Box, {
|
|
118
|
+
left: 3,
|
|
119
|
+
children: /*#__PURE__*/_jsxs(StackView, {
|
|
120
|
+
space: 1,
|
|
121
|
+
children: [getCopy('badgeText') ? /*#__PURE__*/_jsx(Badge, {
|
|
122
|
+
variant: {
|
|
123
|
+
outline: true,
|
|
124
|
+
purpose: 'editorial'
|
|
125
|
+
},
|
|
126
|
+
children: getCopy('badgeText')
|
|
127
|
+
}) : null, /*#__PURE__*/_jsx(Typography, {
|
|
128
|
+
variant: {
|
|
129
|
+
size: 'h6'
|
|
130
|
+
},
|
|
131
|
+
children: getCopy('brandName')
|
|
132
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
|
133
|
+
variant: {
|
|
134
|
+
size: 'h4',
|
|
135
|
+
colour: 'brand'
|
|
136
|
+
},
|
|
137
|
+
tokens: {
|
|
138
|
+
fontWeight: 400
|
|
139
|
+
},
|
|
140
|
+
children: getCopy('productName')
|
|
141
|
+
}), /*#__PURE__*/_jsxs(StackView, {
|
|
142
|
+
space: 3,
|
|
143
|
+
divider: true,
|
|
144
|
+
direction: "row",
|
|
145
|
+
children: [/*#__PURE__*/_jsx(PriceLockup, {
|
|
146
|
+
...getCopy('primaryPrice'),
|
|
147
|
+
size: "small",
|
|
148
|
+
ratePosition: "bottom"
|
|
149
|
+
}), (_getCopy = getCopy('secondaryPrice')) !== null && _getCopy !== void 0 && _getCopy.price ? /*#__PURE__*/_jsx(PriceLockup, {
|
|
150
|
+
...getCopy('secondaryPrice'),
|
|
151
|
+
size: "small",
|
|
152
|
+
ratePosition: "bottom"
|
|
153
|
+
}) : null]
|
|
154
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
155
|
+
top: 2,
|
|
156
|
+
children: /*#__PURE__*/_jsxs(StackView, {
|
|
157
|
+
space: 2,
|
|
158
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
159
|
+
variant: {
|
|
160
|
+
size: 'h6'
|
|
161
|
+
},
|
|
162
|
+
tokens: {
|
|
163
|
+
fontWeight: 500
|
|
164
|
+
},
|
|
165
|
+
children: getCopy('term')
|
|
166
|
+
}), getCopy('buttonLabel') ? /*#__PURE__*/_jsx(Box, {
|
|
167
|
+
top: 1,
|
|
168
|
+
children: renderButton
|
|
169
|
+
}) : null]
|
|
170
|
+
})
|
|
171
|
+
})]
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
})]
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
ProductCard.displayName = 'ProductCard';
|
|
178
|
+
|
|
179
|
+
// If a language dictionary entry is provided, it must contain every key
|
|
180
|
+
const dictionaryContentShape = PropTypes.shape({
|
|
181
|
+
badgeText: PropTypes.string,
|
|
182
|
+
brandName: PropTypes.string.isRequired,
|
|
183
|
+
productName: PropTypes.string.isRequired,
|
|
184
|
+
primaryPrice: PropTypes.object.isRequired,
|
|
185
|
+
secondaryPrice: PropTypes.object,
|
|
186
|
+
term: PropTypes.string.isRequired,
|
|
187
|
+
buttonLabel: PropTypes.string.isRequired,
|
|
188
|
+
selectedButtonLabel: PropTypes.string.isRequired
|
|
189
|
+
});
|
|
190
|
+
ProductCard.propTypes = {
|
|
191
|
+
...selectedSystemPropTypes,
|
|
192
|
+
image: PropTypes.shape({
|
|
193
|
+
src: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
194
|
+
alt: PropTypes.string
|
|
195
|
+
}),
|
|
196
|
+
/**
|
|
197
|
+
* Select English or French copy for the place holder labels.
|
|
198
|
+
* You may also pass in a custom dictionary object.
|
|
199
|
+
*/
|
|
200
|
+
copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr'])]),
|
|
201
|
+
/**
|
|
202
|
+
* Override the default dictionary, by passing the complete dictionary object for `en` and `fr`
|
|
203
|
+
*/
|
|
204
|
+
dictionary: PropTypes.shape({
|
|
205
|
+
en: dictionaryContentShape,
|
|
206
|
+
fr: dictionaryContentShape
|
|
207
|
+
}),
|
|
208
|
+
tokens: getTokensPropType('ProductCard')
|
|
209
|
+
};
|
|
210
|
+
export default ProductCard;
|
|
211
|
+
const staticStyles = StyleSheet.create({
|
|
212
|
+
container: {
|
|
213
|
+
flexDirection: 'row',
|
|
214
|
+
flex: 1
|
|
215
|
+
},
|
|
216
|
+
imageContainer: {
|
|
217
|
+
width: '30%',
|
|
218
|
+
minWidth: 96,
|
|
219
|
+
maxWidth: 96
|
|
220
|
+
},
|
|
221
|
+
image: {
|
|
222
|
+
resizeMode: 'contain',
|
|
223
|
+
width: '100%',
|
|
224
|
+
height: undefined,
|
|
225
|
+
// This is to maintain the aspect ratio
|
|
226
|
+
aspectRatio: 0.8
|
|
227
|
+
},
|
|
228
|
+
textContainer: {
|
|
229
|
+
width: '70%'
|
|
230
|
+
}
|
|
231
|
+
});
|