@telus-uds/components-web 2.33.2 → 2.34.1

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 (192) hide show
  1. package/CHANGELOG.md +29 -3
  2. package/lib/Badge/Badge.js +4 -2
  3. package/lib/BlockQuote/BlockQuote.js +4 -2
  4. package/lib/Breadcrumbs/Breadcrumbs.js +7 -5
  5. package/lib/Breadcrumbs/Item/Item.js +2 -13
  6. package/lib/Callout/Callout.js +4 -2
  7. package/lib/Card/Card.js +3 -5
  8. package/lib/Card/CardContent.js +4 -2
  9. package/lib/Countdown/Countdown.js +2 -6
  10. package/lib/Countdown/Segment.js +4 -2
  11. package/lib/DatePicker/CalendarContainer.js +2 -2
  12. package/lib/DatePicker/DatePicker.js +21 -35
  13. package/lib/Disclaimer/Disclaimer.js +4 -2
  14. package/lib/ExpandCollapseMini/ExpandCollapseMini.js +5 -11
  15. package/lib/ExpandCollapseMini/ExpandCollapseMiniControl.js +4 -2
  16. package/lib/Footnote/Footnote.js +32 -37
  17. package/lib/Footnote/FootnoteLink.js +9 -6
  18. package/lib/IconButton/IconButton.js +4 -11
  19. package/lib/Image/Image.js +5 -3
  20. package/lib/List/ListItem.js +2 -7
  21. package/lib/NavigationBar/NavigationBar.js +8 -18
  22. package/lib/NavigationBar/NavigationItem.js +4 -9
  23. package/lib/NavigationBar/NavigationSubMenu.js +8 -7
  24. package/lib/NavigationBar/index.js +2 -0
  25. package/lib/OptimizeImage/OptimizeImage.js +8 -8
  26. package/lib/OrderedList/Item.js +3 -9
  27. package/lib/OrderedList/OrderedList.js +5 -13
  28. package/lib/OrderedList/OrderedListBase.js +3 -8
  29. package/lib/Paragraph/Paragraph.js +5 -3
  30. package/lib/PreviewCard/PreviewCard.js +3 -5
  31. package/lib/PriceLockup/PriceLockup.js +4 -2
  32. package/lib/Progress/ProgressBar.js +4 -2
  33. package/lib/QuantitySelector/QuantitySelector.js +21 -24
  34. package/lib/QuantitySelector/SideButton.js +12 -20
  35. package/lib/ResponsiveImage/ResponsiveImage.js +4 -2
  36. package/lib/Ribbon/Ribbon.js +4 -2
  37. package/lib/SkeletonProvider/SkeletonImage.js +5 -3
  38. package/lib/SkeletonProvider/SkeletonProvider.js +3 -5
  39. package/lib/SkeletonProvider/SkeletonTypography.js +5 -3
  40. package/lib/Span/Span.js +5 -3
  41. package/lib/Spinner/Spinner.js +4 -2
  42. package/lib/Spinner/SpinnerContent.js +4 -2
  43. package/lib/StoryCard/StoryCard.js +3 -5
  44. package/lib/Table/Body.js +4 -2
  45. package/lib/Table/Cell.js +5 -3
  46. package/lib/Table/Header.js +6 -6
  47. package/lib/Table/Row.js +6 -6
  48. package/lib/Table/SubHeading.js +6 -6
  49. package/lib/Table/Table.js +6 -8
  50. package/lib/TermsAndConditions/ExpandCollapse.js +2 -7
  51. package/lib/TermsAndConditions/TermsAndConditions.js +5 -14
  52. package/lib/Testimonial/Testimonial.js +4 -2
  53. package/lib/Toast/Toast.js +4 -2
  54. package/lib/Video/Video.js +19 -55
  55. package/lib/VideoPicker/VideoPicker.js +38 -9
  56. package/lib/VideoPicker/VideoPickerPlayer.js +4 -2
  57. package/lib/VideoPicker/VideoPickerThumbnail.js +4 -2
  58. package/lib/VideoPicker/VideoSlider.js +7 -7
  59. package/lib/WaffleGrid/WaffleGrid.js +4 -2
  60. package/lib/WebVideo/WebVideo.js +51 -13
  61. package/lib/WebVideo/utils/index.js +58 -0
  62. package/lib/baseExports.js +6 -0
  63. package/lib/utils/theming/with-client-theme.js +1 -1
  64. package/lib/utils/theming/with-server-theme.js +1 -1
  65. package/lib-module/Badge/Badge.js +4 -2
  66. package/lib-module/BlockQuote/BlockQuote.js +4 -2
  67. package/lib-module/Breadcrumbs/Breadcrumbs.js +7 -5
  68. package/lib-module/Breadcrumbs/Item/Item.js +2 -11
  69. package/lib-module/Callout/Callout.js +4 -2
  70. package/lib-module/Card/Card.js +2 -3
  71. package/lib-module/Card/CardContent.js +4 -2
  72. package/lib-module/Countdown/Countdown.js +2 -3
  73. package/lib-module/Countdown/Segment.js +4 -2
  74. package/lib-module/DatePicker/CalendarContainer.js +2 -2
  75. package/lib-module/DatePicker/DatePicker.js +21 -33
  76. package/lib-module/Disclaimer/Disclaimer.js +4 -2
  77. package/lib-module/ExpandCollapseMini/ExpandCollapseMini.js +5 -9
  78. package/lib-module/ExpandCollapseMini/ExpandCollapseMiniControl.js +4 -2
  79. package/lib-module/Footnote/Footnote.js +31 -36
  80. package/lib-module/Footnote/FootnoteLink.js +9 -7
  81. package/lib-module/IconButton/IconButton.js +4 -9
  82. package/lib-module/Image/Image.js +5 -3
  83. package/lib-module/List/ListItem.js +2 -5
  84. package/lib-module/NavigationBar/NavigationBar.js +9 -17
  85. package/lib-module/NavigationBar/NavigationItem.js +5 -8
  86. package/lib-module/NavigationBar/NavigationSubMenu.js +9 -6
  87. package/lib-module/NavigationBar/index.js +2 -0
  88. package/lib-module/OptimizeImage/OptimizeImage.js +8 -6
  89. package/lib-module/OrderedList/Item.js +3 -7
  90. package/lib-module/OrderedList/OrderedList.js +6 -12
  91. package/lib-module/OrderedList/OrderedListBase.js +3 -6
  92. package/lib-module/Paragraph/Paragraph.js +6 -4
  93. package/lib-module/PreviewCard/PreviewCard.js +2 -3
  94. package/lib-module/PriceLockup/PriceLockup.js +4 -2
  95. package/lib-module/Progress/ProgressBar.js +4 -2
  96. package/lib-module/QuantitySelector/QuantitySelector.js +22 -23
  97. package/lib-module/QuantitySelector/SideButton.js +13 -21
  98. package/lib-module/ResponsiveImage/ResponsiveImage.js +4 -2
  99. package/lib-module/Ribbon/Ribbon.js +4 -2
  100. package/lib-module/SkeletonProvider/SkeletonImage.js +5 -3
  101. package/lib-module/SkeletonProvider/SkeletonProvider.js +3 -3
  102. package/lib-module/SkeletonProvider/SkeletonTypography.js +5 -3
  103. package/lib-module/Span/Span.js +6 -4
  104. package/lib-module/Spinner/Spinner.js +4 -2
  105. package/lib-module/Spinner/SpinnerContent.js +4 -2
  106. package/lib-module/StoryCard/StoryCard.js +2 -3
  107. package/lib-module/Table/Body.js +4 -2
  108. package/lib-module/Table/Cell.js +5 -3
  109. package/lib-module/Table/Header.js +6 -4
  110. package/lib-module/Table/Row.js +6 -4
  111. package/lib-module/Table/SubHeading.js +6 -4
  112. package/lib-module/Table/Table.js +6 -6
  113. package/lib-module/TermsAndConditions/ExpandCollapse.js +2 -5
  114. package/lib-module/TermsAndConditions/TermsAndConditions.js +5 -12
  115. package/lib-module/Testimonial/Testimonial.js +4 -2
  116. package/lib-module/Toast/Toast.js +4 -2
  117. package/lib-module/Video/Video.js +19 -53
  118. package/lib-module/VideoPicker/VideoPicker.js +37 -8
  119. package/lib-module/VideoPicker/VideoPickerPlayer.js +4 -2
  120. package/lib-module/VideoPicker/VideoPickerThumbnail.js +4 -2
  121. package/lib-module/VideoPicker/VideoSlider.js +7 -5
  122. package/lib-module/WaffleGrid/WaffleGrid.js +4 -2
  123. package/lib-module/WebVideo/WebVideo.js +51 -11
  124. package/lib-module/WebVideo/utils/index.js +50 -0
  125. package/lib-module/baseExports.js +1 -1
  126. package/lib-module/utils/theming/with-client-theme.js +2 -2
  127. package/lib-module/utils/theming/with-server-theme.js +2 -2
  128. package/package.json +3 -3
  129. package/src/Badge/Badge.jsx +5 -2
  130. package/src/BlockQuote/BlockQuote.jsx +120 -112
  131. package/src/Breadcrumbs/Breadcrumbs.jsx +84 -77
  132. package/src/Breadcrumbs/Item/Item.jsx +2 -9
  133. package/src/Callout/Callout.jsx +37 -40
  134. package/src/Card/Card.jsx +2 -3
  135. package/src/Card/CardContent.jsx +19 -14
  136. package/src/Countdown/Countdown.jsx +72 -71
  137. package/src/Countdown/Segment.jsx +40 -28
  138. package/src/DatePicker/CalendarContainer.jsx +2 -2
  139. package/src/DatePicker/DatePicker.jsx +21 -34
  140. package/src/Disclaimer/Disclaimer.jsx +5 -3
  141. package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +37 -40
  142. package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +52 -44
  143. package/src/Footnote/Footnote.jsx +32 -38
  144. package/src/Footnote/FootnoteLink.jsx +45 -49
  145. package/src/IconButton/IconButton.jsx +19 -20
  146. package/src/Image/Image.jsx +40 -43
  147. package/src/List/ListItem.jsx +3 -5
  148. package/src/NavigationBar/NavigationBar.jsx +9 -18
  149. package/src/NavigationBar/NavigationItem.jsx +6 -5
  150. package/src/NavigationBar/NavigationSubMenu.jsx +104 -88
  151. package/src/NavigationBar/index.js +3 -0
  152. package/src/OptimizeImage/OptimizeImage.jsx +48 -41
  153. package/src/OrderedList/Item.jsx +34 -35
  154. package/src/OrderedList/OrderedList.jsx +4 -6
  155. package/src/OrderedList/OrderedListBase.jsx +2 -3
  156. package/src/Paragraph/Paragraph.jsx +21 -16
  157. package/src/PreviewCard/PreviewCard.jsx +2 -3
  158. package/src/PriceLockup/PriceLockup.jsx +143 -136
  159. package/src/Progress/ProgressBar.jsx +11 -3
  160. package/src/QuantitySelector/QuantitySelector.jsx +162 -154
  161. package/src/QuantitySelector/SideButton.jsx +52 -56
  162. package/src/ResponsiveImage/ResponsiveImage.jsx +16 -22
  163. package/src/Ribbon/Ribbon.jsx +85 -83
  164. package/src/SkeletonProvider/SkeletonImage.jsx +24 -15
  165. package/src/SkeletonProvider/SkeletonProvider.jsx +3 -3
  166. package/src/SkeletonProvider/SkeletonTypography.jsx +18 -13
  167. package/src/Span/Span.jsx +7 -5
  168. package/src/Spinner/Spinner.jsx +86 -79
  169. package/src/Spinner/SpinnerContent.jsx +31 -33
  170. package/src/StoryCard/StoryCard.jsx +2 -3
  171. package/src/Table/Body.jsx +5 -3
  172. package/src/Table/Cell.jsx +77 -67
  173. package/src/Table/Header.jsx +7 -5
  174. package/src/Table/Row.jsx +7 -5
  175. package/src/Table/SubHeading.jsx +7 -5
  176. package/src/Table/Table.jsx +6 -6
  177. package/src/TermsAndConditions/ExpandCollapse.jsx +2 -6
  178. package/src/TermsAndConditions/TermsAndConditions.jsx +5 -13
  179. package/src/Testimonial/Testimonial.jsx +148 -137
  180. package/src/Toast/Toast.jsx +68 -63
  181. package/src/Video/Video.jsx +25 -45
  182. package/src/VideoPicker/VideoPicker.jsx +114 -75
  183. package/src/VideoPicker/VideoPickerPlayer.jsx +13 -9
  184. package/src/VideoPicker/VideoPickerThumbnail.jsx +102 -94
  185. package/src/VideoPicker/VideoSlider.jsx +8 -6
  186. package/src/WaffleGrid/WaffleGrid.jsx +36 -40
  187. package/src/WebVideo/WebVideo.jsx +114 -60
  188. package/src/WebVideo/utils/index.js +56 -0
  189. package/src/baseExports.js +1 -0
  190. package/src/utils/theming/with-client-theme.jsx +2 -2
  191. package/src/utils/theming/with-server-theme.jsx +2 -2
  192. package/types/WebVideo.d.ts +2 -1
