@telus-uds/components-web 2.20.1 → 2.21.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 CHANGED
@@ -1,12 +1,26 @@
1
1
  # Change Log - @telus-uds/components-web
2
2
 
3
- This log was last generated on Mon, 16 Oct 2023 22:48:33 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 19 Oct 2023 00:22:35 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 2.21.0
8
+
9
+ Thu, 19 Oct 2023 00:22:35 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - Changes to the footnote component to align with design intention (35577399+JoshHC@users.noreply.github.com)
14
+ - Bump @telus-uds/components-base to v1.64.0
15
+
16
+ ### Patches
17
+
18
+ - Fix image height prop type (carlos.jeronimo@telus.com)
19
+ - inverse variant story for badge component (mauricio.batresmontejo@telus.com)
20
+
7
21
  ## 2.20.1
8
22
 
9
- Mon, 16 Oct 2023 22:48:33 GMT
23
+ Mon, 16 Oct 2023 22:55:37 GMT
10
24
 
11
25
  ### Patches
12
26
 
@@ -28,6 +28,7 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
28
28
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
29
29
 
30
30
  const [selectProps, selectedSystemPropTypes] = (0, _componentsBase.selectSystemProps)([_utils.htmlAttrs]);
31
+ const viewportBreakpoint = 1440;
31
32
  const GlobalBodyScrollLock = /*#__PURE__*/(0, _styledComponents.createGlobalStyle)({
32
33
  'html, body': (0, _utils.media)().until('md').css({
33
34
  overflow: 'hidden'
@@ -41,18 +42,20 @@ const StyledFootnote = /*#__PURE__*/_styledComponents.default.div.withConfig({
41
42
  let {
42
43
  footnoteBackground,
43
44
  isVisible,
44
- footnoteBorderTop
45
+ footnoteBorderTop,
46
+ isScrollable
45
47
  } = _ref;
46
48
  return {
47
49
  position: 'fixed',
48
- overflowY: 'scroll',
50
+ overflowY: isVisible && isScrollable ? 'scroll' : 'hidden',
49
51
  top: 0,
50
- left: 0,
52
+ left: window.innerWidth >= viewportBreakpoint ? '50%' : 0,
51
53
  height: '100vh',
52
54
  width: '100vw',
53
55
  backgroundColor: footnoteBackground,
54
56
  display: 'block',
55
57
  transform: 'translateY(100%)',
58
+ translate: window.innerWidth >= viewportBreakpoint ? '-50%' : '',
56
59
  transition: 'transform 500ms ease-out',
57
60
  '@media() (prefers-reduced-motion: reduce)': {
58
61
  transition: 'none'
@@ -84,10 +87,10 @@ const StyledFootnote = /*#__PURE__*/_styledComponents.default.div.withConfig({
84
87
  const StyledFootnoteHeader = /*#__PURE__*/_styledComponents.default.div.withConfig({
85
88
  displayName: "Footnote__StyledFootnoteHeader",
86
89
  componentId: "components-web__sc-1563bo5-1"
87
- })({
90
+ })(() => ({
88
91
  position: 'relative',
89
92
  width: '100%'
90
- });
93
+ }));
91
94
 
92
95
  const StyledHeader = /*#__PURE__*/_styledComponents.default.div.withConfig({
93
96
  displayName: "Footnote__StyledHeader",
@@ -114,38 +117,27 @@ const StyledHeader = /*#__PURE__*/_styledComponents.default.div.withConfig({
114
117
  const StyledFootnoteBody = /*#__PURE__*/_styledComponents.default.div.withConfig({
115
118
  displayName: "Footnote__StyledFootnoteBody",
116
119
  componentId: "components-web__sc-1563bo5-3"
117
- })({
118
- overflow: 'auto',
119
- transition: 'height 300ms ease-out, opacity 200ms ease-out',
120
- transform: 'translateZ(0)',
121
- '@media() (prefers-reduced-motion: reduce)': {
122
- transition: 'height 1ms ease-out, opacity 1ms ease-out'
123
- }
124
- }, _ref4 => {
120
+ })(_ref4 => {
125
121
  let {
126
122
  footnoteBodyBackground,
127
- footnoteBodyPadding
123
+ footnoteBodyPadding,
124
+ headerHeight,
125
+ bodyHeight,
126
+ isTextVisible
128
127
  } = _ref4;
129
128
  return {
129
+ overflow: 'auto',
130
+ transition: 'height 300ms ease-out, opacity 200ms ease-out',
131
+ transform: 'translateZ(0)',
132
+ '@media() (prefers-reduced-motion: reduce)': {
133
+ transition: 'height 1ms ease-out, opacity 1ms ease-out'
134
+ },
130
135
  backgroundColor: footnoteBodyBackground,
131
- padding: footnoteBodyPadding
132
- };
133
- }, _ref5 => {
134
- let {
135
- headerHeight
136
- } = _ref5;
137
- return {
136
+ padding: footnoteBodyPadding,
138
137
  maxHeight: `calc(100vh - ${headerHeight}px)`,
139
138
  ...(0, _utils.media)().from('md').css({
140
139
  maxHeight: `calc(50vh - ${headerHeight}px)`
141
- })
142
- };
143
- }, _ref6 => {
144
- let {
145
- bodyHeight,
146
- isTextVisible
147
- } = _ref6;
148
- return {
140
+ }),
149
141
  height: bodyHeight,
150
142
  opacity: isTextVisible ? 1 : 0
151
143
  };
@@ -154,10 +146,10 @@ const StyledFootnoteBody = /*#__PURE__*/_styledComponents.default.div.withConfig
154
146
  const List = /*#__PURE__*/(0, _styledComponents.default)(_OrderedListBase.default).withConfig({
155
147
  displayName: "Footnote__List",
156
148
  componentId: "components-web__sc-1563bo5-4"
157
- })(_ref7 => {
149
+ })(_ref5 => {
158
150
  let {
159
151
  listPaddingLeft
160
- } = _ref7;
152
+ } = _ref5;
161
153
  return {
162
154
  listStylePosition: 'outside',
163
155
  paddingLeft: listPaddingLeft
@@ -166,7 +158,7 @@ const List = /*#__PURE__*/(0, _styledComponents.default)(_OrderedListBase.defaul
166
158
  const ListItem = /*#__PURE__*/(0, _styledComponents.default)(_OrderedListBase.default.Item).withConfig({
167
159
  displayName: "Footnote__ListItem",
168
160
  componentId: "components-web__sc-1563bo5-5"
169
- })(_ref8 => {
161
+ })(_ref6 => {
170
162
  let {
171
163
  listItemMarkerFontSize,
172
164
  listItemMarkerLineHeight,
@@ -174,7 +166,7 @@ const ListItem = /*#__PURE__*/(0, _styledComponents.default)(_OrderedListBase.de
174
166
  listItemFontSize,
175
167
  listItemLineHeight,
176
168
  listItemPaddingLeft
177
- } = _ref8;
169
+ } = _ref6;
178
170
  return {
179
171
  display: 'list-item',
180
172
  '&::marker': {
@@ -194,14 +186,14 @@ const ListItem = /*#__PURE__*/(0, _styledComponents.default)(_OrderedListBase.de
194
186
  const CloseButton = /*#__PURE__*/_styledComponents.default.button.withConfig({
195
187
  displayName: "Footnote__CloseButton",
196
188
  componentId: "components-web__sc-1563bo5-6"
197
- })(_ref9 => {
189
+ })(_ref7 => {
198
190
  let {
199
191
  closeButtonBorder,
200
192
  closeButtonHeight,
201
193
  closeButtonBackgroundColor,
202
194
  closeButtonMargin,
203
195
  closeButtonWidth
204
- } = _ref9;
196
+ } = _ref7;
205
197
  return {
206
198
  alignItems: 'center',
207
199
  borderRadius: '50%',
@@ -223,11 +215,12 @@ const ContentContainer = /*#__PURE__*/_styledComponents.default.div.withConfig({
223
215
  'margin-left': 'auto',
224
216
  'margin-right': 'auto',
225
217
  left: 0,
226
- right: 0
227
- }, _ref10 => {
218
+ right: 0,
219
+ maxWidth: '1200px'
220
+ }, _ref8 => {
228
221
  let {
229
222
  maxWidth
230
- } = _ref10;
223
+ } = _ref8;
231
224
  return {
232
225
  width: maxWidth
233
226
  };
@@ -236,13 +229,13 @@ const ContentContainer = /*#__PURE__*/_styledComponents.default.div.withConfig({
236
229
  const StyledCustomContentContainer = /*#__PURE__*/_styledComponents.default.div.withConfig({
237
230
  displayName: "Footnote__StyledCustomContentContainer",
238
231
  componentId: "components-web__sc-1563bo5-8"
239
- })(_ref11 => {
232
+ })(_ref9 => {
240
233
  let {
241
234
  listItemColor,
242
235
  listItemFontSize,
243
236
  listItemLineHeight,
244
237
  listItemPaddingLeft
245
- } = _ref11;
238
+ } = _ref9;
246
239
  return {
247
240
  fontSize: listItemFontSize,
248
241
  lineHeight: listItemLineHeight,
@@ -287,6 +280,7 @@ const usePrevious = value => {
287
280
  const Footnote = props => {
288
281
  var _theme$themeOptions;
289
282
 
283
+ const viewport = (0, _componentsBase.useViewport)();
290
284
  const {
291
285
  copy,
292
286
  number,
@@ -332,7 +326,9 @@ const Footnote = props => {
332
326
  closeButtonWidth,
333
327
  closeButtonIconSize,
334
328
  closeIcon
335
- } = (0, _componentsBase.useThemeTokens)('Footnote', tokens, variant);
329
+ } = (0, _componentsBase.useThemeTokens)('Footnote', tokens, variant, {
330
+ viewport
331
+ });
336
332
  const footnoteRef = (0, _react.useRef)(null);
337
333
  const headerRef = (0, _react.useRef)(null);
338
334
  const bodyRef = (0, _react.useRef)(null);
@@ -353,6 +349,7 @@ const Footnote = props => {
353
349
  const prevProps = usePrevious(props);
354
350
  const theme = (0, _componentsBase.useTheme)();
355
351
  const maxWidth = (0, _componentsBase.useResponsiveProp)((_theme$themeOptions = theme.themeOptions) === null || _theme$themeOptions === void 0 ? void 0 : _theme$themeOptions.contentMaxWidth);
352
+ const [isScrollable, setIsScrollable] = (0, _react.useState)(false);
356
353
  const closeFootnote = (0, _react.useCallback)((event, options) => {
357
354
  onClose(event, options);
358
355
  }, [onClose]); // Listen for ESCAPE, close button clicks, and clicks outside of the Footnote. Call onClose.
@@ -522,6 +519,22 @@ const Footnote = props => {
522
519
  })
523
520
  });
524
521
  }, [data.content, data.number, listItemColor, listItemFontSize, listItemLineHeight, listItemMarkerFontSize, listItemMarkerLineHeight, listItemPaddingLeft, listPaddingLeft]);
522
+ const checkIfScrollable = (0, _react.useCallback)(() => {
523
+ const footnoteElement = footnoteRef.current;
524
+
525
+ if (footnoteElement) {
526
+ const footnoteViewportHeight = footnoteElement.clientHeight ? footnoteElement.clientHeight : 0;
527
+ const contentHeight = contentRef.current ? contentRef.current.offsetHeight : 0;
528
+ setIsScrollable(contentHeight > footnoteViewportHeight * 0.5);
529
+ }
530
+ }, [contentRef, setIsScrollable]);
531
+ (0, _react.useEffect)(() => {
532
+ if (isOpen) {
533
+ setTimeout(() => {
534
+ checkIfScrollable();
535
+ }, 100);
536
+ }
537
+ }, [isOpen, checkIfScrollable]);
525
538
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_componentsBase.Portal, {
526
539
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { ...selectProps(rest),
527
540
  children: [isOpen && /*#__PURE__*/(0, _jsxRuntime.jsx)(GlobalBodyScrollLock, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledFootnote, {
@@ -532,10 +545,12 @@ const Footnote = props => {
532
545
  tabIndex: 0,
533
546
  footnoteBackground: footnoteBackground,
534
547
  footnoteBorderTop: `${footnoteBorderTopSizeMd}px solid ${footnoteBorderColorMd}`,
548
+ isScrollable: isScrollable,
535
549
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(ContentContainer, {
536
550
  maxWidth: maxWidth,
537
551
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(StyledFootnoteHeader, {
538
552
  ref: headerRef,
553
+ viewport: viewport,
539
554
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(StyledHeader, {
540
555
  ref: headingRef,
541
556
  footnoteHeaderPaddingLeft: footnoteHeaderPaddingLeft,
@@ -113,7 +113,7 @@ Image.propTypes = { ...selectedSystemPropTypes,
113
113
  /**
114
114
  * The image's height.
115
115
  */
116
- height: _propTypes.default.number.isRequired,
116
+ height: _propTypes.default.number,
117
117
 
118
118
  /**
119
119
  * Loading strategy.
@@ -1,13 +1,14 @@
1
1
  import React, { useRef, useEffect, useState, useCallback } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import styled, { createGlobalStyle } from 'styled-components';
4
- import { Icon, Portal, selectSystemProps, Typography, useCopy, useTheme, useResponsiveProp, useThemeTokens, getTokensPropType } from '@telus-uds/components-base';
4
+ import { Icon, Portal, selectSystemProps, Typography, useCopy, useTheme, useResponsiveProp, useThemeTokens, useViewport, getTokensPropType } from '@telus-uds/components-base';
5
5
  import OrderedListBase from '../OrderedList/OrderedListBase';
6
6
  import { htmlAttrs, media, renderStructuredContent } from '../utils';
7
7
  import defaultDictionary from './dictionary';
8
8
  import { jsx as _jsx } from "react/jsx-runtime";
9
9
  import { jsxs as _jsxs } from "react/jsx-runtime";
10
10
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs]);
11
+ const viewportBreakpoint = 1440;
11
12
  const GlobalBodyScrollLock = /*#__PURE__*/createGlobalStyle({
12
13
  'html, body': media().until('md').css({
13
14
  overflow: 'hidden'
@@ -20,18 +21,20 @@ const StyledFootnote = /*#__PURE__*/styled.div.withConfig({
20
21
  let {
21
22
  footnoteBackground,
22
23
  isVisible,
23
- footnoteBorderTop
24
+ footnoteBorderTop,
25
+ isScrollable
24
26
  } = _ref;
25
27
  return {
26
28
  position: 'fixed',
27
- overflowY: 'scroll',
29
+ overflowY: isVisible && isScrollable ? 'scroll' : 'hidden',
28
30
  top: 0,
29
- left: 0,
31
+ left: window.innerWidth >= viewportBreakpoint ? '50%' : 0,
30
32
  height: '100vh',
31
33
  width: '100vw',
32
34
  backgroundColor: footnoteBackground,
33
35
  display: 'block',
34
36
  transform: 'translateY(100%)',
37
+ translate: window.innerWidth >= viewportBreakpoint ? '-50%' : '',
35
38
  transition: 'transform 500ms ease-out',
36
39
  '@media() (prefers-reduced-motion: reduce)': {
37
40
  transition: 'none'
@@ -62,10 +65,10 @@ const StyledFootnote = /*#__PURE__*/styled.div.withConfig({
62
65
  const StyledFootnoteHeader = /*#__PURE__*/styled.div.withConfig({
63
66
  displayName: "Footnote__StyledFootnoteHeader",
64
67
  componentId: "components-web__sc-1563bo5-1"
65
- })({
68
+ })(() => ({
66
69
  position: 'relative',
67
70
  width: '100%'
68
- });
71
+ }));
69
72
  const StyledHeader = /*#__PURE__*/styled.div.withConfig({
70
73
  displayName: "Footnote__StyledHeader",
71
74
  componentId: "components-web__sc-1563bo5-2"
@@ -90,38 +93,27 @@ const StyledHeader = /*#__PURE__*/styled.div.withConfig({
90
93
  const StyledFootnoteBody = /*#__PURE__*/styled.div.withConfig({
91
94
  displayName: "Footnote__StyledFootnoteBody",
92
95
  componentId: "components-web__sc-1563bo5-3"
93
- })({
94
- overflow: 'auto',
95
- transition: 'height 300ms ease-out, opacity 200ms ease-out',
96
- transform: 'translateZ(0)',
97
- '@media() (prefers-reduced-motion: reduce)': {
98
- transition: 'height 1ms ease-out, opacity 1ms ease-out'
99
- }
100
- }, _ref4 => {
96
+ })(_ref4 => {
101
97
  let {
102
98
  footnoteBodyBackground,
103
- footnoteBodyPadding
99
+ footnoteBodyPadding,
100
+ headerHeight,
101
+ bodyHeight,
102
+ isTextVisible
104
103
  } = _ref4;
105
104
  return {
105
+ overflow: 'auto',
106
+ transition: 'height 300ms ease-out, opacity 200ms ease-out',
107
+ transform: 'translateZ(0)',
108
+ '@media() (prefers-reduced-motion: reduce)': {
109
+ transition: 'height 1ms ease-out, opacity 1ms ease-out'
110
+ },
106
111
  backgroundColor: footnoteBodyBackground,
107
- padding: footnoteBodyPadding
108
- };
109
- }, _ref5 => {
110
- let {
111
- headerHeight
112
- } = _ref5;
113
- return {
112
+ padding: footnoteBodyPadding,
114
113
  maxHeight: `calc(100vh - ${headerHeight}px)`,
115
114
  ...media().from('md').css({
116
115
  maxHeight: `calc(50vh - ${headerHeight}px)`
117
- })
118
- };
119
- }, _ref6 => {
120
- let {
121
- bodyHeight,
122
- isTextVisible
123
- } = _ref6;
124
- return {
116
+ }),
125
117
  height: bodyHeight,
126
118
  opacity: isTextVisible ? 1 : 0
127
119
  };
@@ -129,10 +121,10 @@ const StyledFootnoteBody = /*#__PURE__*/styled.div.withConfig({
129
121
  const List = /*#__PURE__*/styled(OrderedListBase).withConfig({
130
122
  displayName: "Footnote__List",
131
123
  componentId: "components-web__sc-1563bo5-4"
132
- })(_ref7 => {
124
+ })(_ref5 => {
133
125
  let {
134
126
  listPaddingLeft
135
- } = _ref7;
127
+ } = _ref5;
136
128
  return {
137
129
  listStylePosition: 'outside',
138
130
  paddingLeft: listPaddingLeft
@@ -141,7 +133,7 @@ const List = /*#__PURE__*/styled(OrderedListBase).withConfig({
141
133
  const ListItem = /*#__PURE__*/styled(OrderedListBase.Item).withConfig({
142
134
  displayName: "Footnote__ListItem",
143
135
  componentId: "components-web__sc-1563bo5-5"
144
- })(_ref8 => {
136
+ })(_ref6 => {
145
137
  let {
146
138
  listItemMarkerFontSize,
147
139
  listItemMarkerLineHeight,
@@ -149,7 +141,7 @@ const ListItem = /*#__PURE__*/styled(OrderedListBase.Item).withConfig({
149
141
  listItemFontSize,
150
142
  listItemLineHeight,
151
143
  listItemPaddingLeft
152
- } = _ref8;
144
+ } = _ref6;
153
145
  return {
154
146
  display: 'list-item',
155
147
  '&::marker': {
@@ -168,14 +160,14 @@ const ListItem = /*#__PURE__*/styled(OrderedListBase.Item).withConfig({
168
160
  const CloseButton = /*#__PURE__*/styled.button.withConfig({
169
161
  displayName: "Footnote__CloseButton",
170
162
  componentId: "components-web__sc-1563bo5-6"
171
- })(_ref9 => {
163
+ })(_ref7 => {
172
164
  let {
173
165
  closeButtonBorder,
174
166
  closeButtonHeight,
175
167
  closeButtonBackgroundColor,
176
168
  closeButtonMargin,
177
169
  closeButtonWidth
178
- } = _ref9;
170
+ } = _ref7;
179
171
  return {
180
172
  alignItems: 'center',
181
173
  borderRadius: '50%',
@@ -196,11 +188,12 @@ const ContentContainer = /*#__PURE__*/styled.div.withConfig({
196
188
  'margin-left': 'auto',
197
189
  'margin-right': 'auto',
198
190
  left: 0,
199
- right: 0
200
- }, _ref10 => {
191
+ right: 0,
192
+ maxWidth: '1200px'
193
+ }, _ref8 => {
201
194
  let {
202
195
  maxWidth
203
- } = _ref10;
196
+ } = _ref8;
204
197
  return {
205
198
  width: maxWidth
206
199
  };
@@ -208,13 +201,13 @@ const ContentContainer = /*#__PURE__*/styled.div.withConfig({
208
201
  const StyledCustomContentContainer = /*#__PURE__*/styled.div.withConfig({
209
202
  displayName: "Footnote__StyledCustomContentContainer",
210
203
  componentId: "components-web__sc-1563bo5-8"
211
- })(_ref11 => {
204
+ })(_ref9 => {
212
205
  let {
213
206
  listItemColor,
214
207
  listItemFontSize,
215
208
  listItemLineHeight,
216
209
  listItemPaddingLeft
217
- } = _ref11;
210
+ } = _ref9;
218
211
  return {
219
212
  fontSize: listItemFontSize,
220
213
  lineHeight: listItemLineHeight,
@@ -259,6 +252,7 @@ const usePrevious = value => {
259
252
  const Footnote = props => {
260
253
  var _theme$themeOptions;
261
254
 
255
+ const viewport = useViewport();
262
256
  const {
263
257
  copy,
264
258
  number,
@@ -304,7 +298,9 @@ const Footnote = props => {
304
298
  closeButtonWidth,
305
299
  closeButtonIconSize,
306
300
  closeIcon
307
- } = useThemeTokens('Footnote', tokens, variant);
301
+ } = useThemeTokens('Footnote', tokens, variant, {
302
+ viewport
303
+ });
308
304
  const footnoteRef = useRef(null);
309
305
  const headerRef = useRef(null);
310
306
  const bodyRef = useRef(null);
@@ -325,6 +321,7 @@ const Footnote = props => {
325
321
  const prevProps = usePrevious(props);
326
322
  const theme = useTheme();
327
323
  const maxWidth = useResponsiveProp((_theme$themeOptions = theme.themeOptions) === null || _theme$themeOptions === void 0 ? void 0 : _theme$themeOptions.contentMaxWidth);
324
+ const [isScrollable, setIsScrollable] = useState(false);
328
325
  const closeFootnote = useCallback((event, options) => {
329
326
  onClose(event, options);
330
327
  }, [onClose]); // Listen for ESCAPE, close button clicks, and clicks outside of the Footnote. Call onClose.
@@ -494,6 +491,22 @@ const Footnote = props => {
494
491
  })
495
492
  });
496
493
  }, [data.content, data.number, listItemColor, listItemFontSize, listItemLineHeight, listItemMarkerFontSize, listItemMarkerLineHeight, listItemPaddingLeft, listPaddingLeft]);
494
+ const checkIfScrollable = useCallback(() => {
495
+ const footnoteElement = footnoteRef.current;
496
+
497
+ if (footnoteElement) {
498
+ const footnoteViewportHeight = footnoteElement.clientHeight ? footnoteElement.clientHeight : 0;
499
+ const contentHeight = contentRef.current ? contentRef.current.offsetHeight : 0;
500
+ setIsScrollable(contentHeight > footnoteViewportHeight * 0.5);
501
+ }
502
+ }, [contentRef, setIsScrollable]);
503
+ useEffect(() => {
504
+ if (isOpen) {
505
+ setTimeout(() => {
506
+ checkIfScrollable();
507
+ }, 100);
508
+ }
509
+ }, [isOpen, checkIfScrollable]);
497
510
  return /*#__PURE__*/_jsx(Portal, {
498
511
  children: /*#__PURE__*/_jsxs("div", { ...selectProps(rest),
499
512
  children: [isOpen && /*#__PURE__*/_jsx(GlobalBodyScrollLock, {}), /*#__PURE__*/_jsx(StyledFootnote, {
@@ -504,10 +517,12 @@ const Footnote = props => {
504
517
  tabIndex: 0,
505
518
  footnoteBackground: footnoteBackground,
506
519
  footnoteBorderTop: `${footnoteBorderTopSizeMd}px solid ${footnoteBorderColorMd}`,
520
+ isScrollable: isScrollable,
507
521
  children: /*#__PURE__*/_jsxs(ContentContainer, {
508
522
  maxWidth: maxWidth,
509
523
  children: [/*#__PURE__*/_jsx(StyledFootnoteHeader, {
510
524
  ref: headerRef,
525
+ viewport: viewport,
511
526
  children: /*#__PURE__*/_jsxs(StyledHeader, {
512
527
  ref: headingRef,
513
528
  footnoteHeaderPaddingLeft: footnoteHeaderPaddingLeft,
@@ -96,7 +96,7 @@ Image.propTypes = { ...selectedSystemPropTypes,
96
96
  /**
97
97
  * The image's height.
98
98
  */
99
- height: PropTypes.number.isRequired,
99
+ height: PropTypes.number,
100
100
 
101
101
  /**
102
102
  * Loading strategy.
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  ],
6
6
  "dependencies": {
7
7
  "@gorhom/portal": "^1.0.14",
8
- "@telus-uds/components-base": "1.63.0",
8
+ "@telus-uds/components-base": "1.64.0",
9
9
  "@telus-uds/system-constants": "^1.3.0",
10
10
  "fscreen": "^1.2.0",
11
11
  "lodash.omit": "^4.5.0",
@@ -62,5 +62,5 @@
62
62
  "skip": true
63
63
  },
64
64
  "types": "types/index.d.ts",
65
- "version": "2.20.1"
65
+ "version": "2.21.0"
66
66
  }
@@ -10,6 +10,7 @@ import {
10
10
  useTheme,
11
11
  useResponsiveProp,
12
12
  useThemeTokens,
13
+ useViewport,
13
14
  getTokensPropType
14
15
  } from '@telus-uds/components-base'
15
16
 
@@ -18,22 +19,24 @@ import { htmlAttrs, media, renderStructuredContent } from '../utils'
18
19
  import defaultDictionary from './dictionary'
19
20
 
20
21
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
22
+ const viewportBreakpoint = 1440
21
23
 
22
24
  const GlobalBodyScrollLock = createGlobalStyle({
23
25
  'html, body': media().until('md').css({ overflow: 'hidden' })
24
26
  })
25
27
 
26
28
  const StyledFootnote = styled.div(
27
- ({ footnoteBackground, isVisible, footnoteBorderTop }) => ({
29
+ ({ footnoteBackground, isVisible, footnoteBorderTop, isScrollable }) => ({
28
30
  position: 'fixed',
29
- overflowY: 'scroll',
31
+ overflowY: isVisible && isScrollable ? 'scroll' : 'hidden',
30
32
  top: 0,
31
- left: 0,
33
+ left: window.innerWidth >= viewportBreakpoint ? '50%' : 0,
32
34
  height: '100vh',
33
35
  width: '100vw',
34
36
  backgroundColor: footnoteBackground,
35
37
  display: 'block',
36
38
  transform: 'translateY(100%)',
39
+ translate: window.innerWidth >= viewportBreakpoint ? '-50%' : '',
37
40
  transition: 'transform 500ms ease-out',
38
41
  '@media() (prefers-reduced-motion: reduce)': {
39
42
  transition: 'none'
@@ -58,10 +61,10 @@ const StyledFootnote = styled.div(
58
61
  }
59
62
  )
60
63
 
61
- const StyledFootnoteHeader = styled.div({
64
+ const StyledFootnoteHeader = styled.div(() => ({
62
65
  position: 'relative',
63
66
  width: '100%'
64
- })
67
+ }))
65
68
 
66
69
  const StyledHeader = styled.div(
67
70
  ({
@@ -82,27 +85,21 @@ const StyledHeader = styled.div(
82
85
  )
83
86
 
84
87
  const StyledFootnoteBody = styled.div(
85
- {
88
+ ({ footnoteBodyBackground, footnoteBodyPadding, headerHeight, bodyHeight, isTextVisible }) => ({
86
89
  overflow: 'auto',
87
90
  transition: 'height 300ms ease-out, opacity 200ms ease-out',
88
91
  transform: 'translateZ(0)',
89
92
  '@media() (prefers-reduced-motion: reduce)': {
90
93
  transition: 'height 1ms ease-out, opacity 1ms ease-out'
91
- }
92
- },
93
- ({ footnoteBodyBackground, footnoteBodyPadding }) => ({
94
+ },
94
95
  backgroundColor: footnoteBodyBackground,
95
- padding: footnoteBodyPadding
96
- }),
97
- ({ headerHeight }) => ({
96
+ padding: footnoteBodyPadding,
98
97
  maxHeight: `calc(100vh - ${headerHeight}px)`,
99
98
  ...media()
100
99
  .from('md')
101
100
  .css({
102
101
  maxHeight: `calc(50vh - ${headerHeight}px)`
103
- })
104
- }),
105
- ({ bodyHeight, isTextVisible }) => ({
102
+ }),
106
103
  height: bodyHeight,
107
104
  opacity: isTextVisible ? 1 : 0
108
105
  })
@@ -163,7 +160,8 @@ const ContentContainer = styled.div(
163
160
  'margin-left': 'auto',
164
161
  'margin-right': 'auto',
165
162
  left: 0,
166
- right: 0
163
+ right: 0,
164
+ maxWidth: '1200px'
167
165
  },
168
166
  ({ maxWidth }) => ({
169
167
  width: maxWidth
@@ -210,6 +208,7 @@ const usePrevious = (value) => {
210
208
  * - When `Footnote` is closed, focus must return to the initiating element
211
209
  */
212
210
  const Footnote = (props) => {
211
+ const viewport = useViewport()
213
212
  const {
214
213
  copy,
215
214
  number,
@@ -255,7 +254,7 @@ const Footnote = (props) => {
255
254
  closeButtonWidth,
256
255
  closeButtonIconSize,
257
256
  closeIcon
258
- } = useThemeTokens('Footnote', tokens, variant)
257
+ } = useThemeTokens('Footnote', tokens, variant, { viewport })
259
258
 
260
259
  const footnoteRef = useRef(null)
261
260
  const headerRef = useRef(null)
@@ -272,6 +271,7 @@ const Footnote = (props) => {
272
271
  const prevProps = usePrevious(props)
273
272
  const theme = useTheme()
274
273
  const maxWidth = useResponsiveProp(theme.themeOptions?.contentMaxWidth)
274
+ const [isScrollable, setIsScrollable] = useState(false)
275
275
 
276
276
  const closeFootnote = useCallback(
277
277
  (event, options) => {
@@ -457,6 +457,24 @@ const Footnote = (props) => {
457
457
  listPaddingLeft
458
458
  ])
459
459
 
460
+ const checkIfScrollable = useCallback(() => {
461
+ const footnoteElement = footnoteRef.current
462
+ if (footnoteElement) {
463
+ const footnoteViewportHeight = footnoteElement.clientHeight ? footnoteElement.clientHeight : 0
464
+ const contentHeight = contentRef.current ? contentRef.current.offsetHeight : 0
465
+
466
+ setIsScrollable(contentHeight > footnoteViewportHeight * 0.5)
467
+ }
468
+ }, [contentRef, setIsScrollable])
469
+
470
+ useEffect(() => {
471
+ if (isOpen) {
472
+ setTimeout(() => {
473
+ checkIfScrollable()
474
+ }, 100)
475
+ }
476
+ }, [isOpen, checkIfScrollable])
477
+
460
478
  return (
461
479
  <Portal>
462
480
  <div {...selectProps(rest)}>
@@ -469,9 +487,10 @@ const Footnote = (props) => {
469
487
  tabIndex={0}
470
488
  footnoteBackground={footnoteBackground}
471
489
  footnoteBorderTop={`${footnoteBorderTopSizeMd}px solid ${footnoteBorderColorMd}`}
490
+ isScrollable={isScrollable}
472
491
  >
473
492
  <ContentContainer maxWidth={maxWidth}>
474
- <StyledFootnoteHeader ref={headerRef}>
493
+ <StyledFootnoteHeader ref={headerRef} viewport={viewport}>
475
494
  <StyledHeader
476
495
  ref={headingRef}
477
496
  footnoteHeaderPaddingLeft={footnoteHeaderPaddingLeft}
@@ -82,7 +82,7 @@ Image.propTypes = {
82
82
  /**
83
83
  * The image's height.
84
84
  */
85
- height: PropTypes.number.isRequired,
85
+ height: PropTypes.number,
86
86
  /**
87
87
  * Loading strategy.
88
88
  * @default 'eager'