@telus-uds/components-web 1.7.0 → 1.9.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.
Files changed (220) hide show
  1. package/.eslintignore +2 -0
  2. package/.vscode/settings.json +7 -0
  3. package/CHANGELOG.md +39 -2
  4. package/lib/Autocomplete/Autocomplete.js +393 -0
  5. package/lib/Autocomplete/Loading.js +51 -0
  6. package/lib/Autocomplete/Suggestions.js +81 -0
  7. package/lib/Autocomplete/constants.js +19 -0
  8. package/lib/Autocomplete/dictionary.js +19 -0
  9. package/lib/Autocomplete/index.js +13 -0
  10. package/lib/BlockQuote/BlockQuote.js +173 -0
  11. package/lib/BlockQuote/index.js +13 -0
  12. package/lib/Callout/Callout.js +3 -0
  13. package/lib/Card/Card.js +180 -0
  14. package/lib/Card/CardContent.js +110 -0
  15. package/lib/Card/CardFooter.js +98 -0
  16. package/lib/Card/index.js +13 -0
  17. package/lib/Countdown/Countdown.js +189 -0
  18. package/lib/Countdown/Segment.js +111 -0
  19. package/lib/Countdown/constants.js +14 -0
  20. package/lib/Countdown/dictionary.js +29 -0
  21. package/lib/Countdown/index.js +13 -0
  22. package/lib/Countdown/types.js +39 -0
  23. package/lib/Countdown/useCountdown.js +40 -0
  24. package/lib/IconButton/IconButton.js +70 -0
  25. package/lib/IconButton/index.js +13 -0
  26. package/lib/Listbox/GroupControl.js +94 -0
  27. package/lib/Listbox/Listbox.js +164 -0
  28. package/lib/Listbox/ListboxGroup.js +129 -0
  29. package/lib/Listbox/ListboxItem.js +137 -0
  30. package/lib/Listbox/ListboxOverlay.js +89 -0
  31. package/lib/Listbox/PressableItem.js +149 -0
  32. package/lib/Listbox/index.js +13 -0
  33. package/lib/Modal/ModalContent.js +11 -4
  34. package/lib/NavigationBar/resolveItemSelection.js +24 -0
  35. package/lib/OptimizeImage/OptimizeImage.js +127 -0
  36. package/lib/OptimizeImage/index.js +13 -0
  37. package/lib/OptimizeImage/utils/getFallbackUrl.js +18 -0
  38. package/lib/OptimizeImage/utils/getOptimizedUrl.js +32 -0
  39. package/lib/OptimizeImage/utils/hasWebpSupport.js +38 -0
  40. package/lib/OptimizeImage/utils/index.js +31 -0
  41. package/lib/OptimizeImage/utils/isSvgUrl.js +10 -0
  42. package/lib/QuantitySelector/QuantitySelector.js +253 -0
  43. package/lib/QuantitySelector/dictionary.js +33 -0
  44. package/lib/QuantitySelector/index.js +13 -0
  45. package/lib/QuantitySelector/styles.js +40 -0
  46. package/lib/StoryCard/StoryCard.js +244 -0
  47. package/lib/StoryCard/index.js +13 -0
  48. package/lib/TermsAndConditions/ExpandCollapse.js +141 -0
  49. package/lib/TermsAndConditions/TermsAndConditions.js +221 -0
  50. package/lib/TermsAndConditions/dictionary.js +19 -0
  51. package/lib/TermsAndConditions/index.js +15 -0
  52. package/lib/Testimonial/Testimonial.js +226 -0
  53. package/lib/Testimonial/index.js +13 -0
  54. package/lib/Video/ControlBar/ControlBar.js +315 -0
  55. package/lib/Video/ControlBar/Controls/VideoButton/VideoButton.js +91 -0
  56. package/lib/Video/ControlBar/Controls/VideoMenu/VideoMenu.js +186 -0
  57. package/lib/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.js +221 -0
  58. package/lib/Video/ControlBar/Controls/VolumeSlider/VolumeSlider.js +213 -0
  59. package/lib/Video/MiddleControlButton/MiddleControlButton.js +89 -0
  60. package/lib/Video/Video.js +1072 -0
  61. package/lib/Video/index.js +13 -0
  62. package/lib/Video/videoText.js +62 -0
  63. package/lib/WebVideo/WebVideo.js +170 -0
  64. package/lib/WebVideo/index.js +13 -0
  65. package/lib/baseExports.js +0 -12
  66. package/lib/index.js +118 -1
  67. package/lib/shared/VideoSplash/SplashButton/SplashButton.js +102 -0
  68. package/lib/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.js +234 -0
  69. package/lib/shared/VideoSplash/VideoSplash.js +86 -0
  70. package/lib/shared/VideoSplash/helpers.js +38 -0
  71. package/lib/utils/index.js +8 -0
  72. package/lib/utils/useOverlaidPosition.js +246 -0
  73. package/lib-module/Autocomplete/Autocomplete.js +369 -0
  74. package/lib-module/Autocomplete/Loading.js +38 -0
  75. package/lib-module/Autocomplete/Suggestions.js +64 -0
  76. package/lib-module/Autocomplete/constants.js +5 -0
  77. package/lib-module/Autocomplete/dictionary.js +12 -0
  78. package/lib-module/Autocomplete/index.js +2 -0
  79. package/lib-module/BlockQuote/BlockQuote.js +156 -0
  80. package/lib-module/BlockQuote/index.js +2 -0
  81. package/lib-module/Callout/Callout.js +3 -0
  82. package/lib-module/Card/Card.js +158 -0
  83. package/lib-module/Card/CardContent.js +92 -0
  84. package/lib-module/Card/CardFooter.js +80 -0
  85. package/lib-module/Card/index.js +2 -0
  86. package/lib-module/Countdown/Countdown.js +165 -0
  87. package/lib-module/Countdown/Segment.js +94 -0
  88. package/lib-module/Countdown/constants.js +4 -0
  89. package/lib-module/Countdown/dictionary.js +22 -0
  90. package/lib-module/Countdown/index.js +2 -0
  91. package/lib-module/Countdown/types.js +23 -0
  92. package/lib-module/Countdown/useCountdown.js +32 -0
  93. package/lib-module/IconButton/IconButton.js +52 -0
  94. package/lib-module/IconButton/index.js +2 -0
  95. package/lib-module/Listbox/GroupControl.js +80 -0
  96. package/lib-module/Listbox/Listbox.js +142 -0
  97. package/lib-module/Listbox/ListboxGroup.js +106 -0
  98. package/lib-module/Listbox/ListboxItem.js +112 -0
  99. package/lib-module/Listbox/ListboxOverlay.js +68 -0
  100. package/lib-module/Listbox/PressableItem.js +128 -0
  101. package/lib-module/Listbox/index.js +2 -0
  102. package/lib-module/Modal/ModalContent.js +10 -4
  103. package/lib-module/NavigationBar/resolveItemSelection.js +16 -0
  104. package/lib-module/OptimizeImage/OptimizeImage.js +106 -0
  105. package/lib-module/OptimizeImage/index.js +2 -0
  106. package/lib-module/OptimizeImage/utils/getFallbackUrl.js +8 -0
  107. package/lib-module/OptimizeImage/utils/getOptimizedUrl.js +22 -0
  108. package/lib-module/OptimizeImage/utils/hasWebpSupport.js +32 -0
  109. package/lib-module/OptimizeImage/utils/index.js +4 -0
  110. package/lib-module/OptimizeImage/utils/isSvgUrl.js +3 -0
  111. package/lib-module/QuantitySelector/QuantitySelector.js +232 -0
  112. package/lib-module/QuantitySelector/dictionary.js +26 -0
  113. package/lib-module/QuantitySelector/index.js +2 -0
  114. package/lib-module/QuantitySelector/styles.js +21 -0
  115. package/lib-module/StoryCard/StoryCard.js +220 -0
  116. package/lib-module/StoryCard/index.js +2 -0
  117. package/lib-module/TermsAndConditions/ExpandCollapse.js +120 -0
  118. package/lib-module/TermsAndConditions/TermsAndConditions.js +193 -0
  119. package/lib-module/TermsAndConditions/dictionary.js +12 -0
  120. package/lib-module/TermsAndConditions/index.js +1 -0
  121. package/lib-module/Testimonial/Testimonial.js +204 -0
  122. package/lib-module/Testimonial/index.js +2 -0
  123. package/lib-module/Video/ControlBar/ControlBar.js +292 -0
  124. package/lib-module/Video/ControlBar/Controls/VideoButton/VideoButton.js +74 -0
  125. package/lib-module/Video/ControlBar/Controls/VideoMenu/VideoMenu.js +167 -0
  126. package/lib-module/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.js +201 -0
  127. package/lib-module/Video/ControlBar/Controls/VolumeSlider/VolumeSlider.js +193 -0
  128. package/lib-module/Video/MiddleControlButton/MiddleControlButton.js +72 -0
  129. package/lib-module/Video/Video.js +1042 -0
  130. package/lib-module/Video/index.js +2 -0
  131. package/lib-module/Video/videoText.js +55 -0
  132. package/lib-module/WebVideo/WebVideo.js +144 -0
  133. package/lib-module/WebVideo/index.js +2 -0
  134. package/lib-module/baseExports.js +1 -1
  135. package/lib-module/index.js +13 -0
  136. package/lib-module/shared/VideoSplash/SplashButton/SplashButton.js +85 -0
  137. package/lib-module/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.js +216 -0
  138. package/lib-module/shared/VideoSplash/VideoSplash.js +65 -0
  139. package/lib-module/shared/VideoSplash/helpers.js +23 -0
  140. package/lib-module/utils/index.js +2 -1
  141. package/lib-module/utils/useOverlaidPosition.js +235 -0
  142. package/package.json +7 -5
  143. package/src/Autocomplete/Autocomplete.jsx +354 -0
  144. package/src/Autocomplete/Loading.jsx +18 -0
  145. package/src/Autocomplete/Suggestions.jsx +52 -0
  146. package/src/Autocomplete/constants.js +6 -0
  147. package/src/Autocomplete/dictionary.js +12 -0
  148. package/src/Autocomplete/index.js +3 -0
  149. package/src/BlockQuote/BlockQuote.jsx +130 -0
  150. package/src/BlockQuote/index.js +3 -0
  151. package/src/Callout/Callout.jsx +1 -1
  152. package/src/Card/Card.jsx +170 -0
  153. package/src/Card/CardContent.jsx +88 -0
  154. package/src/Card/CardFooter.jsx +70 -0
  155. package/src/Card/index.js +3 -0
  156. package/src/Countdown/Countdown.jsx +144 -0
  157. package/src/Countdown/Segment.jsx +69 -0
  158. package/src/Countdown/constants.js +4 -0
  159. package/src/Countdown/dictionary.js +22 -0
  160. package/src/Countdown/index.js +3 -0
  161. package/src/Countdown/types.js +23 -0
  162. package/src/Countdown/useCountdown.js +34 -0
  163. package/src/IconButton/IconButton.jsx +46 -0
  164. package/src/IconButton/index.js +3 -0
  165. package/src/Listbox/GroupControl.jsx +65 -0
  166. package/src/Listbox/Listbox.jsx +148 -0
  167. package/src/Listbox/ListboxGroup.jsx +110 -0
  168. package/src/Listbox/ListboxItem.jsx +101 -0
  169. package/src/Listbox/ListboxOverlay.jsx +71 -0
  170. package/src/Listbox/PressableItem.jsx +121 -0
  171. package/src/Listbox/index.js +3 -0
  172. package/src/Modal/ModalContent.jsx +8 -4
  173. package/src/NavigationBar/resolveItemSelection.js +11 -0
  174. package/src/OptimizeImage/OptimizeImage.jsx +131 -0
  175. package/src/OptimizeImage/index.js +3 -0
  176. package/src/OptimizeImage/utils/getFallbackUrl.js +9 -0
  177. package/src/OptimizeImage/utils/getOptimizedUrl.js +30 -0
  178. package/src/OptimizeImage/utils/hasWebpSupport.js +33 -0
  179. package/src/OptimizeImage/utils/index.js +5 -0
  180. package/src/OptimizeImage/utils/isSvgUrl.js +3 -0
  181. package/src/QuantitySelector/QuantitySelector.jsx +245 -0
  182. package/src/QuantitySelector/dictionary.js +27 -0
  183. package/src/QuantitySelector/index.js +3 -0
  184. package/src/QuantitySelector/styles.js +83 -0
  185. package/src/StoryCard/StoryCard.jsx +198 -0
  186. package/src/StoryCard/index.js +3 -0
  187. package/src/TermsAndConditions/ExpandCollapse.jsx +106 -0
  188. package/src/TermsAndConditions/TermsAndConditions.jsx +161 -0
  189. package/src/TermsAndConditions/dictionary.js +12 -0
  190. package/src/TermsAndConditions/index.js +1 -0
  191. package/src/Testimonial/Testimonial.jsx +169 -0
  192. package/src/Testimonial/index.js +3 -0
  193. package/src/Video/ControlBar/ControlBar.jsx +261 -0
  194. package/src/Video/ControlBar/Controls/VideoButton/VideoButton.jsx +61 -0
  195. package/src/Video/ControlBar/Controls/VideoMenu/VideoMenu.jsx +159 -0
  196. package/src/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.jsx +185 -0
  197. package/src/Video/ControlBar/Controls/VolumeSlider/VolumeSlider.jsx +184 -0
  198. package/src/Video/MiddleControlButton/MiddleControlButton.jsx +64 -0
  199. package/src/Video/Video.jsx +988 -0
  200. package/src/Video/index.js +3 -0
  201. package/src/Video/videoText.js +58 -0
  202. package/src/WebVideo/WebVideo.jsx +131 -0
  203. package/src/WebVideo/index.js +3 -0
  204. package/src/baseExports.js +0 -2
  205. package/src/index.js +13 -0
  206. package/src/shared/VideoSplash/SplashButton/SplashButton.jsx +64 -0
  207. package/src/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.jsx +128 -0
  208. package/src/shared/VideoSplash/VideoSplash.jsx +50 -0
  209. package/src/shared/VideoSplash/helpers.js +27 -0
  210. package/src/utils/index.js +10 -1
  211. package/src/utils/useOverlaidPosition.js +226 -0
  212. package/types/Autocomplete.d.ts +32 -0
  213. package/types/Card.d.ts +45 -0
  214. package/types/ControlBar.d.ts +59 -0
  215. package/types/MiddleControlButton.d.ts +15 -0
  216. package/types/Video.d.ts +39 -0
  217. package/types/VideoButton.d.ts +14 -0
  218. package/types/VideoMenu.d.ts +16 -0
  219. package/types/VideoProgressBar.d.ts +17 -0
  220. package/types/VolumeSlider.d.ts +20 -0
