@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.
- package/CHANGELOG.md +27 -2
- package/lib/Autocomplete/Autocomplete.js +393 -0
- package/lib/Autocomplete/Loading.js +51 -0
- package/lib/Autocomplete/Suggestions.js +81 -0
- package/lib/Autocomplete/constants.js +19 -0
- package/lib/Autocomplete/dictionary.js +19 -0
- package/lib/Autocomplete/index.js +13 -0
- package/lib/Callout/Callout.js +3 -0
- package/lib/Card/Card.js +180 -0
- package/lib/Card/CardContent.js +110 -0
- package/lib/Card/CardFooter.js +98 -0
- package/lib/Card/index.js +13 -0
- package/lib/Countdown/Countdown.js +189 -0
- package/lib/Countdown/Segment.js +111 -0
- package/lib/Countdown/constants.js +14 -0
- package/lib/Countdown/dictionary.js +29 -0
- package/lib/Countdown/index.js +13 -0
- package/lib/Countdown/types.js +39 -0
- package/lib/Countdown/useCountdown.js +40 -0
- package/lib/Modal/ModalContent.js +11 -4
- package/lib/OptimizeImage/OptimizeImage.js +127 -0
- package/lib/OptimizeImage/index.js +13 -0
- package/lib/OptimizeImage/utils/getFallbackUrl.js +18 -0
- package/lib/OptimizeImage/utils/getOptimizedUrl.js +32 -0
- package/lib/OptimizeImage/utils/hasWebpSupport.js +38 -0
- package/lib/OptimizeImage/utils/index.js +31 -0
- package/lib/OptimizeImage/utils/isSvgUrl.js +10 -0
- package/lib/QuantitySelector/QuantitySelector.js +253 -0
- package/lib/QuantitySelector/dictionary.js +33 -0
- package/lib/QuantitySelector/index.js +13 -0
- package/lib/QuantitySelector/styles.js +40 -0
- package/lib/StoryCard/StoryCard.js +244 -0
- package/lib/StoryCard/index.js +13 -0
- package/lib/TermsAndConditions/ExpandCollapse.js +141 -0
- package/lib/TermsAndConditions/TermsAndConditions.js +221 -0
- package/lib/TermsAndConditions/dictionary.js +19 -0
- package/lib/TermsAndConditions/index.js +15 -0
- package/lib/Testimonial/Testimonial.js +226 -0
- package/lib/Testimonial/index.js +13 -0
- package/lib/Video/ControlBar/ControlBar.js +315 -0
- package/lib/Video/ControlBar/Controls/VideoButton/VideoButton.js +91 -0
- package/lib/Video/ControlBar/Controls/VideoMenu/VideoMenu.js +186 -0
- package/lib/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.js +221 -0
- package/lib/Video/ControlBar/Controls/VolumeSlider/VolumeSlider.js +213 -0
- package/lib/Video/MiddleControlButton/MiddleControlButton.js +89 -0
- package/lib/Video/Video.js +1072 -0
- package/lib/Video/index.js +13 -0
- package/lib/Video/videoText.js +62 -0
- package/lib/WebVideo/WebVideo.js +170 -0
- package/lib/WebVideo/index.js +13 -0
- package/lib/baseExports.js +0 -6
- package/lib/index.js +91 -1
- package/lib/shared/VideoSplash/SplashButton/SplashButton.js +102 -0
- package/lib/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.js +234 -0
- package/lib/shared/VideoSplash/VideoSplash.js +86 -0
- package/lib/shared/VideoSplash/helpers.js +38 -0
- package/lib/utils/index.js +8 -0
- package/lib-module/Autocomplete/Autocomplete.js +369 -0
- package/lib-module/Autocomplete/Loading.js +38 -0
- package/lib-module/Autocomplete/Suggestions.js +64 -0
- package/lib-module/Autocomplete/constants.js +5 -0
- package/lib-module/Autocomplete/dictionary.js +12 -0
- package/lib-module/Autocomplete/index.js +2 -0
- package/lib-module/Callout/Callout.js +3 -0
- package/lib-module/Card/Card.js +158 -0
- package/lib-module/Card/CardContent.js +92 -0
- package/lib-module/Card/CardFooter.js +80 -0
- package/lib-module/Card/index.js +2 -0
- package/lib-module/Countdown/Countdown.js +165 -0
- package/lib-module/Countdown/Segment.js +94 -0
- package/lib-module/Countdown/constants.js +4 -0
- package/lib-module/Countdown/dictionary.js +22 -0
- package/lib-module/Countdown/index.js +2 -0
- package/lib-module/Countdown/types.js +23 -0
- package/lib-module/Countdown/useCountdown.js +32 -0
- package/lib-module/Modal/ModalContent.js +10 -4
- package/lib-module/OptimizeImage/OptimizeImage.js +106 -0
- package/lib-module/OptimizeImage/index.js +2 -0
- package/lib-module/OptimizeImage/utils/getFallbackUrl.js +8 -0
- package/lib-module/OptimizeImage/utils/getOptimizedUrl.js +22 -0
- package/lib-module/OptimizeImage/utils/hasWebpSupport.js +32 -0
- package/lib-module/OptimizeImage/utils/index.js +4 -0
- package/lib-module/OptimizeImage/utils/isSvgUrl.js +3 -0
- package/lib-module/QuantitySelector/QuantitySelector.js +232 -0
- package/lib-module/QuantitySelector/dictionary.js +26 -0
- package/lib-module/QuantitySelector/index.js +2 -0
- package/lib-module/QuantitySelector/styles.js +21 -0
- package/lib-module/StoryCard/StoryCard.js +220 -0
- package/lib-module/StoryCard/index.js +2 -0
- package/lib-module/TermsAndConditions/ExpandCollapse.js +120 -0
- package/lib-module/TermsAndConditions/TermsAndConditions.js +193 -0
- package/lib-module/TermsAndConditions/dictionary.js +12 -0
- package/lib-module/TermsAndConditions/index.js +1 -0
- package/lib-module/Testimonial/Testimonial.js +204 -0
- package/lib-module/Testimonial/index.js +2 -0
- package/lib-module/Video/ControlBar/ControlBar.js +292 -0
- package/lib-module/Video/ControlBar/Controls/VideoButton/VideoButton.js +74 -0
- package/lib-module/Video/ControlBar/Controls/VideoMenu/VideoMenu.js +167 -0
- package/lib-module/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.js +201 -0
- package/lib-module/Video/ControlBar/Controls/VolumeSlider/VolumeSlider.js +193 -0
- package/lib-module/Video/MiddleControlButton/MiddleControlButton.js +72 -0
- package/lib-module/Video/Video.js +1042 -0
- package/lib-module/Video/index.js +2 -0
- package/lib-module/Video/videoText.js +55 -0
- package/lib-module/WebVideo/WebVideo.js +144 -0
- package/lib-module/WebVideo/index.js +2 -0
- package/lib-module/baseExports.js +1 -1
- package/lib-module/index.js +10 -0
- package/lib-module/shared/VideoSplash/SplashButton/SplashButton.js +85 -0
- package/lib-module/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.js +216 -0
- package/lib-module/shared/VideoSplash/VideoSplash.js +65 -0
- package/lib-module/shared/VideoSplash/helpers.js +23 -0
- package/lib-module/utils/index.js +2 -1
- package/package.json +7 -5
- package/src/Autocomplete/Autocomplete.jsx +354 -0
- package/src/Autocomplete/Loading.jsx +18 -0
- package/src/Autocomplete/Suggestions.jsx +52 -0
- package/src/Autocomplete/constants.js +6 -0
- package/src/Autocomplete/dictionary.js +12 -0
- package/src/Autocomplete/index.js +3 -0
- package/src/Callout/Callout.jsx +1 -1
- package/src/Card/Card.jsx +170 -0
- package/src/Card/CardContent.jsx +88 -0
- package/src/Card/CardFooter.jsx +70 -0
- package/src/Card/index.js +3 -0
- package/src/Countdown/Countdown.jsx +144 -0
- package/src/Countdown/Segment.jsx +69 -0
- package/src/Countdown/constants.js +4 -0
- package/src/Countdown/dictionary.js +22 -0
- package/src/Countdown/index.js +3 -0
- package/src/Countdown/types.js +23 -0
- package/src/Countdown/useCountdown.js +34 -0
- package/src/Modal/ModalContent.jsx +8 -4
- package/src/OptimizeImage/OptimizeImage.jsx +131 -0
- package/src/OptimizeImage/index.js +3 -0
- package/src/OptimizeImage/utils/getFallbackUrl.js +9 -0
- package/src/OptimizeImage/utils/getOptimizedUrl.js +30 -0
- package/src/OptimizeImage/utils/hasWebpSupport.js +33 -0
- package/src/OptimizeImage/utils/index.js +5 -0
- package/src/OptimizeImage/utils/isSvgUrl.js +3 -0
- package/src/QuantitySelector/QuantitySelector.jsx +245 -0
- package/src/QuantitySelector/dictionary.js +27 -0
- package/src/QuantitySelector/index.js +3 -0
- package/src/QuantitySelector/styles.js +83 -0
- package/src/StoryCard/StoryCard.jsx +198 -0
- package/src/StoryCard/index.js +3 -0
- package/src/TermsAndConditions/ExpandCollapse.jsx +106 -0
- package/src/TermsAndConditions/TermsAndConditions.jsx +161 -0
- package/src/TermsAndConditions/dictionary.js +12 -0
- package/src/TermsAndConditions/index.js +1 -0
- package/src/Testimonial/Testimonial.jsx +169 -0
- package/src/Testimonial/index.js +3 -0
- package/src/Video/ControlBar/ControlBar.jsx +261 -0
- package/src/Video/ControlBar/Controls/VideoButton/VideoButton.jsx +61 -0
- package/src/Video/ControlBar/Controls/VideoMenu/VideoMenu.jsx +159 -0
- package/src/Video/ControlBar/Controls/VideoProgressBar/VideoProgressBar.jsx +185 -0
- package/src/Video/ControlBar/Controls/VolumeSlider/VolumeSlider.jsx +184 -0
- package/src/Video/MiddleControlButton/MiddleControlButton.jsx +64 -0
- package/src/Video/Video.jsx +988 -0
- package/src/Video/index.js +3 -0
- package/src/Video/videoText.js +58 -0
- package/src/WebVideo/WebVideo.jsx +131 -0
- package/src/WebVideo/index.js +3 -0
- package/src/baseExports.js +0 -1
- package/src/index.js +10 -0
- package/src/shared/VideoSplash/SplashButton/SplashButton.jsx +64 -0
- package/src/shared/VideoSplash/SplashButtonWithDetails/SplashButtonWithDetails.jsx +128 -0
- package/src/shared/VideoSplash/VideoSplash.jsx +50 -0
- package/src/shared/VideoSplash/helpers.js +27 -0
- package/src/utils/index.js +10 -1
- package/types/Autocomplete.d.ts +32 -0
- package/types/Card.d.ts +45 -0
- package/types/ControlBar.d.ts +59 -0
- package/types/MiddleControlButton.d.ts +15 -0
- package/types/Video.d.ts +39 -0
- package/types/VideoButton.d.ts +14 -0
- package/types/VideoMenu.d.ts +16 -0
- package/types/VideoProgressBar.d.ts +17 -0
- package/types/VolumeSlider.d.ts +20 -0
|
@@ -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
|
package/src/baseExports.js
CHANGED
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
|
+
}
|
package/src/utils/index.js
CHANGED
|
@@ -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 {
|
|
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
|
package/types/Card.d.ts
ADDED
|
@@ -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
|