@telus-uds/components-web 1.8.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 (179) hide show
  1. package/CHANGELOG.md +27 -2
  2. package/lib/Autocomplete/Autocomplete.js +393 -0
  3. package/lib/Autocomplete/Loading.js +51 -0
  4. package/lib/Autocomplete/Suggestions.js +81 -0
  5. package/lib/Autocomplete/constants.js +19 -0
  6. package/lib/Autocomplete/dictionary.js +19 -0
  7. package/lib/Autocomplete/index.js +13 -0
  8. package/lib/Callout/Callout.js +3 -0
  9. package/lib/Card/Card.js +180 -0
  10. package/lib/Card/CardContent.js +110 -0
  11. package/lib/Card/CardFooter.js +98 -0
  12. package/lib/Card/index.js +13 -0
  13. package/lib/Countdown/Countdown.js +189 -0
  14. package/lib/Countdown/Segment.js +111 -0
  15. package/lib/Countdown/constants.js +14 -0
  16. package/lib/Countdown/dictionary.js +29 -0
  17. package/lib/Countdown/index.js +13 -0
  18. package/lib/Countdown/types.js +39 -0
  19. package/lib/Countdown/useCountdown.js +40 -0
  20. package/lib/Modal/ModalContent.js +11 -4
  21. package/lib/OptimizeImage/OptimizeImage.js +127 -0
  22. package/lib/OptimizeImage/index.js +13 -0
  23. package/lib/OptimizeImage/utils/getFallbackUrl.js +18 -0
  24. package/lib/OptimizeImage/utils/getOptimizedUrl.js +32 -0
  25. package/lib/OptimizeImage/utils/hasWebpSupport.js +38 -0
  26. package/lib/OptimizeImage/utils/index.js +31 -0
  27. package/lib/OptimizeImage/utils/isSvgUrl.js +10 -0
  28. package/lib/QuantitySelector/QuantitySelector.js +253 -0
  29. package/lib/QuantitySelector/dictionary.js +33 -0
  30. package/lib/QuantitySelector/index.js +13 -0
  31. package/lib/QuantitySelector/styles.js +40 -0
  32. package/lib/StoryCard/StoryCard.js +244 -0
  33. package/lib/StoryCard/index.js +13 -0
  34. package/lib/TermsAndConditions/ExpandCollapse.js +141 -0
  35. package/lib/TermsAndConditions/TermsAndConditions.js +221 -0
  36. package/lib/TermsAndConditions/dictionary.js +19 -0
  37. package/lib/TermsAndConditions/index.js +15 -0
  38. package/lib/Testimonial/Testimonial.js +226 -0
  39. package/lib/Testimonial/index.js +13 -0
  40. package/lib/Video/ControlBar/ControlBar.js +315 -0
  41. package/lib/Video/ControlBar/Controls/VideoButton/VideoButton.js +91 -0
  42. package/lib/Video/ControlBar/Controls/VideoMenu/VideoMenu.js +186 -0
  43. package/lib/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.js +221 -0
  44. package/lib/Video/ControlBar/Controls/VolumeSlider/VolumeSlider.js +213 -0
  45. package/lib/Video/MiddleControlButton/MiddleControlButton.js +89 -0
  46. package/lib/Video/Video.js +1072 -0
  47. package/lib/Video/index.js +13 -0
  48. package/lib/Video/videoText.js +62 -0
  49. package/lib/WebVideo/WebVideo.js +170 -0
  50. package/lib/WebVideo/index.js +13 -0
  51. package/lib/baseExports.js +0 -6
  52. package/lib/index.js +91 -1
  53. package/lib/shared/VideoSplash/SplashButton/SplashButton.js +102 -0
  54. package/lib/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.js +234 -0
  55. package/lib/shared/VideoSplash/VideoSplash.js +86 -0
  56. package/lib/shared/VideoSplash/helpers.js +38 -0
  57. package/lib/utils/index.js +8 -0
  58. package/lib-module/Autocomplete/Autocomplete.js +369 -0
  59. package/lib-module/Autocomplete/Loading.js +38 -0
  60. package/lib-module/Autocomplete/Suggestions.js +64 -0
  61. package/lib-module/Autocomplete/constants.js +5 -0
  62. package/lib-module/Autocomplete/dictionary.js +12 -0
  63. package/lib-module/Autocomplete/index.js +2 -0
  64. package/lib-module/Callout/Callout.js +3 -0
  65. package/lib-module/Card/Card.js +158 -0
  66. package/lib-module/Card/CardContent.js +92 -0
  67. package/lib-module/Card/CardFooter.js +80 -0
  68. package/lib-module/Card/index.js +2 -0
  69. package/lib-module/Countdown/Countdown.js +165 -0
  70. package/lib-module/Countdown/Segment.js +94 -0
  71. package/lib-module/Countdown/constants.js +4 -0
  72. package/lib-module/Countdown/dictionary.js +22 -0
  73. package/lib-module/Countdown/index.js +2 -0
  74. package/lib-module/Countdown/types.js +23 -0
  75. package/lib-module/Countdown/useCountdown.js +32 -0
  76. package/lib-module/Modal/ModalContent.js +10 -4
  77. package/lib-module/OptimizeImage/OptimizeImage.js +106 -0
  78. package/lib-module/OptimizeImage/index.js +2 -0
  79. package/lib-module/OptimizeImage/utils/getFallbackUrl.js +8 -0
  80. package/lib-module/OptimizeImage/utils/getOptimizedUrl.js +22 -0
  81. package/lib-module/OptimizeImage/utils/hasWebpSupport.js +32 -0
  82. package/lib-module/OptimizeImage/utils/index.js +4 -0
  83. package/lib-module/OptimizeImage/utils/isSvgUrl.js +3 -0
  84. package/lib-module/QuantitySelector/QuantitySelector.js +232 -0
  85. package/lib-module/QuantitySelector/dictionary.js +26 -0
  86. package/lib-module/QuantitySelector/index.js +2 -0
  87. package/lib-module/QuantitySelector/styles.js +21 -0
  88. package/lib-module/StoryCard/StoryCard.js +220 -0
  89. package/lib-module/StoryCard/index.js +2 -0
  90. package/lib-module/TermsAndConditions/ExpandCollapse.js +120 -0
  91. package/lib-module/TermsAndConditions/TermsAndConditions.js +193 -0
  92. package/lib-module/TermsAndConditions/dictionary.js +12 -0
  93. package/lib-module/TermsAndConditions/index.js +1 -0
  94. package/lib-module/Testimonial/Testimonial.js +204 -0
  95. package/lib-module/Testimonial/index.js +2 -0
  96. package/lib-module/Video/ControlBar/ControlBar.js +292 -0
  97. package/lib-module/Video/ControlBar/Controls/VideoButton/VideoButton.js +74 -0
  98. package/lib-module/Video/ControlBar/Controls/VideoMenu/VideoMenu.js +167 -0
  99. package/lib-module/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.js +201 -0
  100. package/lib-module/Video/ControlBar/Controls/VolumeSlider/VolumeSlider.js +193 -0
  101. package/lib-module/Video/MiddleControlButton/MiddleControlButton.js +72 -0
  102. package/lib-module/Video/Video.js +1042 -0
  103. package/lib-module/Video/index.js +2 -0
  104. package/lib-module/Video/videoText.js +55 -0
  105. package/lib-module/WebVideo/WebVideo.js +144 -0
  106. package/lib-module/WebVideo/index.js +2 -0
  107. package/lib-module/baseExports.js +1 -1
  108. package/lib-module/index.js +10 -0
  109. package/lib-module/shared/VideoSplash/SplashButton/SplashButton.js +85 -0
  110. package/lib-module/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.js +216 -0
  111. package/lib-module/shared/VideoSplash/VideoSplash.js +65 -0
  112. package/lib-module/shared/VideoSplash/helpers.js +23 -0
  113. package/lib-module/utils/index.js +2 -1
  114. package/package.json +7 -5
  115. package/src/Autocomplete/Autocomplete.jsx +354 -0
  116. package/src/Autocomplete/Loading.jsx +18 -0
  117. package/src/Autocomplete/Suggestions.jsx +52 -0
  118. package/src/Autocomplete/constants.js +6 -0
  119. package/src/Autocomplete/dictionary.js +12 -0
  120. package/src/Autocomplete/index.js +3 -0
  121. package/src/Callout/Callout.jsx +1 -1
  122. package/src/Card/Card.jsx +170 -0
  123. package/src/Card/CardContent.jsx +88 -0
  124. package/src/Card/CardFooter.jsx +70 -0
  125. package/src/Card/index.js +3 -0
  126. package/src/Countdown/Countdown.jsx +144 -0
  127. package/src/Countdown/Segment.jsx +69 -0
  128. package/src/Countdown/constants.js +4 -0
  129. package/src/Countdown/dictionary.js +22 -0
  130. package/src/Countdown/index.js +3 -0
  131. package/src/Countdown/types.js +23 -0
  132. package/src/Countdown/useCountdown.js +34 -0
  133. package/src/Modal/ModalContent.jsx +8 -4
  134. package/src/OptimizeImage/OptimizeImage.jsx +131 -0
  135. package/src/OptimizeImage/index.js +3 -0
  136. package/src/OptimizeImage/utils/getFallbackUrl.js +9 -0
  137. package/src/OptimizeImage/utils/getOptimizedUrl.js +30 -0
  138. package/src/OptimizeImage/utils/hasWebpSupport.js +33 -0
  139. package/src/OptimizeImage/utils/index.js +5 -0
  140. package/src/OptimizeImage/utils/isSvgUrl.js +3 -0
  141. package/src/QuantitySelector/QuantitySelector.jsx +245 -0
  142. package/src/QuantitySelector/dictionary.js +27 -0
  143. package/src/QuantitySelector/index.js +3 -0
  144. package/src/QuantitySelector/styles.js +83 -0
  145. package/src/StoryCard/StoryCard.jsx +198 -0
  146. package/src/StoryCard/index.js +3 -0
  147. package/src/TermsAndConditions/ExpandCollapse.jsx +106 -0
  148. package/src/TermsAndConditions/TermsAndConditions.jsx +161 -0
  149. package/src/TermsAndConditions/dictionary.js +12 -0
  150. package/src/TermsAndConditions/index.js +1 -0
  151. package/src/Testimonial/Testimonial.jsx +169 -0
  152. package/src/Testimonial/index.js +3 -0
  153. package/src/Video/ControlBar/ControlBar.jsx +261 -0
  154. package/src/Video/ControlBar/Controls/VideoButton/VideoButton.jsx +61 -0
  155. package/src/Video/ControlBar/Controls/VideoMenu/VideoMenu.jsx +159 -0
  156. package/src/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.jsx +185 -0
  157. package/src/Video/ControlBar/Controls/VolumeSlider/VolumeSlider.jsx +184 -0
  158. package/src/Video/MiddleControlButton/MiddleControlButton.jsx +64 -0
  159. package/src/Video/Video.jsx +988 -0
  160. package/src/Video/index.js +3 -0
  161. package/src/Video/videoText.js +58 -0
  162. package/src/WebVideo/WebVideo.jsx +131 -0
  163. package/src/WebVideo/index.js +3 -0
  164. package/src/baseExports.js +0 -1
  165. package/src/index.js +10 -0
  166. package/src/shared/VideoSplash/SplashButton/SplashButton.jsx +64 -0
  167. package/src/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.jsx +128 -0
  168. package/src/shared/VideoSplash/VideoSplash.jsx +50 -0
  169. package/src/shared/VideoSplash/helpers.js +27 -0
  170. package/src/utils/index.js +10 -1
  171. package/types/Autocomplete.d.ts +32 -0
  172. package/types/Card.d.ts +45 -0
  173. package/types/ControlBar.d.ts +59 -0
  174. package/types/MiddleControlButton.d.ts +15 -0
  175. package/types/Video.d.ts +39 -0
  176. package/types/VideoButton.d.ts +14 -0
  177. package/types/VideoMenu.d.ts +16 -0
  178. package/types/VideoProgressBar.d.ts +17 -0
  179. package/types/VolumeSlider.d.ts +20 -0