@@ -1,4 +1,4 @@
1
- import React, { forwardRef, useEffect, useState, useRef } from 'react'
1
+ import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import styled from 'styled-components'
4
4
  import momentPropTypes from 'react-moment-proptypes'
@@ -79,36 +79,37 @@ const validDatePattern = /^([0-2][0-9]|3[0-1])(\/)(0[1-9]|1[0-2])\2(\d{4})$/
79
79
  * - Optimized for keyboard interaction and tablet touch
80
80
  * - Recommended for viewports greater than or equal to 576px
81
81
  */
82
- const DatePicker = forwardRef(
82
+ const DatePicker = React.forwardRef(
83
83
  (
84
84
  {
85
85
  copy = 'en',
86
86
  id,
87
87
  date,
88
88
  feedback,
89
- inline,
89
+ inline = false,
90
90
  isDayDisabled,
91
91
  label,
92
- onDateChange,
92
+ onDateChange = () => {},
93
93
  hint,
94
94
  hintPosition = 'inline',
95
95
  tooltip,
96
96
  tokens,
97
97
  variant = {},
98
98
  validation,
99
- disabled,
100
- prevTestID,
101
- nextTestID,
99
+ disabled = false,
100
+ prevTestID = '',
101
+ nextTestID = '',
102
+ placeholder = 'DD / MM / YYYY',
102
103
  ...rest
103
104
  },
104
105
  ref
105
106
  ) => {
106
- const [inputDate, setInputDate] = useState(date instanceof moment ? date : undefined)
107
- const [inputText, setInputText] = useState(
107
+ const [inputDate, setInputDate] = React.useState(date instanceof moment ? date : undefined)
108
+ const [inputText, setInputText] = React.useState(
108
109
  date instanceof moment ? date.format(dateFormat) : ''
109
110
  )
110
- const textInputRef = useRef()
111
- const [datePickerPosition, setDatePickerPosition] = useState({ left: 0, top: 0 })
111
+ const textInputRef = React.useRef()
112
+ const [datePickerPosition, setDatePickerPosition] = React.useState({ left: 0, top: 0 })
112
113
 
113
114
  useSafeLayoutEffect(() => {
114
115
  const updateDimensions = () => {
@@ -126,10 +127,10 @@ const DatePicker = forwardRef(
126
127
  return () => window.removeEventListener('resize', throttledUpdateDimensions)
127
128
  }, [])
128
129
 
129
- const [isFocused, setIsFocused] = useState(false)
130
- const [isClickedInside, setIsClickedInside] = useState(false)
130
+ const [isFocused, setIsFocused] = React.useState(false)
131
+ const [isClickedInside, setIsClickedInside] = React.useState(false)
131
132
  const getCopy = useCopy({ dictionary, copy })
132
- useEffect(() => {
133
+ React.useEffect(() => {
133
134
  /**
134
135
  * `date` could be passed as `null` to reset the value so explicitly
135
136
  * checking for not being `undefined`
@@ -315,7 +316,7 @@ const DatePicker = forwardRef(
315
316
  copy={copy}
316
317
  feedback={feedback}
317
318
  hint={hint}
318
- placeholder="DD / MM / YYYY"
319
+ placeholder={placeholder}
319
320
  onChange={onChangeInput}
320
321
  onKeyPress={handleOnKeyPress}
321
322
  tooltip={tooltip}
@@ -473,25 +474,11 @@ DatePicker.propTypes = {
473
474
  * This is for automation testing purposes.
474
475
  * Will be added as a `data-testid-next` attribute for example.
475
476
  */
476
- nextTestID: PropTypes.string
477
- }
478
-
479
- DatePicker.defaultProps = {
480
- copy: 'en',
481
- date: undefined,
482
- feedback: undefined,
483
- inline: false,
484
- isDayDisabled: undefined,
485
- label: undefined,
486
- hint: undefined,
487
- hintPosition: 'inline',
488
- tooltip: undefined,
489
- onDateChange: () => {},
490
- validation: undefined,
491
- disabled: false,
492
- tokens: undefined,
493
- prevTestID: '',
494
- nextTestID: ''
477
+ nextTestID: PropTypes.string,
478
+ /**
479
+ * Optional placeholder for the date input. If not set the default value will be `DD / MM / YYYY`
480
+ */
481
+ placeholder: PropTypes.string
495
482
  }
496
483
 
497
484
  export default DatePicker
@@ -24,14 +24,16 @@ const StyledDisclaimer = styled.p(({ fontName, fontWeight, fontSize, ...tokens }
24
24
  * Use Disclaimer to display singular legal statement and must be displayed
25
25
  * immediately adjacent to the related, originating content.
26
26
  */
27
- const Disclaimer = ({ children, ...rest }) => {
27
+ const Disclaimer = React.forwardRef(({ children, ...rest }, ref) => {
28
28
  const themeTokens = useThemeTokens('Disclaimer')
29
29
  return (
30
- <StyledDisclaimer {...selectProps(rest)} {...themeTokens}>
30
+ <StyledDisclaimer ref={ref} {...selectProps(rest)} {...themeTokens}>
31
31
  {children}
32
32
  </StyledDisclaimer>
33
33
  )
34
- }
34
+ })
35
+
36
+ Disclaimer.displayName = 'Disclaimer'
35
37
 
36
38
  Disclaimer.propTypes = {
37
39
  ...selectedSystemPropTypes,
@@ -1,44 +1,46 @@
1
- import React, { forwardRef } from 'react'
1
+ import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { ExpandCollapse, getTokensPropType } from '@telus-uds/components-base'
4
4
  import ExpandCollapseMiniControl from './ExpandCollapseMiniControl'
5
5
 
6
- const ExpandCollapseMini = forwardRef(({ children, onToggle, tokens, nativeID, ...rest }, ref) => {
7
- const handleChange = (openPanels, event) => {
8
- if (typeof onToggle === 'function') {
9
- const isOpen = openPanels.length > 0
10
- onToggle(event, isOpen)
6
+ const ExpandCollapseMini = React.forwardRef(
7
+ ({ children, onToggle = () => {}, tokens = {}, nativeID, ...rest }, ref) => {
8
+ const handleChange = (openPanels, event) => {
9
+ if (typeof onToggle === 'function') {
10
+ const isOpen = openPanels.length > 0
11
+ onToggle(event, isOpen)
12
+ }
11
13
  }
12
- }
13
14
 
14
- return (
15
- <ExpandCollapse onChange={handleChange}>
16
- {(expandProps) => (
17
- <ExpandCollapse.Panel
18
- {...expandProps}
19
- panelId="ExpandCollapseMiniPanel"
20
- variant={{ mini: true }}
21
- controlTokens={{
22
- // Remove unwanted look and feel from ExpandCollapse(background pressed, focus border and text underline)
23
- icon: null,
24
- borderColor: 'transparent',
25
- textLine: 'none',
26
- backgroundColor: 'transparent'
27
- }}
28
- // TODO refactor
29
- // eslint-disable-next-line react/no-unstable-nested-components
30
- control={(pressableState) => (
31
- <ExpandCollapseMiniControl pressableState={pressableState} {...rest} />
32
- )}
33
- controlRef={ref}
34
- nativeID={nativeID}
35
- >
36
- {children}
37
- </ExpandCollapse.Panel>
38
- )}
39
- </ExpandCollapse>
40
- )
41
- })
15
+ return (
16
+ <ExpandCollapse onChange={handleChange} tokens={tokens}>
17
+ {(expandProps) => (
18
+ <ExpandCollapse.Panel
19
+ {...expandProps}
20
+ panelId="ExpandCollapseMiniPanel"
21
+ variant={{ mini: true }}
22
+ controlTokens={{
23
+ // Remove unwanted look and feel from ExpandCollapse(background pressed, focus border and text underline)
24
+ icon: null,
25
+ borderColor: 'transparent',
26
+ textLine: 'none',
27
+ backgroundColor: 'transparent'
28
+ }}
29
+ // TODO refactor
30
+ // eslint-disable-next-line react/no-unstable-nested-components
31
+ control={(pressableState) => (
32
+ <ExpandCollapseMiniControl pressableState={pressableState} {...rest} />
33
+ )}
34
+ controlRef={ref}
35
+ nativeID={nativeID}
36
+ >
37
+ {children}
38
+ </ExpandCollapse.Panel>
39
+ )}
40
+ </ExpandCollapse>
41
+ )
42
+ }
43
+ )
42
44
  ExpandCollapseMini.displayName = 'ExpandCollapseMini'
43
45
 
44
46
  ExpandCollapseMini.propTypes = {
@@ -57,10 +59,5 @@ ExpandCollapseMini.propTypes = {
57
59
  children: PropTypes.node.isRequired,
58
60
  tokens: getTokensPropType('ExpandCollapseMini')
59
61
  }
60
- ExpandCollapseMini.defaultProps = {
61
- onToggle: () => {},
62
- tokens: {},
63
- nativeID: ''
64
- }
65
62
 
66
63
  export default ExpandCollapseMini
@@ -20,56 +20,64 @@ const selectLinkTokens = ({ color, textLine, lineHeight, fontSize }) => ({
20
20
  blockFontSize: fontSize
21
21
  })
22
22
 
23
- const ExpandCollapseMiniControl = ({
24
- pressableState,
25
- collapseTitle,
26
- expandTitle = collapseTitle,
27
- iconPosition = 'right',
28
- tokens,
29
- variant = {},
30
- ...rest
31
- }) => {
32
- const { expanded, hover, focus } = pressableState || {}
33
- // we only want focus outline when focusing, if user is pressing we don't want the border.
34
- const { outerBorderColor } = useThemeTokens('Link', {}, {}, { focus })
35
- const { size, icon, ...themeTokens } = useThemeTokens(
36
- 'ExpandCollapseMiniControl',
37
- tokens,
38
- variant,
39
- { expanded, focus }
40
- )
23
+ const ExpandCollapseMiniControl = React.forwardRef(
24
+ (
25
+ {
26
+ pressableState,
27
+ collapseTitle,
28
+ expandTitle = collapseTitle,
29
+ iconPosition = 'right',
30
+ tokens,
31
+ variant = {},
32
+ ...rest
33
+ },
34
+ ref
35
+ ) => {
36
+ const { expanded, hover, focus } = pressableState || {}
37
+ // we only want focus outline when focusing, if user is pressing we don't want the border.
38
+ const { outerBorderColor } = useThemeTokens('Link', {}, {}, { focus })
39
+ const { size, icon, ...themeTokens } = useThemeTokens(
40
+ 'ExpandCollapseMiniControl',
41
+ tokens,
42
+ variant,
43
+ { expanded, focus }
44
+ )
41
45
 
42
- // Choose hover styles when any part of Control is hoverred
43
- const appearance = { ...variant, hover }
46
+ // Choose hover styles when any part of Control is hoverred
47
+ const appearance = { ...variant, hover }
44
48
 
45
- const getTokens = (linkState) => {
46
- const { hover: linkHover } = linkState || {}
47
- const isHovered = hover || linkHover
48
- if (isHovered) {
49
- // Include vertical icon animation on hover alongside built-in Link theme, the size is size4
50
- return { iconTranslateY: (expanded ? -1 : 1) * size }
49
+ const getTokens = (linkState) => {
50
+ const { hover: linkHover } = linkState || {}
51
+ const isHovered = hover || linkHover
52
+ if (isHovered) {
53
+ // Include vertical icon animation on hover alongside built-in Link theme, the size is size4
54
+ return { iconTranslateY: (expanded ? -1 : 1) * size }
55
+ }
56
+
57
+ return {}
51
58
  }
52
59
 
53
- return {}
60
+ return (
61
+ <Link
62
+ variant={appearance}
63
+ icon={icon}
64
+ iconPosition={iconPosition}
65
+ tokens={(linkState) => ({
66
+ ...getTokens(linkState),
67
+ ...selectLinkTokens(themeTokens),
68
+ outerBorderColor
69
+ })}
70
+ ref={ref}
71
+ {...presentationOnly}
72
+ {...selectProps(rest)}
73
+ >
74
+ {expanded ? expandTitle : collapseTitle}
75
+ </Link>
76
+ )
54
77
  }
78
+ )
55
79
 
56
- return (
57
- <Link
58
- variant={appearance}
59
- icon={icon}
60
- iconPosition={iconPosition}
61
- tokens={(linkState) => ({
62
- ...getTokens(linkState),
63
- ...selectLinkTokens(themeTokens),
64
- outerBorderColor
65
- })}
66
- {...presentationOnly}
67
- {...selectProps(rest)}
68
- >
69
- {expanded ? expandTitle : collapseTitle}
70
- </Link>
71
- )
72
- }
80
+ ExpandCollapseMiniControl.displayName = 'ExpandCollapseMiniControl'
73
81
 
74
82
  ExpandCollapseMiniControl.propTypes = {
75
83
  ...selectedSystemPropTypes,
@@ -1,4 +1,4 @@
1
- import React, { useRef, useEffect, useState, useCallback } from 'react'
1
+ import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import styled, { createGlobalStyle } from 'styled-components'
4
4
  import {
@@ -181,8 +181,8 @@ const StyledCustomContentContainer = styled.div(
181
181
  )
182
182
 
183
183
  const usePrevious = (value) => {
184
- const ref = useRef()
185
- useEffect(() => {
184
+ const ref = React.useRef()
185
+ React.useEffect(() => {
186
186
  ref.current = value
187
187
  })
188
188
  if (ref.current) {
@@ -209,20 +209,20 @@ const usePrevious = (value) => {
209
209
  * - When `Footnote` is open, the inert prop must be set on all children of body excluding the Footnote
210
210
  * - When `Footnote` is closed, focus must return to the initiating element
211
211
  */
212
- const Footnote = (props) => {
213
- const viewport = useViewport()
212
+ const Footnote = React.forwardRef((props, ref) => {
214
213
  const {
215
- copy,
214
+ copy = 'en',
216
215
  number,
217
216
  content,
218
217
  onClose,
219
- isOpen,
218
+ isOpen = false,
220
219
  tokens,
221
220
  variant = {},
222
221
  isMobileFullScreen = true,
223
222
  dictionary = defaultDictionary,
224
223
  ...rest
225
224
  } = props
225
+ const viewport = useViewport()
226
226
  const {
227
227
  footnoteBackground,
228
228
  footnoteBorderTopSizeMd,
@@ -259,24 +259,24 @@ const Footnote = (props) => {
259
259
  closeIcon
260
260
  } = useThemeTokens('Footnote', tokens, variant, { viewport })
261
261
 
262
- const footnoteRef = useRef(null)
263
- const headerRef = useRef(null)
264
- const bodyRef = useRef(null)
265
- const contentRef = useRef(null)
266
- const headingRef = useRef(null)
267
- const [data, setData] = useState({ content: null, number: null })
268
- const [headerHeight, setHeaderHeight] = useState('auto')
269
- const [bodyHeight, setBodyHeight] = useState('auto')
270
- const [isVisible, setIsVisible] = useState(false)
271
- const [isTextVisible, setIsTextVisible] = useState(true)
262
+ const footnoteRef = React.useRef(null)
263
+ const headerRef = React.useRef(null)
264
+ const bodyRef = React.useRef(null)
265
+ const contentRef = React.useRef(null)
266
+ const headingRef = React.useRef(null)
267
+ const [data, setData] = React.useState({ content: null, number: null })
268
+ const [headerHeight, setHeaderHeight] = React.useState('auto')
269
+ const [bodyHeight, setBodyHeight] = React.useState('auto')
270
+ const [isVisible, setIsVisible] = React.useState(false)
271
+ const [isTextVisible, setIsTextVisible] = React.useState(true)
272
272
  const getCopy = useCopy({ dictionary, copy })
273
273
 
274
274
  const prevProps = usePrevious(props)
275
275
  const theme = useTheme()
276
276
  const maxWidth = useResponsiveProp(theme.themeOptions?.contentMaxWidth)
277
- const [isScrollable, setIsScrollable] = useState(false)
277
+ const [isScrollable, setIsScrollable] = React.useState(false)
278
278
 
279
- const closeFootnote = useCallback(
279
+ const closeFootnote = React.useCallback(
280
280
  (event, options) => {
281
281
  onClose(event, options)
282
282
  },
@@ -284,7 +284,7 @@ const Footnote = (props) => {
284
284
  )
285
285
 
286
286
  // Listen for ESCAPE, close button clicks, and clicks outside of the Footnote. Call onClose.
287
- const handleClose = useCallback(
287
+ const handleClose = React.useCallback(
288
288
  (event) => {
289
289
  if (!isVisible) {
290
290
  return
@@ -362,7 +362,7 @@ const Footnote = (props) => {
362
362
  }
363
363
 
364
364
  // Set height of header on mount
365
- useEffect(() => {
365
+ React.useEffect(() => {
366
366
  setHeaderHeight(headerRef.current?.offsetHeight)
367
367
  }, [])
368
368
 
@@ -373,7 +373,7 @@ const Footnote = (props) => {
373
373
  }
374
374
 
375
375
  // Add listeners for mouse clicks outside of Footnote and for ESCAPE key presses
376
- useEffect(() => {
376
+ React.useEffect(() => {
377
377
  if (isOpen) {
378
378
  setIsVisible(true)
379
379
  document.addEventListener('mousedown', handleClose)
@@ -394,13 +394,13 @@ const Footnote = (props) => {
394
394
  }, [handleClose, isOpen])
395
395
 
396
396
  // Set data if opening a new footnote
397
- useEffect(() => {
397
+ React.useEffect(() => {
398
398
  if (isOpen && !prevProps.isOpen) {
399
399
  setData({ content, number })
400
400
  }
401
401
  }, [isOpen, prevProps.isOpen, content, number])
402
402
 
403
- useEffect(() => {
403
+ React.useEffect(() => {
404
404
  if (isOpen && prevProps.isOpen && number !== prevProps.number) {
405
405
  saveCurrentHeight()
406
406
  setIsTextVisible(false)
@@ -408,9 +408,9 @@ const Footnote = (props) => {
408
408
  }, [number, isOpen, prevProps.isOpen, prevProps.number])
409
409
 
410
410
  // Reset footnote on close
411
- useEffect(resetFootnote, [isOpen])
411
+ React.useEffect(resetFootnote, [isOpen])
412
412
 
413
- const getFootnoteBodyContent = useCallback(() => {
413
+ const getFootnoteBodyContent = React.useCallback(() => {
414
414
  if (!data.number || !data.content) {
415
415
  return null
416
416
  }
@@ -460,7 +460,7 @@ const Footnote = (props) => {
460
460
  listPaddingLeft
461
461
  ])
462
462
 
463
- const checkIfScrollable = useCallback(() => {
463
+ const checkIfScrollable = React.useCallback(() => {
464
464
  const footnoteElement = footnoteRef.current
465
465
  if (footnoteElement) {
466
466
  const footnoteViewportHeight = footnoteElement.clientHeight ? footnoteElement.clientHeight : 0
@@ -470,7 +470,7 @@ const Footnote = (props) => {
470
470
  }
471
471
  }, [contentRef, setIsScrollable])
472
472
 
473
- useEffect(() => {
473
+ React.useEffect(() => {
474
474
  if (isOpen) {
475
475
  setTimeout(() => {
476
476
  checkIfScrollable()
@@ -480,7 +480,7 @@ const Footnote = (props) => {
480
480
 
481
481
  return (
482
482
  <Portal>
483
- <div {...selectProps(rest)}>
483
+ <div {...selectProps(rest)} ref={ref}>
484
484
  {isOpen && <GlobalBodyScrollLock />}
485
485
  <StyledFootnote
486
486
  ref={footnoteRef}
@@ -544,7 +544,9 @@ const Footnote = (props) => {
544
544
  </div>
545
545
  </Portal>
546
546
  )
547
- }
547
+ })
548
+
549
+ Footnote.displayName = 'Footnote'
548
550
 
549
551
  const copyShape = PropTypes.shape({
550
552
  close: PropTypes.string.isRequired,
@@ -599,12 +601,4 @@ Footnote.propTypes = {
599
601
  isMobileFullScreen: PropTypes.bool
600
602
  }
601
603
 
602
- Footnote.defaultProps = {
603
- isOpen: false,
604
- number: undefined,
605
- content: undefined,
606
- copy: 'en',
607
- isMobileFullScreen: true
608
- }
609
-
610
604
  export default Footnote
@@ -33,6 +33,10 @@ const StyledSup = styled.sup(
33
33
  }
34
34
  )
35
35
 
36
+ const FootnoteLinkContainer = styled.div`
37
+ display: inline-block;
38
+ `
39
+
36
40
  /**
37
41
  * Use `FootnoteLink` to open `Footnote` component and display related legal content.
38
42
  *
@@ -42,56 +46,52 @@ const StyledSup = styled.sup(
42
46
  * - Avoid using FootnoteLink if there is only one annotation on a page. Consider including
43
47
  * the annotation as part of the content whenever possible.
44
48
  */
45
- const FootnoteLink = ({
46
- copy = 'en',
47
- number = [],
48
- onClick,
49
- fontSize,
50
- tokens,
51
- variant = {},
52
- ...rest
53
- }) => {
54
- const themeTokens = useThemeTokens('FootnoteLink', tokens, variant)
55
- const numbers = Array.isArray(number) ? number : [number]
56
- const refs = numbers.map(() => React.createRef())
57
- const handleClick = (index) => {
58
- onClick(numbers[index], refs[index])
59
- }
60
- const getCopy = useCopy({ dictionary, copy })
61
-
62
- const handleOnClick = (event, index) => {
63
- event.preventDefault()
64
- event.stopPropagation()
65
- handleClick(index)
66
- }
49
+ const FootnoteLink = React.forwardRef(
50
+ ({ copy = 'en', number = [], onClick, fontSize, tokens, variant = {}, ...rest }, ref) => {
51
+ const themeTokens = useThemeTokens('FootnoteLink', tokens, variant)
52
+ const numbers = Array.isArray(number) ? number : [number]
53
+ const refs = numbers.map(() => React.createRef())
54
+ const handleClick = (index) => {
55
+ onClick(numbers[index], refs[index])
56
+ }
57
+ const getCopy = useCopy({ dictionary, copy })
67
58
 
68
- const handleOnKeyDown = (event, index) => {
69
- if (event.key === 'Enter' || event.key === 13) {
59
+ const handleOnClick = (event, index) => {
60
+ event.preventDefault()
61
+ event.stopPropagation()
70
62
  handleClick(index)
71
63
  }
64
+
65
+ const handleOnKeyDown = (event, index) => {
66
+ if (event.key === 'Enter' || event.key === 13) {
67
+ handleClick(index)
68
+ }
69
+ }
70
+
71
+ return (
72
+ <FootnoteLinkContainer ref={ref}>
73
+ {numbers.map((num, index) => (
74
+ <StyledSup
75
+ onKeyDown={(event) => handleOnKeyDown(event, index)}
76
+ role="button"
77
+ aria-label={getCopy('a11yLabel')}
78
+ key={num}
79
+ ref={refs[index]}
80
+ onClick={(event) => handleOnClick(event, index)}
81
+ tabIndex={0}
82
+ {...selectProps(rest)}
83
+ {...themeTokens}
84
+ fontSize={fontSize ?? themeTokens.fontSize}
85
+ >
86
+ {`${num}${index !== numbers.length - 1 ? ',' : ''}`}
87
+ </StyledSup>
88
+ ))}
89
+ </FootnoteLinkContainer>
90
+ )
72
91
  }
92
+ )
73
93
 
74
- return (
75
- <>
76
- {numbers.map((num, index) => (
77
- <StyledSup
78
- onKeyDown={(event) => handleOnKeyDown(event, index)}
79
- role="button"
80
- aria-label={getCopy('a11yLabel')}
81
- key={num}
82
- ref={refs[index]}
83
- onClick={(event) => handleOnClick(event, index)}
84
- tabIndex={0}
85
- {...selectProps(rest)}
86
- {...themeTokens}
87
- fontSize={fontSize ?? themeTokens.fontSize}
88
- >
89
- {`${num}${index !== numbers.length - 1 ? ',' : ''}`}
90
- </StyledSup>
91
- ))}
92
- </>
93
- )
94
- }
94
+ FootnoteLink.displayName = 'FootnoteLink'
95
95
 
96
96
  const copyShape = PropTypes.shape({
97
97
  a11yLabel: PropTypes.string.isRequired
@@ -125,8 +125,4 @@ FootnoteLink.propTypes = {
125
125
  fontSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
126
126
  }
127
127
 
128
- FootnoteLink.defaultProps = {
129
- copy: 'en'
130
- }
131
-
132
128
  export default FootnoteLink