@telus-uds/components-web 1.2.0 → 1.4.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 (140) hide show
  1. package/CHANGELOG.md +34 -2
  2. package/lib/Breadcrumbs/Breadcrumbs.js +247 -0
  3. package/lib/Breadcrumbs/Item/Item.js +165 -0
  4. package/lib/Breadcrumbs/index.js +15 -0
  5. package/lib/Callout/Callout.js +121 -0
  6. package/lib/Callout/index.js +13 -0
  7. package/lib/DatePicker/CalendarContainer.js +221 -0
  8. package/lib/DatePicker/DatePicker.js +329 -0
  9. package/lib/DatePicker/dictionary.js +134 -0
  10. package/lib/DatePicker/index.js +13 -0
  11. package/lib/DatePicker/reactDatesCss.js +12 -0
  12. package/lib/ExpandCollapseMini/ExpandCollapseMini.js +75 -0
  13. package/lib/ExpandCollapseMini/ExpandCollapseMiniControl.js +95 -0
  14. package/lib/ExpandCollapseMini/index.js +13 -0
  15. package/lib/Footnote/Footnote.js +571 -0
  16. package/lib/Footnote/FootnoteLink.js +149 -0
  17. package/lib/Footnote/dictionary.js +19 -0
  18. package/lib/Footnote/index.js +16 -0
  19. package/lib/OrderedList/Item.js +162 -0
  20. package/lib/OrderedList/ItemBase.js +42 -0
  21. package/lib/OrderedList/OrderedList.js +94 -0
  22. package/lib/OrderedList/OrderedListBase.js +68 -0
  23. package/lib/OrderedList/constants.js +9 -0
  24. package/lib/OrderedList/index.js +16 -0
  25. package/lib/PreviewCard/AuthorDate.js +64 -0
  26. package/lib/PreviewCard/PreviewCard.js +236 -0
  27. package/lib/PreviewCard/index.js +13 -0
  28. package/lib/PriceLockup/PriceLockup.js +237 -0
  29. package/lib/PriceLockup/index.js +13 -0
  30. package/lib/PriceLockup/tokens.js +131 -0
  31. package/lib/ResponsiveImage/ResponsiveImage.js +115 -0
  32. package/lib/ResponsiveImage/index.js +13 -0
  33. package/lib/Ribbon/Ribbon.js +0 -1
  34. package/lib/Span/Span.js +88 -0
  35. package/lib/Span/index.js +13 -0
  36. package/lib/index.js +91 -1
  37. package/lib/shared/FullBleedContent/FullBleedContent.js +121 -0
  38. package/lib/shared/FullBleedContent/getFullBleedBorderRadius.js +73 -0
  39. package/lib/shared/FullBleedContent/index.js +29 -0
  40. package/lib/shared/FullBleedContent/useFullBleedContentProps.js +73 -0
  41. package/lib/utils/index.js +32 -0
  42. package/lib/utils/logger.js +31 -0
  43. package/lib/utils/media.js +54 -0
  44. package/lib/utils/renderStructuredContent.js +89 -0
  45. package/lib/utils/useTypographyTheme.js +32 -0
  46. package/lib-module/Breadcrumbs/Breadcrumbs.js +228 -0
  47. package/lib-module/Breadcrumbs/Item/Item.js +141 -0
  48. package/lib-module/Breadcrumbs/index.js +1 -0
  49. package/lib-module/Callout/Callout.js +106 -0
  50. package/lib-module/Callout/index.js +2 -0
  51. package/lib-module/DatePicker/CalendarContainer.js +208 -0
  52. package/lib-module/DatePicker/DatePicker.js +302 -0
  53. package/lib-module/DatePicker/dictionary.js +127 -0
  54. package/lib-module/DatePicker/index.js +2 -0
  55. package/lib-module/DatePicker/reactDatesCss.js +3 -0
  56. package/lib-module/ExpandCollapseMini/ExpandCollapseMini.js +56 -0
  57. package/lib-module/ExpandCollapseMini/ExpandCollapseMiniControl.js +80 -0
  58. package/lib-module/ExpandCollapseMini/index.js +2 -0
  59. package/lib-module/Footnote/Footnote.js +541 -0
  60. package/lib-module/Footnote/FootnoteLink.js +130 -0
  61. package/lib-module/Footnote/dictionary.js +12 -0
  62. package/lib-module/Footnote/index.js +4 -0
  63. package/lib-module/OrderedList/Item.js +139 -0
  64. package/lib-module/OrderedList/ItemBase.js +28 -0
  65. package/lib-module/OrderedList/OrderedList.js +71 -0
  66. package/lib-module/OrderedList/OrderedListBase.js +48 -0
  67. package/lib-module/OrderedList/constants.js +2 -0
  68. package/lib-module/OrderedList/index.js +4 -0
  69. package/lib-module/PreviewCard/AuthorDate.js +53 -0
  70. package/lib-module/PreviewCard/PreviewCard.js +211 -0
  71. package/lib-module/PreviewCard/index.js +2 -0
  72. package/lib-module/PriceLockup/PriceLockup.js +213 -0
  73. package/lib-module/PriceLockup/index.js +2 -0
  74. package/lib-module/PriceLockup/tokens.js +120 -0
  75. package/lib-module/ResponsiveImage/ResponsiveImage.js +100 -0
  76. package/lib-module/ResponsiveImage/index.js +2 -0
  77. package/lib-module/Ribbon/Ribbon.js +1 -2
  78. package/lib-module/Span/Span.js +70 -0
  79. package/lib-module/Span/index.js +2 -0
  80. package/lib-module/index.js +10 -0
  81. package/lib-module/shared/FullBleedContent/FullBleedContent.js +106 -0
  82. package/lib-module/shared/FullBleedContent/getFullBleedBorderRadius.js +65 -0
  83. package/lib-module/shared/FullBleedContent/index.js +4 -0
  84. package/lib-module/shared/FullBleedContent/useFullBleedContentProps.js +65 -0
  85. package/lib-module/utils/index.js +5 -1
  86. package/lib-module/utils/logger.js +18 -0
  87. package/lib-module/utils/media.js +46 -0
  88. package/lib-module/utils/renderStructuredContent.js +77 -0
  89. package/lib-module/utils/useTypographyTheme.js +24 -0
  90. package/package.json +9 -4
  91. package/src/Breadcrumbs/Breadcrumbs.jsx +222 -0
  92. package/src/Breadcrumbs/Item/Item.jsx +127 -0
  93. package/src/Breadcrumbs/index.js +1 -0
  94. package/src/Callout/Callout.jsx +76 -0
  95. package/src/Callout/index.js +3 -0
  96. package/src/DatePicker/CalendarContainer.jsx +210 -0
  97. package/src/DatePicker/DatePicker.jsx +303 -0
  98. package/src/DatePicker/dictionary.js +92 -0
  99. package/src/DatePicker/index.js +3 -0
  100. package/src/DatePicker/reactDatesCss.js +892 -0
  101. package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +48 -0
  102. package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +67 -0
  103. package/src/ExpandCollapseMini/index.js +3 -0
  104. package/src/Footnote/Footnote.jsx +468 -0
  105. package/src/Footnote/FootnoteLink.jsx +120 -0
  106. package/src/Footnote/dictionary.js +12 -0
  107. package/src/Footnote/index.js +6 -0
  108. package/src/OrderedList/Item.jsx +121 -0
  109. package/src/OrderedList/ItemBase.jsx +18 -0
  110. package/src/OrderedList/OrderedList.jsx +61 -0
  111. package/src/OrderedList/OrderedListBase.jsx +38 -0
  112. package/src/OrderedList/constants.js +2 -0
  113. package/src/OrderedList/index.js +6 -0
  114. package/src/PreviewCard/AuthorDate.jsx +31 -0
  115. package/src/PreviewCard/PreviewCard.jsx +201 -0
  116. package/src/PreviewCard/index.js +3 -0
  117. package/src/PriceLockup/PriceLockup.jsx +210 -0
  118. package/src/PriceLockup/index.js +3 -0
  119. package/src/PriceLockup/tokens.js +58 -0
  120. package/src/ResponsiveImage/ResponsiveImage.jsx +77 -0
  121. package/src/ResponsiveImage/index.js +3 -0
  122. package/src/Ribbon/Ribbon.jsx +0 -1
  123. package/src/Span/Span.jsx +66 -0
  124. package/src/Span/index.js +3 -0
  125. package/src/index.js +10 -0
  126. package/src/shared/FullBleedContent/FullBleedContent.jsx +90 -0
  127. package/src/shared/FullBleedContent/getFullBleedBorderRadius.js +55 -0
  128. package/src/shared/FullBleedContent/index.js +6 -0
  129. package/src/shared/FullBleedContent/useFullBleedContentProps.js +63 -0
  130. package/src/utils/index.js +5 -1
  131. package/src/utils/logger.js +20 -0
  132. package/src/utils/media.js +40 -0
  133. package/src/utils/renderStructuredContent.jsx +73 -0
  134. package/src/utils/useTypographyTheme.js +14 -0
  135. package/types/Callout.d.ts +13 -0
  136. package/types/DatePicker.d.ts +21 -0
  137. package/types/Footnote.d.ts +21 -0
  138. package/types/FootnoteLink.d.ts +20 -0
  139. package/types/PriceLockup.d.ts +22 -0
  140. package/types/common.d.ts +14 -0