@@ -0,0 +1,3 @@
1
+ import Video from './Video'
2
+
3
+ export default Video
@@ -0,0 +1,58 @@
1
+ const videoText = {
2
+ en: {
3
+ videoPlayer:
4
+ 'Press the space bar or K to toggle play and pause. Use the left and right arrow keys or the comma and period keys to scrub through the video. Use the up and down arrow keys, the dash and equal keys, or the add and subtract number pad keys to increase and decrease volume. Press M to toggle mute. Press F to toggle fullscreen. Press escape to exit instructions and return to video.',
5
+ videoSelected: 'Video selected. Press Q to listen to controls.',
6
+ videoSelectedSimple: 'Video selected. Press the space bar or K to toggle play and pause.',
7
+ mute: 'Mute',
8
+ unmute: 'Unmute',
9
+ watch: 'Watch the video',
10
+ replay: 'Replay the video',
11
+ itemSelected: 'This is the currently selected option.',
12
+ itemUnselected: 'Select to switch to this option.',
13
+ captionsToggle: 'Select captions',
14
+ captionsDialogue: 'Captions',
15
+ captionsNone: 'None',
16
+ qualityToggle: 'Change video quality',
17
+ qualityDialogue: 'Quality',
18
+ fullScreenToggle: 'Toggle fullscreen',
19
+ minute: 'minute',
20
+ minutes: 'minutes',
21
+ second: 'second',
22
+ seconds: 'seconds',
23
+ ariaLabel: 'Play video. Video length is {minutes} and {seconds}.',
24
+ volumeSliderLabel: 'Adjust the volume',
25
+ videoProgressBarLabel: 'Progress bar',
26
+ en: 'English',
27
+ fr: 'French'
28
+ },
29
+ fr: {
30
+ videoPlayer:
31
+ 'Appuyer sur K pour basculer entre lecture et pause. Utiliser les flèches gauche et droite ou les touches virgule et point pour reculer ou faire une avance rapide dans la vidéo. Utiliser les flèches ascendante et descendante, les touches tiret et égal ou les touches plus et moins du clavier numérique pour contrôler le volume. Appuyer sur la touche M pour désactiver le son. Appuyer sur F pour basculer en mode plein écran. Appuyer sur la touche d’échappement pour quitter les instructions et retourner à la vidéo.',
32
+ videoSelected: 'Vidéo sélectionnée. Appuyer sur Q pour écouter les contrôles',
33
+ videoSelectedSimple: 'Vidéo sélectionnée. Appuyer sur K pour basculer entre lecture et pause.',
34
+ mute: 'Désactiver le son',
35
+ unmute: 'Activer le son',
36
+ watch: 'Voir la vidéo',
37
+ replay: 'Relire la vidéo',
38
+ itemSelected: 'Cette option est déjà sélectionnée.',
39
+ itemUnselected: 'Sélectionner pour basculer à cette option.',
40
+ captionsToggle: 'Sélectionner les sous-titres',
41
+ captionsDialogue: 'Sous-titres',
42
+ captionsNone: 'Aucun',
43
+ qualityToggle: 'Modifier la qualité de la vidéo',
44
+ qualityDialogue: 'Qualité',
45
+ fullScreenToggle: 'Basculer en mode plein écran',
46
+ minute: 'minute',
47
+ minutes: 'minutes',
48
+ second: 'seconde',
49
+ seconds: 'secondes',
50
+ ariaLabel: 'Lire la vidéo. La durée de la vidéo est de {minutes} et {seconds}.',
51
+ volumeSliderLabel: 'Réglez le volume',
52
+ videoProgressBarLabel: 'Barre de progression',
53
+ en: 'Anglais',
54
+ fr: 'Français'
55
+ }
56
+ }
57
+
58
+ export default videoText
@@ -0,0 +1,131 @@
1
+ import React, { useState } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import styled from 'styled-components'
4
+ import YouTube from 'react-youtube'
5
+ import { selectSystemProps } from '@telus-uds/components-base'
6
+ import VideoSplash from '../shared/VideoSplash/VideoSplash'
7
+ import { htmlAttrs } from '../utils'
8
+
9
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
10
+
11
+ const StyledPlayerContainer = styled.div({
12
+ width: '100%',
13
+ minWidth: 288,
14
+ outline: 'none'
15
+ })
16
+
17
+ const StyledYoutubePlayer = styled(YouTube)({
18
+ position: 'absolute',
19
+ top: 0,
20
+ left: 0,
21
+ bottom: 0,
22
+ right: 0
23
+ })
24
+
25
+ const aspectRatios = {
26
+ '16:9': { paddingTop: '56.25%' },
27
+ '4:3': { paddingTop: '75%' },
28
+ '1:1': { paddingTop: '100%' }
29
+ }
30
+
31
+ const AspectLimiter = styled.div((props) => ({
32
+ ...aspectRatios[props.aspectRatio],
33
+ position: 'relative'
34
+ }))
35
+
36
+ const WebVideo = ({
37
+ videoId,
38
+ aspectRatio = '16:9',
39
+ posterSrc,
40
+ defaultVolume = 1,
41
+ beginMuted = false,
42
+ videoLength,
43
+ copy,
44
+ onStart = () => {},
45
+ ...rest
46
+ }) => {
47
+ const [started, setStarted] = useState(false)
48
+
49
+ const initializeYoutubePlayer = (event) => {
50
+ onStart()
51
+
52
+ if (beginMuted) {
53
+ event.target.mute()
54
+ }
55
+
56
+ event.target.setVolume(defaultVolume)
57
+ event.target.playVideo() // This plays the video after passing the splash screen on mobile.
58
+ }
59
+
60
+ return (
61
+ <StyledPlayerContainer data-testid="web-video-container" {...selectProps(rest)}>
62
+ <AspectLimiter aspectRatio={aspectRatio}>
63
+ {started ? (
64
+ <StyledYoutubePlayer
65
+ videoId={videoId}
66
+ opts={{
67
+ width: '100%',
68
+ height: '100%',
69
+ playerVars: {
70
+ autoplay: 1,
71
+ modestbranding: 1,
72
+ playsinline: 1,
73
+ rel: 0
74
+ }
75
+ }}
76
+ onReady={initializeYoutubePlayer}
77
+ />
78
+ ) : (
79
+ <VideoSplash
80
+ poster={posterSrc || `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`}
81
+ videoLength={videoLength}
82
+ copy={copy}
83
+ onClick={() => {
84
+ setStarted(true)
85
+ }}
86
+ />
87
+ )}
88
+ </AspectLimiter>
89
+ </StyledPlayerContainer>
90
+ )
91
+ }
92
+
93
+ export const VideoProps = {
94
+ ...selectedSystemPropTypes,
95
+ /**
96
+ * The video's ID, typically available via the video's URL.
97
+ */
98
+ videoId: PropTypes.string.isRequired,
99
+ /**
100
+ * The aspect ratio of the player.
101
+ */
102
+ aspectRatio: PropTypes.oneOf(['16:9', '4:3', '1:1']),
103
+ /**
104
+ * A path of the image that will be displayed on the video's splash screen. If this is undefined, it will pull an image from the defined web video if available.
105
+ */
106
+ posterSrc: PropTypes.string,
107
+ /**
108
+ * The video's default volume, defined from 1 to 100. Please use the `beginMuted` prop to have the video start silenced.
109
+ */
110
+ defaultVolume: PropTypes.number,
111
+ /**
112
+ * Defines if the video should start muted.
113
+ */
114
+ beginMuted: PropTypes.bool,
115
+ /**
116
+ * The video's length, which will be displayed on the splash screen. This is defined in seconds.
117
+ */
118
+ videoLength: PropTypes.number.isRequired,
119
+ /**
120
+ * The splash screen UI's language as an ISO language code. It currently supports English and French.
121
+ */
122
+ copy: PropTypes.oneOf(['en', 'fr']).isRequired,
123
+ /**
124
+ * A function to be run when the play button is pressed on the video splash screen and the video is ready to play.
125
+ */
126
+ onStart: PropTypes.func
127
+ }
128
+
129
+ WebVideo.propTypes = VideoProps
130
+
131
+ export default WebVideo
@@ -0,0 +1,3 @@
1
+ import WebVideo from './WebVideo'
2
+
3
+ export default WebVideo
@@ -17,7 +17,6 @@ export {
17
17
  ButtonGroup,
18
18
  ButtonLink,
19
19
  Carousel,
20
- Card,
21
20
  CarouselTabs,
22
21
  Checkbox,
23
22
  CheckboxGroup,
package/src/index.js CHANGED
@@ -1,9 +1,11 @@
1
+ export { default as Autocomplete } from './Autocomplete'
1
2
  export { default as Badge } from './Badge'
2
3
  export { default as Modal } from './Modal'
3
4
  export { default as OrderedList } from './OrderedList'
4
5
  export { default as PreviewCard } from './PreviewCard'
5
6
  export { default as ResponsiveImage } from './ResponsiveImage'
6
7
  export { default as Ribbon } from './Ribbon'
8
+ export { default as Countdown } from './Countdown'
7
9
  export { default as DatePicker } from './DatePicker'
8
10
  export { default as Paragraph } from './Paragraph'
9
11
  export { default as Span } from './Span'
@@ -11,15 +13,23 @@ export { default as ExpandCollapseMini } from './ExpandCollapseMini'
11
13
  export { default as Callout } from './Callout'
12
14
  export { default as PriceLockup } from './PriceLockup'
13
15
  export { default as Footnote } from './Footnote'
16
+ export { default as QuantitySelector } from './QuantitySelector'
14
17
  export { default as IconButton } from './IconButton'
15
18
  export { transformGradient } from './utils'
16
19
  export { default as Breadcrumbs } from './Breadcrumbs'
17
20
  export { default as BlockQuote } from './BlockQuote'
21
+ export { default as OptimizeImage } from './OptimizeImage'
22
+ export { default as Testimonial } from './Testimonial'
18
23
  export { default as Toast } from './Toast'
19
24
  export { default as Table } from './Table'
20
25
  export { default as Image } from './Image'
26
+ export { default as WebVideo } from './WebVideo'
21
27
  export { default as WaffleGrid } from './WaffleGrid'
22
28
  export { default as Spinner } from './Spinner'
23
29
  export { default as Listbox } from './Listbox'
30
+ export { default as Video } from './Video'
31
+ export { default as StoryCard } from './StoryCard'
32
+ export { default as Card } from './Card'
33
+ export { default as TermsAndConditions } from './TermsAndConditions'
24
34
 
25
35
  export * from './baseExports'
@@ -0,0 +1,64 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import styled from 'styled-components'
4
+ import { useThemeTokens } from '@telus-uds/components-base'
5
+ import { getAriaLabel, getTimestamp } from '../helpers'
6
+
7
+ const ButtonContainer = styled.button({
8
+ background: 'none',
9
+ border: 0,
10
+ padding: 0,
11
+ position: 'absolute',
12
+ width: '100%',
13
+ height: '100%',
14
+ display: 'flex',
15
+ justifyContent: 'center',
16
+ alignItems: 'center',
17
+ cursor: 'pointer'
18
+ })
19
+
20
+ const ButtonContent = styled.div({
21
+ display: 'flex',
22
+ justifyContent: 'center',
23
+ alignItems: 'center',
24
+ width: 64,
25
+ height: 64,
26
+ background: ({ buttonContentBackground }) => buttonContentBackground ?? 'none',
27
+ borderRadius: '100%',
28
+ transition: 'background 0.2s ease-in-out',
29
+ [`${ButtonContainer}:hover &`]: {
30
+ background: ({ buttonContentChildrenBackground }) => buttonContentChildrenBackground
31
+ }
32
+ })
33
+
34
+ const SplashButton = ({ copy, tokens, variant, videoLength }) => {
35
+ const { buttonContentChildrenBackground } = useThemeTokens('SplashButton', tokens, variant, {
36
+ hover: true
37
+ })
38
+ const {
39
+ playIcon: PlayIcon,
40
+ playIconColor,
41
+ ...themeTokens
42
+ } = useThemeTokens('SplashButton', tokens, variant)
43
+ const ariaLabel = getAriaLabel(getTimestamp(videoLength), copy)
44
+
45
+ return (
46
+ <ButtonContainer aria-label={ariaLabel}>
47
+ <ButtonContent
48
+ {...themeTokens}
49
+ buttonContentChildrenBackground={buttonContentChildrenBackground}
50
+ >
51
+ <PlayIcon size={27} color={playIconColor} />
52
+ </ButtonContent>
53
+ </ButtonContainer>
54
+ )
55
+ }
56
+
57
+ SplashButton.propTypes = {
58
+ videoLength: PropTypes.number,
59
+ tokens: PropTypes.object,
60
+ variant: PropTypes.object,
61
+ copy: PropTypes.oneOf(['en', 'fr'])
62
+ }
63
+
64
+ export default SplashButton
@@ -0,0 +1,128 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import styled from 'styled-components'
4
+
5
+ import { Typography, useThemeTokens } from '@telus-uds/components-base'
6
+ import { getAriaLabel, getTimestamp } from '../helpers'
7
+
8
+ const ButtonContainer = styled.button({
9
+ background: 'none',
10
+ border: 0,
11
+ position: 'absolute',
12
+ width: '100%',
13
+ height: '100%',
14
+ padding: 0,
15
+ cursor: 'pointer'
16
+ })
17
+
18
+ const ButtonContent = styled.div({
19
+ background: ({ buttonBackground }) => buttonBackground,
20
+ border: ({ buttonBorderColor }) => `1px solid ${buttonBorderColor}`,
21
+ borderRadius: ({ buttonRadius }) => `${buttonRadius}px`,
22
+ position: 'absolute',
23
+ left: ({ buttonLeftPosition }) => `${buttonLeftPosition}px`,
24
+ bottom: ({ buttonBottomPosition }) => `${buttonBottomPosition}px`,
25
+ boxSizing: 'border-box',
26
+ display: 'flex',
27
+ alignItems: 'center',
28
+ minHeight: ({ buttonMinHeight }) => `${buttonMinHeight}px`,
29
+ paddingRight: ({ buttonPaddingLeft }) => `${buttonPaddingLeft}px`,
30
+ paddingLeft: ({ buttonPaddingRight }) => `${buttonPaddingRight}px`,
31
+ transition: 'background 0.2s ease-in-out',
32
+
33
+ [`${ButtonContainer}:hover &`]: {
34
+ background: ({ buttonContentChildrenBackground }) => buttonContentChildrenBackground
35
+ }
36
+ })
37
+
38
+ const PlayIconContainer = styled.div({
39
+ display: 'flex',
40
+ justifyContent: 'center',
41
+ alignItems: 'center',
42
+ width: 32,
43
+ height: 32,
44
+ background: ({ playIconContainerBackground }) => playIconContainerBackground ?? 'none',
45
+ borderRadius: '100%',
46
+ transition: 'background 0.2s ease-in-out'
47
+ })
48
+
49
+ const DetailsContainer = styled.div({
50
+ display: 'flex',
51
+ flexDirection: 'column',
52
+ alignItems: 'flex-start',
53
+ paddingLeft: ({ detailsContainerPadding }) => `${detailsContainerPadding}px`
54
+ })
55
+
56
+ const selectPlayIconContainerTokens = ({ playIconContainerBackground }) => ({
57
+ playIconContainerBackground
58
+ })
59
+ const selectDetailsContainerTokens = ({ detailsContainerPadding }) => ({ detailsContainerPadding })
60
+ const selectButtonContentTokens = ({
61
+ buttonBackground,
62
+ buttonBorderColor,
63
+ buttonRadius,
64
+ buttonLeftPosition,
65
+ buttonBottomPosition,
66
+ buttonMinHeight,
67
+ buttonPaddingLeft,
68
+ buttonPaddingRight
69
+ }) => ({
70
+ buttonBackground,
71
+ buttonBorderColor,
72
+ buttonRadius,
73
+ buttonLeftPosition,
74
+ buttonBottomPosition,
75
+ buttonMinHeight,
76
+ buttonPaddingLeft,
77
+ buttonPaddingRight
78
+ })
79
+
80
+ const SplashButtonWithDetails = ({ label, tokens, variant, copy, videoLength }) => {
81
+ const { buttonContentChildrenBackground } = useThemeTokens(
82
+ 'SplashButtonWithDetails',
83
+ tokens,
84
+ variant,
85
+ { hover: true }
86
+ )
87
+ const {
88
+ playIcon: PlayIcon,
89
+ playIconColor,
90
+ ...themeTokens
91
+ } = useThemeTokens('SplashButtonWithDetails', tokens, variant)
92
+ const mappedVideoLength = getTimestamp(videoLength, copy)
93
+ const ariaLabel = getAriaLabel(mappedVideoLength, copy)
94
+
95
+ return (
96
+ <ButtonContainer aria-label={ariaLabel}>
97
+ <ButtonContent
98
+ {...selectButtonContentTokens(themeTokens)}
99
+ buttonContentChildrenBackground={buttonContentChildrenBackground}
100
+ >
101
+ <PlayIconContainer {...selectPlayIconContainerTokens(themeTokens)}>
102
+ <PlayIcon size={13} color={playIconColor} />
103
+ </PlayIconContainer>
104
+ <DetailsContainer {...selectDetailsContainerTokens(themeTokens)}>
105
+ <Typography variant={{ bold: true }}>{label}</Typography>
106
+ <Typography
107
+ variant={{
108
+ colour: 'secondary' /* TODO: this is not the same color as in designs */,
109
+ size: 'micro'
110
+ }}
111
+ >
112
+ {mappedVideoLength.timestamp}
113
+ </Typography>
114
+ </DetailsContainer>
115
+ </ButtonContent>
116
+ </ButtonContainer>
117
+ )
118
+ }
119
+
120
+ SplashButtonWithDetails.propTypes = {
121
+ label: PropTypes.string,
122
+ tokens: PropTypes.object,
123
+ variant: PropTypes.object,
124
+ videoLength: PropTypes.number,
125
+ copy: PropTypes.oneOf(['en', 'fr'])
126
+ }
127
+
128
+ export default SplashButtonWithDetails
@@ -0,0 +1,50 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import styled from 'styled-components'
4
+ import { selectSystemProps, useViewport } from '@telus-uds/components-base'
5
+ import { viewports } from '@telus-uds/system-constants'
6
+ import SplashButton from './SplashButton/SplashButton'
7
+ import SplashButtonWithDetails from './SplashButtonWithDetails/SplashButtonWithDetails'
8
+ import videoText from '../../Video/videoText'
9
+ import { htmlAttrs } from '../../utils'
10
+
11
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
12
+
13
+ const SplashBackground = styled.div(({ videoPoster }) => ({
14
+ backgroundImage: `url(${videoPoster})`,
15
+ backgroundSize: 'cover',
16
+ backgroundPosition: 'center',
17
+ position: 'absolute',
18
+ top: 0,
19
+ width: '100%',
20
+ height: '100%', // fixes vertical alignment on IE 11
21
+ cursor: 'pointer'
22
+ }))
23
+
24
+ const VideoSplash = ({ poster, videoLength, simpleMode, copy = 'en', onClick, ...rest }) => {
25
+ const viewport = useViewport()
26
+
27
+ const showDetails = !simpleMode && viewport !== viewports.xs
28
+ const label = videoText[copy].watch
29
+
30
+ return (
31
+ <SplashBackground {...selectProps(rest)} onClick={onClick} videoPoster={poster}>
32
+ {showDetails ? (
33
+ <SplashButtonWithDetails videoLength={videoLength} copy={copy} label={label} />
34
+ ) : (
35
+ <SplashButton videoLength={videoLength} copy={copy} />
36
+ )}
37
+ </SplashBackground>
38
+ )
39
+ }
40
+
41
+ VideoSplash.propTypes = {
42
+ ...selectedSystemPropTypes,
43
+ onClick: PropTypes.func,
44
+ poster: PropTypes.string,
45
+ videoLength: PropTypes.number.isRequired,
46
+ simpleMode: PropTypes.bool,
47
+ copy: PropTypes.oneOf(['en', 'fr'])
48
+ }
49
+
50
+ export default VideoSplash
@@ -0,0 +1,27 @@
1
+ import videoText from '../../Video/videoText'
2
+
3
+ export const getTimestamp = (videoLength, copy) => {
4
+ const minutes = Math.floor(videoLength / 60)
5
+ const seconds = Math.ceil(videoLength % 60)
6
+
7
+ const minutesText = minutes > 0 ? `${minutes}min ` : ''
8
+ const secondsText = `${seconds}${copy === 'fr' ? 's' : 'sec'}`
9
+ const timestamp = `${minutesText}${secondsText}`
10
+
11
+ return {
12
+ minutes,
13
+ seconds,
14
+ timestamp
15
+ }
16
+ }
17
+
18
+ export const getAriaLabel = (timestamp, copy) => {
19
+ const { minutes, seconds } = timestamp
20
+
21
+ const text = videoText[copy]
22
+
23
+ const minutesText = `${minutes} ${minutes !== 1 ? text.minutes : text.minute}`
24
+ const secondsText = `${seconds} ${seconds !== 1 ? text.seconds : text.second}`
25
+
26
+ return text.ariaLabel.replace('{minutes}', minutesText).replace('{seconds}', secondsText)
27
+ }
@@ -4,5 +4,14 @@ import htmlAttrs from './htmlAttrs'
4
4
  import { warn } from './logger'
5
5
  import media from './media'
6
6
  import renderStructuredContent from './renderStructuredContent'
7
+ import useOverlaidPosition from './useOverlaidPosition'
7
8
 
8
- export { htmlAttrs, transformGradient, useTypographyTheme, warn, media, renderStructuredContent }
9
+ export {
10
+ htmlAttrs,
11
+ transformGradient,
12
+ useTypographyTheme,
13
+ warn,
14
+ media,
15
+ renderStructuredContent,
16
+ useOverlaidPosition
17
+ }
@@ -0,0 +1,32 @@
1
+ import type { ComponentType, ReactElement, ReactNode } from 'react'
2
+ import type { HTMLAttrs, InputSupportsProps, TextInputProps, TextInputHandlerProps } from './common'
3
+
4
+ interface AutocompleteCommonProps
5
+ extends HTMLAttrs,
6
+ InputSupportsProps,
7
+ TextInputProps,
8
+ TextInputHandlerProps {}
9
+
10
+ interface AutocompleteChildrenProps extends AutocompleteCommonProps {
11
+ inputId?: string
12
+ inputRef?: any
13
+ }
14
+
15
+ export interface AutocompleteItem {
16
+ id: string
17
+ label: string
18
+ }
19
+
20
+ export interface AutocompleteProps extends AutocompleteCommonProps {
21
+ children?: (props: AutocompleteChildrenProps) => ReactElement
22
+ isLoading?: boolean
23
+ items?: AutocompleteItem[]
24
+ loadingLabel?: string
25
+ minToSuggestion?: number
26
+ maxSuggestions?: number
27
+ noResults?: ReactNode
28
+ }
29
+
30
+ declare const Autocomplete: ComponentType<AutocompleteProps>
31
+
32
+ export default Autocomplete
@@ -0,0 +1,45 @@
1
+ import type { ComponentType, ReactNode } from 'react'
2
+ import type { HTMLAttrs, Variant } from './common'
3
+
4
+ type FooterPadding = {
5
+ paddingBottom?: number
6
+ paddingLeft?: number
7
+ paddingRight?: number
8
+ paddingTop?: number
9
+ }
10
+
11
+ type BorderRadius = {
12
+ borderBottomLeftRadius: number
13
+ borderBottomRightRadius: number
14
+ borderTopLeftRadius: number
15
+ borderTopRightRadius: number
16
+ }
17
+
18
+ type FullBleedContent = {
19
+ position: 'none' | 'bottom' | 'left' | 'right' | 'top'
20
+ align?: 'start' | 'end' | 'center' | 'stretch'
21
+ borderRadius?: BorderRadius
22
+ content?: ReactNode
23
+ src?: string
24
+ alt?: string
25
+ xsSrc?: string
26
+ smSrc?: string
27
+ fallbackSrc?: string
28
+ mdSrc?: string
29
+ lgSrc?: string
30
+ xlSrc?: string
31
+ loading?: 'eager' | 'lazy'
32
+ }
33
+
34
+ export interface CardProps extends HTMLAttrs {
35
+ children: ReactNode
36
+ variant?: Variant
37
+ footer?: ReactNode
38
+ footerPadding?: FooterPadding
39
+ fullBleedImage?: FullBleedContent
40
+ fullBleedContent?: FullBleedContent
41
+ }
42
+
43
+ declare const Card: ComponentType<CardProps>
44
+
45
+ export default Card
@@ -0,0 +1,59 @@
1
+ import type { ComponentType, ReactNode } from 'react'
2
+ import type { HTMLAttrs, Variant } from './common'
3
+
4
+ type Track = {
5
+ source: string
6
+ label: string
7
+ kind: string
8
+ language: string
9
+ }
10
+
11
+ type Source = {
12
+ source: string
13
+ mediaType: string
14
+ qualityName: string
15
+ qualityRank: number
16
+ isFallback: boolean
17
+ }
18
+
19
+ export interface ControlBarProps extends HTMLAttrs {
20
+ children?: ReactNode
21
+ variant?: Variant
22
+ videoPlayer: any
23
+ videoPlayerContainer: any
24
+ sources: [Source]
25
+ tracks?: [Track]
26
+ videoPlaying: boolean
27
+ videoUnplayed: boolean
28
+ videoBufferEnd: number
29
+ isHidden?: boolean
30
+ videoLength: number
31
+ videoCurrentTime: number
32
+ videoCurrentVolume: number
33
+ videoIsMuted: boolean
34
+ setVolume: Function
35
+ isMobile: boolean
36
+ tracksAvailable: boolean
37
+ togglePlayPause: Function
38
+ setSeek: Function
39
+ toggleMute: Function
40
+ toggleFullscreen: Function
41
+ videoIsFullscreen: boolean
42
+ setTextTracks: Function
43
+ selectedTextTrack: number
44
+ resetInactivityTimer: Function
45
+ videoQuality: number
46
+ setVideoQuality: Function
47
+ captionsMenuOpen: boolean
48
+ setCaptionsMenuOpen: Function
49
+ qualityMenuOpen: boolean
50
+ setQualityMenuOpen: Function
51
+ clearInactivityTimer: Function
52
+ copy: 'en' | 'fr'
53
+ compactModeThreshold: number
54
+ videoPlayerWidth: number
55
+ }
56
+
57
+ declare const ControlBar: ComponentType<ControlBarProps>
58
+
59
+ export default ControlBar
@@ -0,0 +1,15 @@
1
+ import type { ComponentType, ElementType, ReactNode } from 'react'
2
+ import type { HTMLAttrs, Variant } from './common'
3
+
4
+ export interface MiddleControlButtonProps extends HTMLAttrs {
5
+ children?: ReactNode
6
+ variant?: Variant
7
+ icon: ElementType
8
+ isHidden?: boolean
9
+ onClick?: Function
10
+ onFocus?: Function
11
+ }
12
+
13
+ declare const MiddleControlButton: ComponentType<MiddleControlButtonProps>
14
+
15
+ export default MiddleControlButton