@@ -0,0 +1,158 @@
1
+ /* eslint-disable react/require-default-props */
2
+ import React, { forwardRef } from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { Card as CardBase, getTokensPropType, paddingProp, responsiveProps, selectSystemProps, StackView, useThemeTokens, variantProp, a11yProps, viewProps } from '@telus-uds/components-base';
5
+ import CardContent from './CardContent';
6
+ import CardFooter from './CardFooter';
7
+ import FullBleedContent, { getFullBleedBorderRadius, useFullBleedContentProps } from '../shared/FullBleedContent'; // Passes React Native-oriented system props through UDS Card
8
+
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ import { jsxs as _jsxs } from "react/jsx-runtime";
11
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
12
+ /**
13
+ * A basic card component, unstyled by default.
14
+ *
15
+ * ## Component API
16
+ *
17
+ * ### With Footer
18
+ *
19
+ * Pass any component or simply a string in the `footer` prop in order to render
20
+ * a card with a footer (which uses the `alternative` background).
21
+ *
22
+ * ### With Full Bleed Content
23
+ *
24
+ * Use `fullBleedContent` prop to add a full bleed style image, video or other content to the
25
+ * card. This prop accepts an object with the following properties:
26
+ * - `alt`: alt tag for an image,
27
+ * - `src`: default image source,
28
+ * - `position`: `none`, `bottom`, `left`, `right` or `top`, depending on where you would like your full bleed image to be placed,
29
+ * - all the props from the `ResponsiveImage` component in case you want that full bleed image to be responsive,
30
+ * - `content`: pass a custom JSX to be used for rendering of the full bleed content (defaults to `ResponsiveImage`
31
+ * receiving the other props).
32
+ *
33
+ * Note that `position` can be responsive, i.e. different for different viewports. A full bleed content with position
34
+ * {xs: 'none', md: 'left'} for example, will have a full bleed content to the left of card content when viewed on desktops
35
+ * viewports, and no content when viewed on mobile viewports.
36
+ *
37
+ * ## Accessibility
38
+ * `Card` component accepts all the standard accessibility props.
39
+ */
40
+
41
+ const Card = /*#__PURE__*/forwardRef(function () {
42
+ let {
43
+ children,
44
+ footer,
45
+ footerPadding,
46
+ fullBleedImage,
47
+ fullBleedContent = fullBleedImage,
48
+ tokens,
49
+ variant,
50
+ ...rest
51
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
52
+ fullBleedContent: {
53
+ position: null
54
+ }
55
+ };
56
+ let ref = arguments.length > 1 ? arguments[1] : undefined;
57
+ const {
58
+ contentStackAlign,
59
+ contentStackDirection,
60
+ fullBleedContentPosition,
61
+ fullBleedContentProps
62
+ } = useFullBleedContentProps(fullBleedContent); // If the card has rounded corners and a full bleed image, we need to apply
63
+ // those corners on the image as well, but partially
64
+
65
+ const {
66
+ borderRadius
67
+ } = useThemeTokens('Card', tokens, variant);
68
+ const hasFooter = Boolean(footer);
69
+ const fullBleedBorderRadius = getFullBleedBorderRadius(borderRadius, fullBleedContentPosition, hasFooter); // Make multiple cards in a row have equal heights with even space between content items
70
+
71
+ const columnFlex = {
72
+ flexGrow: 1,
73
+ flexShrink: 1,
74
+ justifyContent: 'space-between'
75
+ };
76
+ return /*#__PURE__*/_jsx(CardBase, {
77
+ ref: ref,
78
+ variant: { ...variant,
79
+ padding: 'custom'
80
+ },
81
+ tokens: tokens,
82
+ ...selectProps(rest),
83
+ children: /*#__PURE__*/_jsxs(StackView, {
84
+ space: 0,
85
+ tokens: columnFlex,
86
+ children: [/*#__PURE__*/_jsxs(StackView, {
87
+ direction: contentStackDirection,
88
+ tokens: { ...columnFlex,
89
+ alignItems: contentStackAlign
90
+ },
91
+ space: 0,
92
+ children: [/*#__PURE__*/_jsx(CardContent, {
93
+ tokens: tokens,
94
+ variant: variant,
95
+ withFooter: hasFooter,
96
+ children: children
97
+ }), fullBleedContentPosition !== 'none' && /*#__PURE__*/_jsx(FullBleedContent, {
98
+ borderRadius: fullBleedBorderRadius,
99
+ ...fullBleedContentProps
100
+ })]
101
+ }), footer && /*#__PURE__*/_jsx(CardFooter, {
102
+ padding: footerPadding,
103
+ tokens: tokens,
104
+ variant: variant,
105
+ children: footer
106
+ })]
107
+ })
108
+ });
109
+ });
110
+ const positionValues = ['none', 'bottom', 'left', 'right', 'top'];
111
+ const alignValues = ['start', 'end', 'center', 'stretch'];
112
+ const PositionedFullBleedContentPropType = PropTypes.shape({
113
+ position: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(positionValues)).isRequired,
114
+ align: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(alignValues)),
115
+ // eslint-disable-next-line react/forbid-foreign-prop-types
116
+ ...FullBleedContent.propTypes
117
+ });
118
+ Card.displayName = 'Card';
119
+ Card.propTypes = { ...selectedSystemPropTypes,
120
+
121
+ /**
122
+ * Card content.
123
+ */
124
+ children: PropTypes.node,
125
+
126
+ /**
127
+ * Card footer.
128
+ */
129
+ footer: PropTypes.node,
130
+
131
+ /**
132
+ * Custom card footer padding.
133
+ */
134
+ footerPadding: paddingProp.propType,
135
+
136
+ /**
137
+ * Full bleed image to be placed on the card, deprecated in favor of `fullBleedContent`.
138
+ *
139
+ * @deprecated
140
+ */
141
+ fullBleedImage: PositionedFullBleedContentPropType,
142
+
143
+ /**
144
+ * Full bleed content to be placed on the card.
145
+ */
146
+ fullBleedContent: PositionedFullBleedContentPropType,
147
+
148
+ /**
149
+ * Card tokens.
150
+ */
151
+ tokens: getTokensPropType('Card'),
152
+
153
+ /**
154
+ * Card variant.
155
+ */
156
+ variant: variantProp.propType
157
+ };
158
+ export default Card;
@@ -0,0 +1,92 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { getTokensPropType, selectSystemProps, useThemeTokens, useViewport, variantProp } from '@telus-uds/components-base';
4
+ import styled from 'styled-components';
5
+ import { htmlAttrs } from '../utils';
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs]);
8
+ const CardContentContainer = /*#__PURE__*/styled.div.withConfig({
9
+ displayName: "CardContent__CardContentContainer",
10
+ componentId: "components-web__sc-1k2501q-0"
11
+ })(_ref => {
12
+ let {
13
+ backgroundColor,
14
+ borderRadius,
15
+ paddingBottom,
16
+ paddingLeft,
17
+ paddingRight,
18
+ paddingTop,
19
+ withFooter,
20
+ contentAlignItem: alignItem,
21
+ contentFlexGrow: flexGrow,
22
+ contentFlexShrink: flexShrink,
23
+ contentJustifyContent: justifyContent
24
+ } = _ref;
25
+ return {
26
+ backgroundColor,
27
+ // We need to make sure to have sharp corners on the bottom
28
+ // if the card has a footer
29
+ borderBottomLeftRadius: withFooter ? 0 : borderRadius,
30
+ borderBottomRightRadius: withFooter ? 0 : borderRadius,
31
+ borderTopLeftRadius: borderRadius,
32
+ borderTopRightRadius: borderRadius,
33
+ paddingBottom,
34
+ paddingLeft,
35
+ paddingRight,
36
+ paddingTop,
37
+ display: 'flex',
38
+ flexDirection: 'column',
39
+ alignItem,
40
+ flexGrow,
41
+ flexShrink,
42
+ justifyContent
43
+ };
44
+ });
45
+ /**
46
+ * Card content, applying the card tokens as per the theme used.
47
+ */
48
+
49
+ const CardContent = _ref2 => {
50
+ let {
51
+ children,
52
+ flexContent,
53
+ tokens,
54
+ variant,
55
+ withFooter = false,
56
+ ...rest
57
+ } = _ref2;
58
+ const viewport = useViewport();
59
+ const themeTokens = useThemeTokens('Card', tokens, variant, {
60
+ viewport
61
+ });
62
+ return /*#__PURE__*/_jsx(CardContentContainer, { ...themeTokens,
63
+ flexContent: flexContent,
64
+ withFooter: withFooter,
65
+ ...selectProps(rest),
66
+ children: children
67
+ });
68
+ };
69
+
70
+ CardContent.propTypes = { ...selectedSystemPropTypes,
71
+
72
+ /**
73
+ * Card section content.
74
+ */
75
+ children: PropTypes.node,
76
+
77
+ /**
78
+ * Card tokens.
79
+ */
80
+ tokens: getTokensPropType('Card'),
81
+
82
+ /**
83
+ * Card variant.
84
+ */
85
+ variant: variantProp.propType,
86
+
87
+ /**
88
+ * Whether the card has a footer.
89
+ */
90
+ withFooter: PropTypes.bool
91
+ };
92
+ export default CardContent;
@@ -0,0 +1,80 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { getTokensPropType, paddingProp, selectSystemProps, useThemeTokens, useViewport, variantProp } from '@telus-uds/components-base';
4
+ import styled from 'styled-components';
5
+ import { htmlAttrs } from '../utils';
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs]);
8
+ const CardFooterContainer = /*#__PURE__*/styled.div.withConfig({
9
+ displayName: "CardFooter__CardFooterContainer",
10
+ componentId: "components-web__sc-pm6vns-0"
11
+ })(_ref => {
12
+ let {
13
+ backgroundColor,
14
+ borderRadius,
15
+ paddingBottom,
16
+ paddingLeft,
17
+ paddingRight,
18
+ paddingTop
19
+ } = _ref;
20
+ return {
21
+ backgroundColor,
22
+ borderBottomLeftRadius: borderRadius,
23
+ borderBottomRightRadius: borderRadius,
24
+ // @todo circle back to the following non-standard value to
25
+ // see if it can be integrated into the palette
26
+ boxShadow: 'inset 0px 1px 3px rgba(0, 0, 0, 0.05)',
27
+ paddingBottom,
28
+ paddingLeft,
29
+ paddingRight,
30
+ paddingTop
31
+ };
32
+ });
33
+ /**
34
+ * Card footer, applying the tokens as per the theme used.
35
+ */
36
+
37
+ const CardFooter = _ref2 => {
38
+ let {
39
+ children,
40
+ padding,
41
+ tokens,
42
+ variant,
43
+ ...rest
44
+ } = _ref2;
45
+ const viewport = useViewport();
46
+ const themeTokens = useThemeTokens('Card', tokens, { ...variant,
47
+ background: 'alternative'
48
+ }, {
49
+ viewport
50
+ });
51
+ return /*#__PURE__*/_jsx(CardFooterContainer, { ...themeTokens,
52
+ ...padding,
53
+ ...selectProps(rest),
54
+ children: children
55
+ });
56
+ };
57
+
58
+ CardFooter.propTypes = { ...selectedSystemPropTypes,
59
+
60
+ /**
61
+ * Card footer content.
62
+ */
63
+ children: PropTypes.node,
64
+
65
+ /**
66
+ * Card footer padding.
67
+ */
68
+ padding: paddingProp.propType,
69
+
70
+ /**
71
+ * Card tokens.
72
+ */
73
+ tokens: getTokensPropType('Card'),
74
+
75
+ /**
76
+ * Card variant.
77
+ */
78
+ variant: variantProp.propType
79
+ };
80
+ export default CardFooter;
@@ -0,0 +1,2 @@
1
+ import Card from './Card';
2
+ export default Card;
@@ -0,0 +1,165 @@
1
+ /* eslint-disable react/require-default-props */
2
+ import React, { forwardRef } from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { Spacer, StackView, Typography, selectSystemProps, useViewport, useThemeTokens, applyTextStyles } from '@telus-uds/components-base';
5
+ import { viewports } from '@telus-uds/system-constants';
6
+ import styled from 'styled-components'; // Reading these from the RN palette since they will be used to generate
7
+ // the `Typography` tokens
8
+
9
+ import { htmlAttrs, transformGradient } from '../utils';
10
+ import Segment from './Segment';
11
+ import useCountdown from './useCountdown';
12
+ import { countdownVariantPropType, dictionaryContentShape } from './types';
13
+ import { jsx as _jsx } from "react/jsx-runtime";
14
+ import { jsxs as _jsxs } from "react/jsx-runtime";
15
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs]);
16
+ const Container = /*#__PURE__*/styled.div.withConfig({
17
+ displayName: "Countdown__Container",
18
+ componentId: "components-web__sc-18tqcb2-0"
19
+ })(_ref => {
20
+ let {
21
+ variant: {
22
+ feature,
23
+ inverse,
24
+ large
25
+ },
26
+ themeTokens,
27
+ gradient
28
+ } = _ref;
29
+ return { ...(large || feature && {
30
+ display: 'flex',
31
+ flex: 0
32
+ }),
33
+ ...(feature && {
34
+ borderRadius: themeTokens.containerBorderRadius,
35
+ justifyContent: 'center',
36
+ paddingBottom: `${themeTokens.containerPaddingBottomTop}px`,
37
+ paddingLeft: `${themeTokens.containerPaddingLeftRight}px`,
38
+ paddingRight: `${themeTokens.containerPaddingLeftRight}px`,
39
+ paddingTop: `${themeTokens.containerPaddingBottomTop}px`,
40
+ width: 'fit-content'
41
+ }),
42
+ ...(feature && !inverse && {
43
+ background: `linear-gradient(#fff 0 0) padding-box, ${gradient} border-box`,
44
+ border: `${themeTokens.containerInverseBorder}px solid transparent`
45
+ }),
46
+ ...(feature && inverse && {
47
+ border: `${themeTokens.containerInverseBorder}px solid ${themeTokens.inverseBorderColor}`
48
+ })
49
+ };
50
+ });
51
+
52
+ const getLabelTokens = themeTokens => ({
53
+ color: themeTokens.labelBorderColor,
54
+ fontWeight: themeTokens.textTimerFontWeight,
55
+ fontSize: `${themeTokens.labelFontSize}`,
56
+ lineHeight: `${themeTokens.labelLineHeight}`
57
+ });
58
+
59
+ const getMainTextTokens = themeTokens => ({
60
+ color: themeTokens.labelBorderColor,
61
+ fontWeight: themeTokens.textTimerFontWeight,
62
+ fontSize: themeTokens.textFontSize,
63
+ lineHeight: themeTokens.textLineHeight
64
+ });
65
+
66
+ const Countdown = /*#__PURE__*/forwardRef((_ref2, ref) => {
67
+ let {
68
+ copy = 'en',
69
+ targetTime,
70
+ tokens,
71
+ variant = {},
72
+ ...rest
73
+ } = _ref2;
74
+ const [days, hours, minutes, seconds] = useCountdown(targetTime);
75
+ const viewport = useViewport();
76
+ const {
77
+ feature,
78
+ large,
79
+ label,
80
+ noDivider
81
+ } = variant;
82
+
83
+ if (noDivider && !label) {
84
+ throw new Error('`noDivider` variant can only be used with `label` enabled!');
85
+ }
86
+
87
+ const themeTokens = useThemeTokens('Countdown', tokens, variant, {
88
+ viewport
89
+ });
90
+ const segmentFontSize = themeTokens.textFontSize;
91
+ const semanticGradient = themeTokens.containerGradient && transformGradient(themeTokens.containerGradient);
92
+ const mainTextTokens = getMainTextTokens(themeTokens);
93
+ const divider = noDivider === true ?
94
+ /*#__PURE__*/
95
+ // StackView-based subcontainer adds a 1-step space on the each side of the divider
96
+ _jsx(Spacer, {
97
+ direction: "row",
98
+ space: (feature || large) && viewport !== viewports.xs ? 7 : 2
99
+ }) : /*#__PURE__*/_jsx(Typography, {
100
+ tokens: mainTextTokens,
101
+ children: ":"
102
+ });
103
+ const labelTokens = getLabelTokens(themeTokens);
104
+ const commonProps = {
105
+ copy,
106
+ labelTokens,
107
+ numberTokens: mainTextTokens,
108
+ segmentFontSize,
109
+ variant
110
+ };
111
+ return (
112
+ /*#__PURE__*/
113
+ // Making it focusable for accessibility purposes
114
+ _jsx(Container, {
115
+ ref: ref,
116
+ variant: variant,
117
+ ...selectProps(rest),
118
+ tabIndex: 0,
119
+ themeTokens: themeTokens,
120
+ gradient: semanticGradient,
121
+ children: /*#__PURE__*/_jsxs(StackView, {
122
+ direction: "row",
123
+ space: 1,
124
+ children: [/*#__PURE__*/_jsx(Segment, {
125
+ labelKey: "day",
126
+ number: days,
127
+ segmentWidth: String(days).length,
128
+ ...commonProps
129
+ }), divider, /*#__PURE__*/_jsx(Segment, {
130
+ labelKey: "hour",
131
+ number: hours,
132
+ ...commonProps,
133
+ ...applyTextStyles(themeTokens)
134
+ }), divider, /*#__PURE__*/_jsx(Segment, {
135
+ labelKey: "minute",
136
+ number: minutes,
137
+ ...commonProps,
138
+ ...applyTextStyles(themeTokens)
139
+ }), divider, /*#__PURE__*/_jsx(Segment, {
140
+ labelKey: "second",
141
+ number: seconds,
142
+ ...commonProps,
143
+ ...applyTextStyles(themeTokens)
144
+ })]
145
+ })
146
+ })
147
+ );
148
+ });
149
+ Countdown.displayName = 'Countdown';
150
+ Countdown.propTypes = { ...selectedSystemPropTypes,
151
+
152
+ /**
153
+ * Copy language identifier (`'en'` or `'fr'`) or a dictionary instance (an object with
154
+ * the following keys: days, day, hours, hour, minutes, minute, seconds, second)
155
+ */
156
+ copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr']), dictionaryContentShape]),
157
+
158
+ /**
159
+ * An instance of JavaScript `Date` object or a string parseable via `Date.parse()`
160
+ * representing a point in the future to count down to.
161
+ */
162
+ targetTime: PropTypes.instanceOf(Date),
163
+ variant: countdownVariantPropType
164
+ };
165
+ export default Countdown;
@@ -0,0 +1,94 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { StackView, Typography, useCopy } from '@telus-uds/components-base';
4
+ import styled from 'styled-components';
5
+ import dictionary from './dictionary';
6
+ import { countdownVariantPropType, dictionaryContentShape } from './types';
7
+ import { SEGMENT_WIDTH_TO_FONT_SIZE_RATIO } from './constants'; // Pads with zeros on the left if it's a single digit number
8
+
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ import { jsxs as _jsxs } from "react/jsx-runtime";
11
+
12
+ const pad = function (number) {
13
+ let segmentWidth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2;
14
+ return String(number).padStart(segmentWidth, '0');
15
+ };
16
+
17
+ const Container = /*#__PURE__*/styled.div.withConfig({
18
+ displayName: "Segment__Container",
19
+ componentId: "components-web__sc-yrh35y-0"
20
+ })(_ref => {
21
+ let {
22
+ segmentFontSize,
23
+ segmentWidth = 2,
24
+ variant: {
25
+ feature
26
+ }
27
+ } = _ref;
28
+ return {
29
+ justifyContent: 'space-evenly',
30
+ display: 'inline-flex',
31
+ ...(feature && {
32
+ width: `${segmentFontSize * SEGMENT_WIDTH_TO_FONT_SIZE_RATIO * segmentWidth}px`,
33
+ display: 'flex'
34
+ })
35
+ };
36
+ }); // A segment of the countdown string: we need to make sure it
37
+ // keeps its width constant to prevent the whole component from
38
+ // being automatically resized while using variable size fonts
39
+
40
+ const Segment = _ref2 => {
41
+ let {
42
+ copy = 'en',
43
+ segmentFontSize,
44
+ labelKey,
45
+ labelTokens,
46
+ number,
47
+ numberTokens,
48
+ segmentWidth = 2,
49
+ variant = {}
50
+ } = _ref2;
51
+ const getCopy = useCopy({
52
+ dictionary,
53
+ copy
54
+ });
55
+ const {
56
+ label,
57
+ large,
58
+ feature
59
+ } = variant;
60
+ return /*#__PURE__*/_jsx(Container, {
61
+ segmentFontSize: segmentFontSize,
62
+ segmentWidth: segmentWidth,
63
+ variant: variant,
64
+ children: /*#__PURE__*/_jsxs(StackView, {
65
+ direction: large || feature ? 'column' : 'row',
66
+ space: large || feature ? 0 : 1,
67
+ tokens: {
68
+ alignItems: 'center'
69
+ },
70
+ children: [/*#__PURE__*/_jsx(Typography, {
71
+ tokens: numberTokens,
72
+ children: pad(number, segmentWidth)
73
+ }), label && /*#__PURE__*/_jsx(Typography, {
74
+ tokens: labelTokens,
75
+ children: getCopy(number === 1 ? labelKey : `${labelKey}s`)
76
+ })]
77
+ })
78
+ });
79
+ };
80
+
81
+ Segment.propTypes = {
82
+ /**
83
+ * Copy language identifier or a dictionary instance.
84
+ */
85
+ copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr']), dictionaryContentShape]),
86
+ segmentFontSize: PropTypes.number,
87
+ labelKey: PropTypes.oneOf(['day', 'hour', 'minute', 'second']),
88
+ labelTokens: PropTypes.object,
89
+ number: PropTypes.number,
90
+ numberTokens: PropTypes.object,
91
+ segmentWidth: PropTypes.number,
92
+ variant: countdownVariantPropType
93
+ };
94
+ export default Segment;
@@ -0,0 +1,4 @@
1
+ export const DEFAULT_FONT_SIZE = 16;
2
+ export const LARGE_FONT_SIZE = 64;
3
+ export const SEGMENT_WIDTH_TO_FONT_SIZE_RATIO = 0.8;
4
+ export const XS_FONT_SIZE = 28;
@@ -0,0 +1,22 @@
1
+ export default {
2
+ en: {
3
+ days: 'Days',
4
+ day: 'Day',
5
+ hours: 'Hours',
6
+ hour: 'Hour',
7
+ minutes: 'Minutes',
8
+ minute: 'Minute',
9
+ seconds: 'Seconds',
10
+ second: 'Second'
11
+ },
12
+ fr: {
13
+ days: 'Jours',
14
+ day: 'Jour',
15
+ hours: 'Heures',
16
+ hour: 'Heure',
17
+ minutes: 'Minutes',
18
+ minute: 'Minute',
19
+ seconds: 'Secondes',
20
+ second: 'Seconde'
21
+ }
22
+ };
@@ -0,0 +1,2 @@
1
+ import Countdown from './Countdown';
2
+ export default Countdown;
@@ -0,0 +1,23 @@
1
+ import PropTypes from 'prop-types';
2
+ export const countdownVariantPropType = PropTypes.shape({
3
+ feature: PropTypes.bool,
4
+ inverse: PropTypes.bool,
5
+ label: PropTypes.bool,
6
+ large: PropTypes.bool,
7
+ noDivider: PropTypes.bool
8
+ }); // If a language dictionary entry is provided, it must contain every key
9
+
10
+ export const dictionaryContentShape = PropTypes.shape({
11
+ days: PropTypes.string.isRequired,
12
+ day: PropTypes.string.isRequired,
13
+ hours: PropTypes.string.isRequired,
14
+ hour: PropTypes.string.isRequired,
15
+ minutes: PropTypes.string.isRequired,
16
+ minute: PropTypes.string.isRequired,
17
+ seconds: PropTypes.string.isRequired,
18
+ second: PropTypes.string.isRequired
19
+ });
20
+ export default {
21
+ countdownVariantPropType,
22
+ dictionaryContentShape
23
+ };
@@ -0,0 +1,32 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ const getTimeCounts = countdown => {
4
+ if (countdown <= 0) {
5
+ return [0, 0, 0, 0];
6
+ }
7
+
8
+ const days = Math.floor(countdown / (1000 * 60 * 60 * 24));
9
+ const hours = Math.floor(countdown % (1000 * 60 * 60 * 24) / (1000 * 60 * 60));
10
+ const minutes = Math.floor(countdown % (1000 * 60 * 60) / (1000 * 60));
11
+ const seconds = Math.floor(countdown % (1000 * 60) / 1000);
12
+ return [days, hours, minutes, seconds];
13
+ };
14
+
15
+ const useCountdown = targetTime => {
16
+ const countdownTime = new Date(targetTime).getTime();
17
+
18
+ if (!countdownTime) {
19
+ throw new Error('Invalid target time is provided!');
20
+ }
21
+
22
+ const [countdown, setCountdown] = useState(countdownTime - new Date().getTime());
23
+ useEffect(() => {
24
+ const interval = setInterval(() => {
25
+ setCountdown(countdownTime - new Date().getTime());
26
+ }, 1000);
27
+ return () => clearInterval(interval);
28
+ }, [countdownTime]);
29
+ return getTimeCounts(countdown);
30
+ };
31
+
32
+ export default useCountdown;