@@ -0,0 +1,210 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import {
4
+ A11yText,
5
+ Divider,
6
+ selectSystemProps,
7
+ Typography,
8
+ useThemeTokens
9
+ } from '@telus-uds/components-base'
10
+ import styled from 'styled-components'
11
+ import FootnoteLink from '../Footnote/FootnoteLink'
12
+ import typographyTokens from './tokens'
13
+ import { htmlAttrs, warn } from '../utils'
14
+
15
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
16
+
17
+ const PriceLockupContainer = styled.div`
18
+ display: flex;
19
+ flex-direction: column;
20
+ width: fit-content;
21
+ `
22
+
23
+ const PriceContainer = styled.div`
24
+ display: flex;
25
+ margin-bottom: ${({ priceMarginBottom }) => priceMarginBottom};
26
+ `
27
+
28
+ const FootnoteContainer = styled.div`
29
+ display: flex;
30
+ margin-top: ${({ footnoteMarginTop }) => footnoteMarginTop};
31
+ gap: ${({ footnoteGap }) => footnoteGap};
32
+ `
33
+
34
+ const BottomTextContainer = styled.div`
35
+ margin-top: ${({ bottomTextMarginTop }) => bottomTextMarginTop};
36
+ `
37
+
38
+ const BottomLinksContainer = styled.div`
39
+ align-self: center;
40
+ margin-left: ${({ bottomLinksMarginLeft }) => bottomLinksMarginLeft};
41
+ `
42
+
43
+ const TopTextContainer = styled.div`
44
+ margin-bottom: ${({ topTextMarginBottom }) => topTextMarginBottom};
45
+ `
46
+
47
+ const RateTextContainer = styled.div`
48
+ align-self: flex-end;
49
+ `
50
+
51
+ const StrikeThroughContainer = styled.div`
52
+ display: flex;
53
+ position: relative;
54
+ align-items: center;
55
+ ::before {
56
+ content: '';
57
+ width: 100%;
58
+ height: ${({ strikeThroughHeight }) => strikeThroughHeight};
59
+ background: ${({ strikeThroughBackground }) => strikeThroughBackground};
60
+ position: absolute;
61
+ }
62
+ `
63
+
64
+ const PriceLockup = ({
65
+ size = 'medium',
66
+ signDirection = 'left',
67
+ footnoteLinks = [],
68
+ topText,
69
+ price,
70
+ currencySymbol = '$',
71
+ rateText,
72
+ bottomText,
73
+ onClickFootnote,
74
+ strikeThrough,
75
+ a11yText,
76
+ tokens: priceLockupTokens,
77
+ variant = {},
78
+ ...rest
79
+ }) => {
80
+ const {
81
+ footnoteMarginTop,
82
+ footnoteGap,
83
+ bottomTextMarginTop,
84
+ priceMarginBottom,
85
+ bottomLinksMarginLeft,
86
+ topTextMarginBottom,
87
+ strikeThroughHeight,
88
+ strikeThroughBackground,
89
+ fontColor,
90
+ dividerColor
91
+ } = useThemeTokens('PriceLockup', priceLockupTokens, variant)
92
+
93
+ const priceString = String(price)
94
+ const lastDotPosition = priceString.lastIndexOf('.')
95
+ const lastCommaPosition = priceString.lastIndexOf(',')
96
+ const [separator, separatorPosition] =
97
+ lastDotPosition > lastCommaPosition ? ['.', lastDotPosition] : [',', lastCommaPosition]
98
+
99
+ // If the separator is at the fourth character from the end of the string or more, it's most probably
100
+ // a part of the amount, and the cents are not included in the price string
101
+ const hasCents = separatorPosition !== -1 && separatorPosition >= priceString.length - 3
102
+ const amount = hasCents ? priceString.substring(0, separatorPosition) : priceString
103
+ const cents = hasCents ? priceString.substring(separatorPosition + 1) : null
104
+
105
+ const color = strikeThrough ? strikeThroughBackground : fontColor
106
+
107
+ const renderTypography = (value, tokens) => (
108
+ <Typography tokens={{ ...tokens, color }}>{value}</Typography>
109
+ )
110
+
111
+ const renderCurrencySymbol = () =>
112
+ renderTypography(`${currencySymbol}`, typographyTokens.dollarSign[size])
113
+
114
+ const renderFootnoteLinks = () =>
115
+ footnoteLinks && footnoteLinks.length > 0 ? (
116
+ <FootnoteLink number={footnoteLinks} onClick={onClickFootnote} />
117
+ ) : null
118
+
119
+ const renderAmount = () => {
120
+ const amountComponent = renderTypography(amount, typographyTokens.amount[size])
121
+ if (strikeThrough) {
122
+ return (
123
+ <>
124
+ <A11yText text={a11yText} />
125
+ <StrikeThroughContainer
126
+ strikeThroughHeight={`${strikeThroughHeight}px`}
127
+ strikeThroughBackground={strikeThroughBackground}
128
+ >
129
+ {amountComponent}
130
+ </StrikeThroughContainer>
131
+ </>
132
+ )
133
+ }
134
+
135
+ return amountComponent
136
+ }
137
+
138
+ const renderPrice = () => (
139
+ <>
140
+ <PriceContainer priceMarginBottom={`${priceMarginBottom}px`}>
141
+ {signDirection === 'left' && renderCurrencySymbol()}
142
+ {renderAmount()}
143
+ {cents && renderTypography(`${separator}${cents}`, typographyTokens.cents[size])}
144
+ {signDirection === 'right' && <>&nbsp;{renderCurrencySymbol()}</>}
145
+ {rateText && (
146
+ <RateTextContainer>
147
+ {renderTypography(rateText, typographyTokens.rate[size])}
148
+ </RateTextContainer>
149
+ )}
150
+ {!bottomText && footnoteLinks.length <= 3 && (
151
+ <BottomLinksContainer bottomLinksMarginLeft={`${bottomLinksMarginLeft}px`}>
152
+ {renderFootnoteLinks()}
153
+ </BottomLinksContainer>
154
+ )}
155
+ </PriceContainer>
156
+ {!bottomText && footnoteLinks.length > 3 && renderFootnoteLinks()}
157
+ </>
158
+ )
159
+
160
+ const renderFootnoteContent = () => (
161
+ <>
162
+ <FootnoteContainer
163
+ footnoteMarginTop={`${footnoteMarginTop}px`}
164
+ footnoteGap={`${footnoteGap}px`}
165
+ >
166
+ <BottomTextContainer bottomTextMarginTop={`${bottomTextMarginTop}px`}>
167
+ {renderTypography(bottomText, typographyTokens.bottomText[size])}
168
+ </BottomTextContainer>
169
+ {footnoteLinks.length <= 3 && renderFootnoteLinks()}
170
+ </FootnoteContainer>
171
+ {footnoteLinks.length > 3 && renderFootnoteLinks()}
172
+ </>
173
+ )
174
+
175
+ if (strikeThrough && !a11yText) {
176
+ warn('PriceLockup', 'a11yText must be provided with strikethrough pricing')
177
+ }
178
+
179
+ return (
180
+ <PriceLockupContainer {...selectProps(rest)}>
181
+ {topText && (
182
+ <TopTextContainer topTextMarginBottom={`${topTextMarginBottom}px`}>
183
+ {renderTypography(topText, typographyTokens.topText[size])}
184
+ </TopTextContainer>
185
+ )}
186
+ {renderPrice()}
187
+ {bottomText && (
188
+ <Divider testID="price-lockup-divider" role="separator" tokens={{ color: dividerColor }} />
189
+ )}
190
+ {bottomText && renderFootnoteContent()}
191
+ </PriceLockupContainer>
192
+ )
193
+ }
194
+
195
+ PriceLockup.propTypes = {
196
+ ...selectedSystemPropTypes,
197
+ size: PropTypes.oneOf(['small', 'medium', 'large']),
198
+ currencySymbol: PropTypes.string,
199
+ topText: PropTypes.string,
200
+ price: PropTypes.string.isRequired,
201
+ rateText: PropTypes.string,
202
+ bottomText: PropTypes.string,
203
+ signDirection: PropTypes.oneOf(['right', 'left']),
204
+ footnoteLinks: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string])),
205
+ onClickFootnote: PropTypes.func,
206
+ strikeThrough: PropTypes.bool,
207
+ a11yText: PropTypes.string
208
+ }
209
+
210
+ export default PriceLockup
@@ -0,0 +1,3 @@
1
+ import PriceLockup from './PriceLockup'
2
+
3
+ export default PriceLockup
@@ -0,0 +1,58 @@
1
+ import palette from '@telus-uds/palette-allium/build/rn/palette'
2
+
3
+ const {
4
+ fontSize: { size14, size16, size20, size28, size36, size40, size64 },
5
+ lineHeight: {
6
+ ratio1to1,
7
+ ratio10to7,
8
+ ratio3to2,
9
+ ratio8to5,
10
+ ratio5to4,
11
+ ratio6to5,
12
+ ratio9to8,
13
+ ratio4to3,
14
+ ratio8to7
15
+ },
16
+ letterSpacing: { condensed }
17
+ } = palette
18
+
19
+ const typographyTokens = {
20
+ topText: {
21
+ small: { fontSize: size14, lineHeight: ratio10to7 },
22
+ medium: { fontSize: size16, lineHeight: ratio3to2 },
23
+ large: { fontSize: size20, lineHeight: ratio8to5 }
24
+ },
25
+ dollarSign: {
26
+ small: { fontSize: size16, lineHeight: ratio5to4 },
27
+ medium: { fontSize: size20, lineHeight: ratio6to5 },
28
+ large: { fontSize: size36, lineHeight: ratio9to8 }
29
+ },
30
+ // TODO - fontWeight should have its own const on palette
31
+ amount: {
32
+ small: { fontSize: size28, lineHeight: ratio1to1, letterSpacing: condensed, fontWeight: '300' },
33
+ medium: {
34
+ fontSize: size40,
35
+ lineHeight: ratio1to1,
36
+ letterSpacing: condensed,
37
+ fontWeight: '300'
38
+ },
39
+ large: { fontSize: size64, lineHeight: ratio1to1, letterSpacing: condensed, fontWeight: '300' }
40
+ },
41
+ cents: {
42
+ small: { fontSize: size16, lineHeight: ratio4to3 },
43
+ medium: { fontSize: size20, lineHeight: ratio6to5 },
44
+ large: { fontSize: size36, lineHeight: ratio9to8 }
45
+ },
46
+ rate: {
47
+ small: { fontSize: size14, lineHeight: ratio8to7 },
48
+ medium: { fontSize: size16, lineHeight: ratio5to4 },
49
+ large: { fontSize: size20, lineHeight: ratio8to5 }
50
+ },
51
+ bottomText: {
52
+ small: { fontSize: size14, lineHeight: ratio10to7 },
53
+ medium: { fontSize: size16, lineHeight: ratio3to2 },
54
+ large: { fontSize: size20, lineHeight: ratio8to5 }
55
+ }
56
+ }
57
+
58
+ export default typographyTokens
@@ -0,0 +1,77 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { selectSystemProps } from '@telus-uds/components-base'
4
+ import { viewports } from '@telus-uds/system-constants'
5
+ import { htmlAttrs } from '../utils'
6
+
7
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
8
+
9
+ const staticStyles = {
10
+ image: { display: 'block', width: '100%' }
11
+ }
12
+
13
+ /**
14
+ * Provide different image sources for different screen sizes.
15
+ */
16
+ const ResponsiveImage = ({
17
+ xsSrc,
18
+ smSrc,
19
+ mdSrc,
20
+ lgSrc,
21
+ xlSrc,
22
+ fallbackSrc,
23
+ alt,
24
+ loading = 'eager',
25
+ ...rest
26
+ }) => {
27
+ return (
28
+ <picture {...selectProps(rest)}>
29
+ <source srcSet={xlSrc} media={`(min-width: ${viewports.map.get(viewports.xl)}px)`} />
30
+ <source srcSet={lgSrc} media={`(min-width: ${viewports.map.get(viewports.lg)}px)`} />
31
+ <source srcSet={mdSrc} media={`(min-width: ${viewports.map.get(viewports.md)}px)`} />
32
+ <source srcSet={smSrc} media={`(min-width: ${viewports.map.get(viewports.sm)}px)`} />
33
+ <source srcSet={xsSrc} media={`(max-width: ${viewports.map.get(viewports.sm) - 1}px)`} />
34
+ <img src={fallbackSrc} alt={alt} style={staticStyles.image} loading={loading} />
35
+ </picture>
36
+ )
37
+ }
38
+
39
+ ResponsiveImage.propTypes = {
40
+ ...selectedSystemPropTypes,
41
+ /**
42
+ * The src attribute used for screen widths up to 575px
43
+ */
44
+ xsSrc: PropTypes.string.isRequired,
45
+ /**
46
+ * The src attribute used for screen widths greater than 576px
47
+ */
48
+ smSrc: PropTypes.string.isRequired,
49
+ /**
50
+ * The src attribute used for screen widths greater than 768px
51
+ */
52
+ mdSrc: PropTypes.string,
53
+ /**
54
+ * The src attribute used for screen widths greater than 992px
55
+ */
56
+ lgSrc: PropTypes.string,
57
+ /**
58
+ * The src attribute used for screen widths greater than 1200px
59
+ */
60
+ xlSrc: PropTypes.string,
61
+ /**
62
+ * The src attribute used for browsers that don't support responsive images (InternetExplorer)
63
+ */
64
+ fallbackSrc: PropTypes.string.isRequired,
65
+ /**
66
+ * The alt attribute for the HTML img element. Setting this attribute to an empty string (alt="") indicates that this image is not a key part of the content, and that non-visual browsers may omit it from rendering.
67
+ */
68
+ alt: PropTypes.string.isRequired,
69
+ /**
70
+ * Loading strategy.
71
+ * @default 'eager'
72
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading
73
+ */
74
+ loading: PropTypes.oneOf(['eager', 'lazy'])
75
+ }
76
+
77
+ export default ResponsiveImage
@@ -0,0 +1,3 @@
1
+ import ResponsiveImage from './ResponsiveImage'
2
+
3
+ export default ResponsiveImage
@@ -1,7 +1,6 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { selectSystemProps, Typography, useThemeTokens } from '@telus-uds/components-base'
4
- // import palette from '@telus-uds/palette-allium/build/web/palette'
5
4
  import styled from 'styled-components'
