@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.
- package/.eslintignore +2 -0
- package/.vscode/settings.json +7 -0
- package/CHANGELOG.md +39 -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/BlockQuote/BlockQuote.js +173 -0
- package/lib/BlockQuote/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/IconButton/IconButton.js +70 -0
- package/lib/IconButton/index.js +13 -0
- package/lib/Listbox/GroupControl.js +94 -0
- package/lib/Listbox/Listbox.js +164 -0
- package/lib/Listbox/ListboxGroup.js +129 -0
- package/lib/Listbox/ListboxItem.js +137 -0
- package/lib/Listbox/ListboxOverlay.js +89 -0
- package/lib/Listbox/PressableItem.js +149 -0
- package/lib/Listbox/index.js +13 -0
- package/lib/Modal/ModalContent.js +11 -4
- package/lib/NavigationBar/resolveItemSelection.js +24 -0
- 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 -12
- package/lib/index.js +118 -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/utils/useOverlaidPosition.js +246 -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/BlockQuote/BlockQuote.js +156 -0
- package/lib-module/BlockQuote/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/IconButton/IconButton.js +52 -0
- package/lib-module/IconButton/index.js +2 -0
- package/lib-module/Listbox/GroupControl.js +80 -0
- package/lib-module/Listbox/Listbox.js +142 -0
- package/lib-module/Listbox/ListboxGroup.js +106 -0
- package/lib-module/Listbox/ListboxItem.js +112 -0
- package/lib-module/Listbox/ListboxOverlay.js +68 -0
- package/lib-module/Listbox/PressableItem.js +128 -0
- package/lib-module/Listbox/index.js +2 -0
- package/lib-module/Modal/ModalContent.js +10 -4
- package/lib-module/NavigationBar/resolveItemSelection.js +16 -0
- 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 +13 -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/lib-module/utils/useOverlaidPosition.js +235 -0
- 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/BlockQuote/BlockQuote.jsx +130 -0
- package/src/BlockQuote/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/IconButton/IconButton.jsx +46 -0
- package/src/IconButton/index.js +3 -0
- package/src/Listbox/GroupControl.jsx +65 -0
- package/src/Listbox/Listbox.jsx +148 -0
- package/src/Listbox/ListboxGroup.jsx +110 -0
- package/src/Listbox/ListboxItem.jsx +101 -0
- package/src/Listbox/ListboxOverlay.jsx +71 -0
- package/src/Listbox/PressableItem.jsx +121 -0
- package/src/Listbox/index.js +3 -0
- package/src/Modal/ModalContent.jsx +8 -4
- package/src/NavigationBar/resolveItemSelection.js +11 -0
- 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 -2
- package/src/index.js +13 -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/src/utils/useOverlaidPosition.js +226 -0
- 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,71 @@
|
|
|
1
|
+
/* eslint-disable react/require-default-props */
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
import { Card, Portal, useThemeTokens } from '@telus-uds/components-base'
|
|
4
|
+
import PropTypes from 'prop-types'
|
|
5
|
+
import { View, StyleSheet } from 'react-native-web'
|
|
6
|
+
|
|
7
|
+
const staticStyles = StyleSheet.create({
|
|
8
|
+
positioner: {
|
|
9
|
+
flex: 1, // Grow to maxWidth when possible, shrink when not possible
|
|
10
|
+
position: 'absolute',
|
|
11
|
+
zIndex: 10000 // Position on top of all the other overlays, including backdrops and modals
|
|
12
|
+
},
|
|
13
|
+
hidden: {
|
|
14
|
+
// Use opacity not visibility to hide the dropdown during positioning
|
|
15
|
+
// so on web, children may be focused from the first render
|
|
16
|
+
opacity: 0
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const paddingVertical = 0
|
|
21
|
+
const paddingHorizontal = 0
|
|
22
|
+
|
|
23
|
+
const DropdownOverlay = forwardRef(
|
|
24
|
+
({ children, isReady = false, overlaidPosition, maxWidth, minWidth, onLayout }, ref) => {
|
|
25
|
+
const systemTokens = useThemeTokens('ListBox', {}, {})
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Portal>
|
|
29
|
+
<View
|
|
30
|
+
ref={ref}
|
|
31
|
+
onLayout={onLayout}
|
|
32
|
+
style={[
|
|
33
|
+
overlaidPosition,
|
|
34
|
+
{ maxWidth, minWidth },
|
|
35
|
+
staticStyles.positioner,
|
|
36
|
+
!isReady && staticStyles.hidden
|
|
37
|
+
]}
|
|
38
|
+
>
|
|
39
|
+
<Card
|
|
40
|
+
tokens={{
|
|
41
|
+
shadow: systemTokens.shadow,
|
|
42
|
+
paddingBottom: paddingVertical,
|
|
43
|
+
paddingTop: paddingVertical,
|
|
44
|
+
paddingLeft: paddingHorizontal,
|
|
45
|
+
paddingRight: paddingHorizontal
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
{children}
|
|
49
|
+
</Card>
|
|
50
|
+
</View>
|
|
51
|
+
</Portal>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
DropdownOverlay.displayName = 'DropdownOverlay'
|
|
57
|
+
|
|
58
|
+
DropdownOverlay.propTypes = {
|
|
59
|
+
children: PropTypes.node.isRequired,
|
|
60
|
+
isReady: PropTypes.bool,
|
|
61
|
+
overlaidPosition: PropTypes.shape({
|
|
62
|
+
top: PropTypes.number,
|
|
63
|
+
left: PropTypes.number,
|
|
64
|
+
width: PropTypes.number
|
|
65
|
+
}),
|
|
66
|
+
maxWidth: PropTypes.number,
|
|
67
|
+
minWidth: PropTypes.number,
|
|
68
|
+
onLayout: PropTypes.func
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default DropdownOverlay
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/* eslint-disable react/require-default-props */
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import { selectSystemProps, useThemeTokens } from '@telus-uds/components-base'
|
|
5
|
+
import styled from 'styled-components'
|
|
6
|
+
import { htmlAttrs } from '../utils'
|
|
7
|
+
|
|
8
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
|
|
9
|
+
|
|
10
|
+
const getItemStyles = ({ tokens }) => ({
|
|
11
|
+
fontFamily: `${tokens.groupFontName}${tokens.groupFontWeight}normal`,
|
|
12
|
+
fontSize: tokens.itemFontSize,
|
|
13
|
+
paddingTop: tokens.itemPaddingTop,
|
|
14
|
+
paddingBottom: tokens.itemPaddingBottom,
|
|
15
|
+
paddingLeft: tokens.itemPaddingLeft,
|
|
16
|
+
paddingRight: tokens.itemPaddingRight,
|
|
17
|
+
borderWidth: tokens.itemBorderWidth,
|
|
18
|
+
width: '100%',
|
|
19
|
+
backgroundColor: tokens.itemBackgroundColor,
|
|
20
|
+
color: tokens.groupColor,
|
|
21
|
+
display: tokens.itemDisplay,
|
|
22
|
+
outline: tokens.itemOutline,
|
|
23
|
+
textDecoration: tokens.itemTextDecoration
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const StyledLink = styled.a(({ isChild, tokens }) => ({
|
|
27
|
+
...getItemStyles({ isChild, tokens }),
|
|
28
|
+
borderLeft: isChild
|
|
29
|
+
? `${tokens.itemBorderWidth}px solid ${tokens.itemBorderBackgroundColor}`
|
|
30
|
+
: 'none',
|
|
31
|
+
cursor: 'pointer',
|
|
32
|
+
|
|
33
|
+
[`&:hover, &:focus, &:active`]: {
|
|
34
|
+
color: tokens.itemColor
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
'&:hover': {
|
|
38
|
+
backgroundColor: tokens.groupBackgroundColor
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
// Highlighting for pressable items that are not links per se
|
|
42
|
+
// TODO: find a better way to display and style a pressable link
|
|
43
|
+
'&:hover > div, &:hover > div > span': {
|
|
44
|
+
color: `${tokens.itemColor} !important`
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
'&:focus': {
|
|
48
|
+
border: `${tokens.groupBorderWidth}px solid ${tokens.itemBorderLeftColor}`,
|
|
49
|
+
borderLeft: isChild && `${tokens.itemBorderWidth}px solid ${tokens.itemBorderLeftColor}`,
|
|
50
|
+
borderRadius: !isChild && tokens.groupBorderRadius,
|
|
51
|
+
paddingLeft: !isChild && `calc(${tokens.itemPaddingLeft}px - ${tokens.groupBorderWidth}px)`,
|
|
52
|
+
paddingRight: `calc(${tokens.itemPaddingRight}px - ${tokens.groupBorderWidth}px)`,
|
|
53
|
+
paddingTop: `calc(${tokens.itemPaddingTop}px - ${tokens.groupBorderWidth}px)`,
|
|
54
|
+
paddingBottom: `calc(${tokens.itemPaddingBottom}px - ${tokens.groupBorderWidth}px)`,
|
|
55
|
+
backgroundColor: tokens.groupBackgroundColor
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
'&:active': {
|
|
59
|
+
backgroundColor: tokens.itemBorderBackgroundColor
|
|
60
|
+
}
|
|
61
|
+
}))
|
|
62
|
+
|
|
63
|
+
const PressableItem = forwardRef(
|
|
64
|
+
(
|
|
65
|
+
{
|
|
66
|
+
children,
|
|
67
|
+
href,
|
|
68
|
+
isChild = false,
|
|
69
|
+
onBlur,
|
|
70
|
+
onPress,
|
|
71
|
+
tabIndex = 0,
|
|
72
|
+
nextItemRef,
|
|
73
|
+
prevItemRef,
|
|
74
|
+
tokens,
|
|
75
|
+
variant = {},
|
|
76
|
+
...rest
|
|
77
|
+
},
|
|
78
|
+
ref
|
|
79
|
+
) => {
|
|
80
|
+
const handleKeyPress = (event) => {
|
|
81
|
+
if (['Enter', ' '].includes(event?.key)) {
|
|
82
|
+
onPress?.(event)
|
|
83
|
+
} else if (event?.key === 'ArrowDown' && nextItemRef?.current) {
|
|
84
|
+
nextItemRef.current.focus()
|
|
85
|
+
} else if (event?.key === 'ArrowUp' && prevItemRef?.current) {
|
|
86
|
+
prevItemRef.current.focus()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const systemTokens = useThemeTokens('ListBox', tokens, variant, { isChild, hover: true })
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<StyledLink
|
|
93
|
+
isChild={isChild}
|
|
94
|
+
tokens={systemTokens}
|
|
95
|
+
onBlur={onBlur}
|
|
96
|
+
onClick={onPress}
|
|
97
|
+
onKeyPress={handleKeyPress}
|
|
98
|
+
ref={ref}
|
|
99
|
+
tabIndex={tabIndex}
|
|
100
|
+
{...(href && { href })}
|
|
101
|
+
{...(onPress && { onClick: onPress })}
|
|
102
|
+
{...selectProps(rest)}
|
|
103
|
+
>
|
|
104
|
+
{children}
|
|
105
|
+
</StyledLink>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
PressableItem.displayName = 'PressableItem'
|
|
110
|
+
PressableItem.propTypes = {
|
|
111
|
+
...selectedSystemPropTypes,
|
|
112
|
+
href: PropTypes.string,
|
|
113
|
+
isChild: PropTypes.bool,
|
|
114
|
+
children: PropTypes.node.isRequired,
|
|
115
|
+
onBlur: PropTypes.func,
|
|
116
|
+
onPress: PropTypes.func,
|
|
117
|
+
nextItemRef: PropTypes.object,
|
|
118
|
+
prevItemRef: PropTypes.object
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export default PressableItem
|
|
@@ -28,6 +28,10 @@ const StyledSubHeading = styled.div`
|
|
|
28
28
|
margin-top: ${({ marginTop }) => marginTop}px;
|
|
29
29
|
`
|
|
30
30
|
|
|
31
|
+
const StyledTextButtonContainer = styled.div({
|
|
32
|
+
display: 'flex'
|
|
33
|
+
})
|
|
34
|
+
|
|
31
35
|
const StyledFooter = styled.footer(
|
|
32
36
|
({
|
|
33
37
|
hasBorder,
|
|
@@ -131,13 +135,13 @@ const ModalContent = ({
|
|
|
131
135
|
{confirmButtonText}
|
|
132
136
|
</Button>
|
|
133
137
|
)}
|
|
134
|
-
|
|
135
|
-
|
|
138
|
+
{hasCancelButton ? (
|
|
139
|
+
<StyledTextButtonContainer>
|
|
136
140
|
<CancelButton tokens={{ color: cancelButtonColor }} onPress={onCancel}>
|
|
137
141
|
{cancelButtonText}
|
|
138
142
|
</CancelButton>
|
|
139
|
-
|
|
140
|
-
|
|
143
|
+
</StyledTextButtonContainer>
|
|
144
|
+
) : null}
|
|
141
145
|
</StyledFooter>
|
|
142
146
|
)}
|
|
143
147
|
</StyledModalContent>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const resolveItemSelection = ({ id, label, items }, selectedId) => {
|
|
2
|
+
const itemId = id ?? label
|
|
3
|
+
|
|
4
|
+
// Treat item as selected if it or any nested child matches the selected id
|
|
5
|
+
const selected = Boolean(
|
|
6
|
+
selectedId === itemId || items?.some((item) => resolveItemSelection(item, selectedId).selected)
|
|
7
|
+
)
|
|
8
|
+
return { itemId, selected }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default resolveItemSelection
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import { selectSystemProps } from '@telus-uds/components-base'
|
|
4
|
+
import ResponsiveImage from '../ResponsiveImage'
|
|
5
|
+
import { hasWebpSupport, getOptimizedUrl, getFallbackUrl } from './utils'
|
|
6
|
+
import { htmlAttrs } from '../utils'
|
|
7
|
+
|
|
8
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
|
|
9
|
+
|
|
10
|
+
const OptimizeImage = ({
|
|
11
|
+
contentfulAssetUrl,
|
|
12
|
+
alt,
|
|
13
|
+
quality = 80,
|
|
14
|
+
xs = 320,
|
|
15
|
+
sm = 576,
|
|
16
|
+
md = 768,
|
|
17
|
+
lg = 992,
|
|
18
|
+
xl = 1200,
|
|
19
|
+
sizeByHeight = false,
|
|
20
|
+
disableRetina = false,
|
|
21
|
+
...rest
|
|
22
|
+
}) => {
|
|
23
|
+
const [imgUrls, setImgUrls] = useState()
|
|
24
|
+
|
|
25
|
+
// `useHeight` is a deprecated TDS prop, replaced by `sizeByHeight`
|
|
26
|
+
const dimension = sizeByHeight || rest.useHeight ? 'h' : 'w'
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
// Currently not all browsers support webP
|
|
30
|
+
hasWebpSupport().then((supportsWebp) => {
|
|
31
|
+
setImgUrls({
|
|
32
|
+
xsSrc: getOptimizedUrl(
|
|
33
|
+
contentfulAssetUrl,
|
|
34
|
+
dimension,
|
|
35
|
+
xs,
|
|
36
|
+
quality,
|
|
37
|
+
disableRetina,
|
|
38
|
+
supportsWebp
|
|
39
|
+
),
|
|
40
|
+
smSrc: getOptimizedUrl(
|
|
41
|
+
contentfulAssetUrl,
|
|
42
|
+
dimension,
|
|
43
|
+
sm,
|
|
44
|
+
quality,
|
|
45
|
+
disableRetina,
|
|
46
|
+
supportsWebp
|
|
47
|
+
),
|
|
48
|
+
mdSrc: getOptimizedUrl(
|
|
49
|
+
contentfulAssetUrl,
|
|
50
|
+
dimension,
|
|
51
|
+
md,
|
|
52
|
+
quality,
|
|
53
|
+
disableRetina,
|
|
54
|
+
supportsWebp
|
|
55
|
+
),
|
|
56
|
+
lgSrc: getOptimizedUrl(
|
|
57
|
+
contentfulAssetUrl,
|
|
58
|
+
dimension,
|
|
59
|
+
lg,
|
|
60
|
+
quality,
|
|
61
|
+
disableRetina,
|
|
62
|
+
supportsWebp
|
|
63
|
+
),
|
|
64
|
+
xlSrc: getOptimizedUrl(
|
|
65
|
+
contentfulAssetUrl,
|
|
66
|
+
dimension,
|
|
67
|
+
xl,
|
|
68
|
+
quality,
|
|
69
|
+
disableRetina,
|
|
70
|
+
supportsWebp
|
|
71
|
+
),
|
|
72
|
+
fallbackSrc: getFallbackUrl(contentfulAssetUrl, xl, quality)
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
}, [contentfulAssetUrl, dimension, disableRetina, lg, md, quality, sm, xl, xs])
|
|
76
|
+
|
|
77
|
+
if (!imgUrls) return null
|
|
78
|
+
return <ResponsiveImage {...imgUrls} alt={alt} {...selectProps(rest)} />
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
OptimizeImage.propTypes = {
|
|
82
|
+
...selectedSystemPropTypes,
|
|
83
|
+
/**
|
|
84
|
+
* The source to load the image. Only contentful image urls are supported. See https://www.contentful.com/developers/docs/references/images-api/ for details.
|
|
85
|
+
*/
|
|
86
|
+
contentfulAssetUrl: PropTypes.string.isRequired,
|
|
87
|
+
/**
|
|
88
|
+
* Alternative text to display if image cannot be loaded or a screen reader is used.
|
|
89
|
+
*/
|
|
90
|
+
alt: PropTypes.string.isRequired,
|
|
91
|
+
/**
|
|
92
|
+
* Customize quality as a percentage between 1 and 100.
|
|
93
|
+
*/
|
|
94
|
+
quality: PropTypes.number,
|
|
95
|
+
/**
|
|
96
|
+
* Customize width for xs screen size in px, this may affect the quality of the image.
|
|
97
|
+
*/
|
|
98
|
+
xs: PropTypes.number,
|
|
99
|
+
/**
|
|
100
|
+
* Customize width for sm screen size in px, this may affect the quality of the image.
|
|
101
|
+
*/
|
|
102
|
+
sm: PropTypes.number,
|
|
103
|
+
/**
|
|
104
|
+
* Customize width for md screen size in px, this may affect the quality of the image.
|
|
105
|
+
*/
|
|
106
|
+
md: PropTypes.number,
|
|
107
|
+
/**
|
|
108
|
+
* Customize width for lg screen size in px, this may affect the quality of the image.
|
|
109
|
+
*/
|
|
110
|
+
lg: PropTypes.number,
|
|
111
|
+
/**
|
|
112
|
+
* Customize width for xl screen size in px, this may affect the quality of the image.
|
|
113
|
+
*/
|
|
114
|
+
xl: PropTypes.number,
|
|
115
|
+
/**
|
|
116
|
+
* Switches size dimension to height, default is false
|
|
117
|
+
*/
|
|
118
|
+
sizeByHeight: PropTypes.bool,
|
|
119
|
+
/**
|
|
120
|
+
* Turns off retina display functionality
|
|
121
|
+
*/
|
|
122
|
+
disableRetina: PropTypes.bool,
|
|
123
|
+
/**
|
|
124
|
+
* Loading strategy.
|
|
125
|
+
* @default 'eager'
|
|
126
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading
|
|
127
|
+
*/
|
|
128
|
+
loading: PropTypes.oneOf(['eager', 'lazy'])
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export default OptimizeImage
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import isSvgUrl from './isSvgUrl'
|
|
2
|
+
|
|
3
|
+
export default function getOptimizedUrl(
|
|
4
|
+
url,
|
|
5
|
+
dimension,
|
|
6
|
+
size,
|
|
7
|
+
quality,
|
|
8
|
+
disableRetina,
|
|
9
|
+
supportsWebp
|
|
10
|
+
) {
|
|
11
|
+
if (!isSvgUrl(url)) {
|
|
12
|
+
let format = ''
|
|
13
|
+
|
|
14
|
+
if (supportsWebp) {
|
|
15
|
+
format = 'fm=webp'
|
|
16
|
+
} else if (url.match(/\.jpe?g$/i)) {
|
|
17
|
+
format = 'fm=jpg&fl=progressive'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let optimizedUrl = `${url}?${dimension}=${size}&q=${quality}&${format}`
|
|
21
|
+
|
|
22
|
+
if (!disableRetina) {
|
|
23
|
+
optimizedUrl += `, ${url}?${dimension}=${size * 2}&q=${quality}&${format} 2x`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return optimizedUrl
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return url
|
|
30
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
let promise
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Taken directly from Google developers guide on how to detect browser support for WebP.
|
|
5
|
+
*
|
|
6
|
+
* @see https://developers.google.com/speed/webp/faq#in_your_own_javascript
|
|
7
|
+
* @return {Promise<boolean>}
|
|
8
|
+
*/
|
|
9
|
+
export default function hasWebpSupport() {
|
|
10
|
+
// cache the result, so that this function runs only once
|
|
11
|
+
if (!promise) {
|
|
12
|
+
promise = new Promise((resolve) => {
|
|
13
|
+
// basic support. other test forms exist for lossless, alpha, and animation types.
|
|
14
|
+
// check google guide if data strings are needed
|
|
15
|
+
const lossy = 'UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA'
|
|
16
|
+
|
|
17
|
+
const img = document.createElement('img')
|
|
18
|
+
|
|
19
|
+
img.onload = function onLoad() {
|
|
20
|
+
const result = img.width > 0 && img.height > 0
|
|
21
|
+
|
|
22
|
+
resolve(result)
|
|
23
|
+
}
|
|
24
|
+
img.onerror = function onError() {
|
|
25
|
+
resolve(false)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
img.src = `data:image/webp;base64,${lossy}`
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return promise
|
|
33
|
+
}
|