6
5
  import { htmlAttrs } from '../utils'
7
6
 
@@ -0,0 +1,66 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import styled from 'styled-components'
4
+ import { selectSystemProps } from '@telus-uds/components-base'
5
+
6
+ import { htmlAttrs, useTypographyTheme } from '../utils'
7
+
8
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
9
+
10
+ const StyledSpan = styled.span`${({ flex }) => (flex ? 'display: inline-flex' : '')}};`
11
+
12
+ /**
13
+ * Text as an HTML ```<span>``` element.
14
+ *
15
+ * Span may be used in cases where an inline span or direct access to HTML attributes is required.
16
+ * In most cases, `Typography` should be used for text, or Paragraph for body text.
17
+ */
18
+ const Span = ({ children, variant, tokens, testID, flex, ...rest }) => {
19
+ const style = useTypographyTheme(variant, tokens)
20
+ return (
21
+ <StyledSpan data-testid={testID} flex={flex} style={style} {...selectProps(rest)}>
22
+ {children}
23
+ </StyledSpan>
24
+ )
25
+ }
26
+
27
+ Span.propTypes = {
28
+ ...selectedSystemPropTypes,
29
+ children: PropTypes.node.isRequired,
30
+ testID: PropTypes.string,
31
+ /**
32
+ * Sets display to inline-flex so that children are laid out using the flex model.
33
+ * Use this if the span contains children that expect to be inside a flex container.
34
+ */
35
+ flex: PropTypes.bool,
36
+ /**
37
+ * Span takes the same tokens overrides as Typography
38
+ */
39
+ tokens: PropTypes.oneOf([PropTypes.object, PropTypes.func]),
40
+ /**
41
+ * Span can take any of Typography's theme variants
42
+ */
43
+ variant: PropTypes.exact({
44
+ bold: PropTypes.bool,
45
+ colour: PropTypes.oneOf(['secondary', 'tertiary']),
46
+ compact: PropTypes.bool,
47
+ inverse: PropTypes.bool,
48
+ size: PropTypes.oneOf([
49
+ 'micro',
50
+ 'small',
51
+ 'large',
52
+ 'eyebrow',
53
+ 'h1',
54
+ 'h2',
55
+ 'h3',
56
+ 'h4',
57
+ 'h5',
58
+ 'h6',
59
+ 'display1',
60
+ 'display2'
61
+ ]),
62
+ weight: PropTypes.oneOf(['semibold', 'bold'])
63
+ })
64
+ }
65
+
66
+ export default Span
@@ -0,0 +1,3 @@
1
+ import Span from './Span'
2
+
3
+ export default Span
package/src/index.js CHANGED
@@ -1,5 +1,15 @@
1
1
  export { default as Badge } from './Badge'
2
+ export { default as OrderedList } from './OrderedList'
3
+ export { default as PreviewCard } from './PreviewCard'
4
+ export { default as ResponsiveImage } from './ResponsiveImage'
2
5
  export { default as Ribbon } from './Ribbon'
6
+ export { default as DatePicker } from './DatePicker'
7
+ export { default as Span } from './Span'
8
+ export { default as ExpandCollapseMini } from './ExpandCollapseMini'
9
+ export { default as Callout } from './Callout'
10
+ export { default as PriceLockup } from './PriceLockup'
11
+ export { default as Footnote } from './Footnote'
3
12
  export { transformGradient } from './utils'
13
+ export { default as Breadcrumbs } from './Breadcrumbs'
4
14
 
5
15
  export * from './baseExports'
@@ -0,0 +1,90 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import styled from 'styled-components'
4
+
5
+ import ResponsiveImage from '../../ResponsiveImage'
6
+
7
+ const selectFullBleedContentProps = ({
8
+ alt,
9
+ height,
10
+ loading,
11
+ src,
12
+ width,
13
+ fallbackSrc = src,
14
+ lgSrc = src,
15
+ mdSrc = src,
16
+ smSrc = src,
17
+ xlSrc = src,
18
+ xsSrc = src
19
+ }) => ({
20
+ alt,
21
+ height,
22
+ loading,
23
+ src,
24
+ width,
25
+ fallbackSrc,
26
+ lgSrc,
27
+ mdSrc,
28
+ smSrc,
29
+ xlSrc,
30
+ xsSrc
31
+ })
32
+
33
+ const FullBleedContentContainer = styled.div(
34
+ ({
35
+ borderBottomLeftRadius,
36
+ borderBottomRightRadius,
37
+ borderTopLeftRadius,
38
+ borderTopRightRadius
39
+ }) => ({
40
+ overflow: 'hidden',
41
+ borderBottomLeftRadius,
42
+ borderBottomRightRadius,
43
+ borderTopLeftRadius,
44
+ borderTopRightRadius
45
+ })
46
+ )
47
+
48
+ /**
49
+ * Full bleed content component can accept either a single source,
50
+ * a number of sources corresponding to the `ResponsiveImage` component API,
51
+ * or a custom component.
52
+ */
53
+ const FullBleedContent = ({ borderRadius, content, ...rest }) => (
54
+ <FullBleedContentContainer {...borderRadius}>
55
+ {content ?? <ResponsiveImage {...selectFullBleedContentProps(rest)} />}
56
+ </FullBleedContentContainer>
57
+ )
58
+
59
+ FullBleedContent.propTypes = {
60
+ /**
61
+ * Content border radius matching the edge values on the parent card.
62
+ */
63
+ borderRadius: PropTypes.shape({
64
+ borderBottomLeftRadius: PropTypes.number,
65
+ borderBottomRightRadius: PropTypes.number,
66
+ borderTopLeftRadius: PropTypes.number,
67
+ borderTopRightRadius: PropTypes.number
68
+ }),
69
+ /**
70
+ * Custom JSX to be used for rendering the content (defaults to `ResponsiveImage` receiving other props).
71
+ */
72
+ content: PropTypes.node,
73
+ /**
74
+ * Image source.
75
+ */
76
+ src: PropTypes.string,
77
+ /**
78
+ * Also accept props for `ResponsiveImage`...
79
+ */
80
+ ...ResponsiveImage.propTypes,
81
+ /**
82
+ * ...but make the required ones optional.
83
+ */
84
+ alt: PropTypes.string,
85
+ xsSrc: PropTypes.string,
86
+ smSrc: PropTypes.string,
87
+ fallbackSrc: PropTypes.string
88
+ }
89
+
90
+ export default FullBleedContent
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Gets the border radius values for an item of content that goes right up to
3
+ * the edges of its container, to the top, bottom, left or right of other content.
4
+ *
5
+ * Gives the full bleed item the same border radius as the container on the corners
6
+ * that are flush with the corners of the container.
7
+ *
8
+ * @param {number} borderRadius
9
+ * @param {'top'|'bottom'|'left'|'right'} position
10
+ * @param {boolean} hasFooter
11
+ * @returns
12
+ */
13
+ const getFullBleedBorderRadius = (borderRadius, position, hasFooter = false) => {
14
+ const innerBorderRadius = {
15
+ borderBottomLeftRadius: 0,
16
+ borderBottomRightRadius: 0,
17
+ borderTopLeftRadius: 0,
18
+ borderTopRightRadius: 0
19
+ }
20
+ if (position && position !== 'none') {
21
+ if (borderRadius) {
22
+ // Depending on the position of the image, we need to round some
23
+ // corners, but not the others
24
+ switch (position) {
25
+ case 'bottom':
26
+ if (!hasFooter) {
27
+ innerBorderRadius.borderBottomLeftRadius = borderRadius
28
+ innerBorderRadius.borderBottomRightRadius = borderRadius
29
+ }
30
+ break
31
+ case 'left':
32
+ if (!hasFooter) {
33
+ innerBorderRadius.borderBottomLeftRadius = borderRadius
34
+ }
35
+ innerBorderRadius.borderTopLeftRadius = borderRadius
36
+ break
37
+ case 'right':
38
+ if (!hasFooter) {
39
+ innerBorderRadius.borderBottomRightRadius = borderRadius
40
+ }
41
+ innerBorderRadius.borderTopRightRadius = borderRadius
42
+ break
43
+ case 'top':
44
+ innerBorderRadius.borderTopLeftRadius = borderRadius
45
+ innerBorderRadius.borderTopRightRadius = borderRadius
46
+ break
47
+ default:
48
+ break
49
+ }
50
+ }
51
+ }
52
+ return innerBorderRadius
53
+ }
54
+
55
+ export default getFullBleedBorderRadius
@@ -0,0 +1,6 @@
1
+ import FullBleedContent from './FullBleedContent'
2
+
3
+ export default FullBleedContent
4
+
5
+ export { default as getFullBleedBorderRadius } from './getFullBleedBorderRadius'
6
+ export { default as useFullBleedContentProps } from './useFullBleedContentProps'
@@ -0,0 +1,63 @@
1
+ import { useResponsiveProp } from '@telus-uds/components-base'
2
+
3
+ const getContentStackDirection = (fullBleedContentPosition) => {
4
+ switch (fullBleedContentPosition) {
5
+ case 'left':
6
+ return 'row-reverse'
7
+ case 'right':
8
+ return 'row'
9
+ case 'top':
10
+ return 'column-reverse'
11
+ default:
12
+ return 'column'
13
+ }
14
+ }
15
+
16
+ const getContentStackAlign = (fullBleedContentAlign) => {
17
+ switch (fullBleedContentAlign) {
18
+ case 'center':
19
+ return 'center'
20
+
21
+ case 'end':
22
+ case 'flex-end':
23
+ return 'flex-end'
24
+
25
+ case 'start':
26
+ case 'flex-start':
27
+ return 'flex-start'
28
+
29
+ default:
30
+ return 'stretch'
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Resolves a set of `FullBleedContent` props into the variables a container needs to
36
+ * correctly position a `FullBleedContent` component for the current viewport.
37
+ *
38
+ * @param {object} [fullBleedContent] - a set of valid proptypes for FullBleedContent
39
+ * @returns
40
+ */
41
+ const useFullBleedContentProps = (fullBleedContent) => {
42
+ const {
43
+ align: fullBleedContentAlignProp,
44
+ position: fullBleedContentPositionProp,
45
+ ...fullBleedContentProps
46
+ } = fullBleedContent ?? {
47
+ position: 'none'
48
+ }
49
+ const fullBleedContentPosition = useResponsiveProp(fullBleedContentPositionProp, 'none')
50
+ const contentStackDirection = getContentStackDirection(fullBleedContentPosition)
51
+
52
+ const fullBleedContentAlign = useResponsiveProp(fullBleedContentAlignProp, 'stretch')
53
+ const contentStackAlign = getContentStackAlign(fullBleedContentAlign)
54
+
55
+ return {
56
+ contentStackAlign,
57
+ contentStackDirection,
58
+ fullBleedContentPosition,
59
+ fullBleedContentProps
60
+ }
61
+ }
62
+
63
+ export default useFullBleedContentProps
@@ -1,4 +1,8 @@
1
1
  import { transformGradient } from './transforms'
2
+ import useTypographyTheme from './useTypographyTheme'
2
3
  import htmlAttrs from './htmlAttrs'
4
+ import { warn } from './logger'
5
+ import media from './media'
6
+ import renderStructuredContent from './renderStructuredContent'
3
7
 
4
- export { htmlAttrs, transformGradient }
8
+ export { htmlAttrs, transformGradient, useTypographyTheme, warn, media, renderStructuredContent }