@telus-uds/components-web 2.34.2 → 2.34.3

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,23 @@
1
1
  # Change Log - @telus-uds/components-web
2
2
 
3
- This log was last generated on Tue, 28 May 2024 14:52:42 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 07 Jun 2024 22:36:16 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 2.34.3
8
+
9
+ Fri, 07 Jun 2024 22:36:16 GMT
10
+
11
+ ### Patches
12
+
13
+ - Fixes for Footnote accesibility (Mauricio.BatresMontejo@telus.com)
14
+ - `Footnote`: fix hydration errors (guillermo.peitzner@telus.com)
15
+ - Bump @telus-uds/components-base to v1.86.0
16
+ - Bump @telus-uds/system-theme-tokens to v2.57.0
17
+
7
18
  ## 2.34.2
8
19
 
9
- Tue, 28 May 2024 14:52:42 GMT
20
+ Tue, 28 May 2024 11:16:51 GMT
10
21
 
11
22
  ### Patches
12
23
 
@@ -308,7 +308,7 @@ const Footnote = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
308
308
  const headerRef = _react.default.useRef(null);
309
309
  const bodyRef = _react.default.useRef(null);
310
310
  const contentRef = _react.default.useRef(null);
311
- const headingRef = _react.default.useRef(null);
311
+ const closeButtonRef = _react.default.useRef(null);
312
312
  const [data, setData] = _react.default.useState({
313
313
  content: null,
314
314
  number: null
@@ -329,8 +329,14 @@ const Footnote = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
329
329
  onClose(event, options);
330
330
  }, [onClose]);
331
331
 
332
- // Listen for ESCAPE, close button clicks, and clicks outside of the Footnote. Call onClose.
333
- const handleClose = _react.default.useCallback(event => {
332
+ /**
333
+ * When listen for ESCAPE, close button clicks, and clicks outside of the Footnote. Call onClose.
334
+ * When the event type is a 'keydonw' and the event key is a 'Tab', using a 'querySelectorAll we obtain all
335
+ * the interactive elements within the footnote, we order and save the first and the last,
336
+ * if the footnote is active the focus will be inside the footnote until it is closed,
337
+ * if there are no interactive elements the focus will remain inside the close button.
338
+ */
339
+ const manageFootnoteFocusAndClose = _react.default.useCallback(event => {
334
340
  var _footnoteRef$current, _footnoteRef$current2;
335
341
  if (!isVisible) {
336
342
  return;
@@ -340,6 +346,17 @@ const Footnote = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
340
346
  closeFootnote(event, {
341
347
  returnFocus: true
342
348
  });
349
+ } else if (event.key === 'Tab') {
350
+ const focusableElements = Array.from(footnoteRef.current.querySelectorAll('*')).filter(_utils.isElementFocusable);
351
+ const firstElement = focusableElements[0];
352
+ const lastElement = focusableElements[focusableElements.length - 1];
353
+ if (event.shiftKey && document.activeElement === firstElement) {
354
+ event.preventDefault();
355
+ lastElement.focus();
356
+ } else if (!event.shiftKey && document.activeElement === lastElement) {
357
+ event.preventDefault();
358
+ firstElement.focus();
359
+ }
343
360
  }
344
361
  } else if ((event.type === 'click' || event.type === 'mousedown') && footnoteRef !== null && footnoteRef !== void 0 && footnoteRef.current && event.target && !(footnoteRef !== null && footnoteRef !== void 0 && (_footnoteRef$current = footnoteRef.current) !== null && _footnoteRef$current !== void 0 && _footnoteRef$current.contains(event.target)) && event.target.getAttribute('data-tds-id') !== 'footnote-link') {
345
362
  closeFootnote(event, {
@@ -356,8 +373,8 @@ const Footnote = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
356
373
  setBodyHeight(oldHeight);
357
374
  };
358
375
  const focusHeading = () => {
359
- if (Boolean(content) && isVisible && headingRef && headingRef.current !== null) {
360
- headingRef.current.focus();
376
+ if (Boolean(content) && isVisible && closeButtonRef && closeButtonRef.current !== null) {
377
+ closeButtonRef.current.focus();
361
378
  }
362
379
  };
363
380
  const handleStyledFootnoteTransitionEnd = event => {
@@ -410,24 +427,24 @@ const Footnote = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
410
427
  _react.default.useEffect(() => {
411
428
  if (isOpen) {
412
429
  setIsVisible(true);
413
- document.addEventListener('mousedown', handleClose);
414
- window.addEventListener('click', handleClose);
415
- window.addEventListener('keydown', handleClose);
416
- window.addEventListener('touchstart', handleClose);
430
+ document.addEventListener('mousedown', manageFootnoteFocusAndClose);
431
+ window.addEventListener('click', manageFootnoteFocusAndClose);
432
+ window.addEventListener('keydown', manageFootnoteFocusAndClose);
433
+ window.addEventListener('touchstart', manageFootnoteFocusAndClose);
417
434
  window.addEventListener('touchmove', preventDefault, {
418
435
  passive: false
419
436
  });
420
437
  }
421
438
  return () => {
422
439
  if (isOpen) {
423
- document.removeEventListener('mousedown', handleClose);
424
- window.removeEventListener('click', handleClose);
425
- window.removeEventListener('keydown', handleClose);
426
- window.removeEventListener('touchstart', handleClose);
440
+ document.removeEventListener('mousedown', manageFootnoteFocusAndClose);
441
+ window.removeEventListener('click', manageFootnoteFocusAndClose);
442
+ window.removeEventListener('keydown', manageFootnoteFocusAndClose);
443
+ window.removeEventListener('touchstart', manageFootnoteFocusAndClose);
427
444
  window.removeEventListener('touchmove', preventDefault);
428
445
  }
429
446
  };
430
- }, [handleClose, isOpen]);
447
+ }, [manageFootnoteFocusAndClose, isOpen]);
431
448
 
432
449
  // Set data if opening a new footnote
433
450
  _react.default.useEffect(() => {
@@ -517,7 +534,6 @@ const Footnote = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
517
534
  ref: headerRef,
518
535
  viewport: viewport,
519
536
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(StyledHeader, {
520
- ref: headingRef,
521
537
  footnoteHeaderPaddingLeft: footnoteHeaderPaddingLeft,
522
538
  footnoteHeaderPaddingRight: footnoteHeaderPaddingRight,
523
539
  footnoteHeaderPaddingTop: footnoteHeaderPaddingTop,
@@ -533,6 +549,7 @@ const Footnote = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
533
549
  },
534
550
  children: getCopy('heading')
535
551
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(CloseButton, {
552
+ ref: closeButtonRef,
536
553
  closeButtonBorder: `${closeButtonBorderSize} solid ${closeButtonBorderColor}`,
537
554
  closeButtonWidth: `${closeButtonWidth}px`,
538
555
  closeButtonHeight: `${closeButtonHeight}px`,
@@ -15,6 +15,12 @@ Object.defineProperty(exports, "htmlAttrs", {
15
15
  return _componentsBase.htmlAttrs;
16
16
  }
17
17
  });
18
+ Object.defineProperty(exports, "isElementFocusable", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _isElementFocusable.default;
22
+ }
23
+ });
18
24
  Object.defineProperty(exports, "media", {
19
25
  enumerable: true,
20
26
  get: function () {
@@ -63,6 +69,7 @@ var _transforms = require("./transforms");
63
69
  var _useTypographyTheme = _interopRequireDefault(require("./useTypographyTheme"));
64
70
  var _media = _interopRequireDefault(require("./media"));
65
71
  var _ssr = _interopRequireDefault(require("./ssr"));
72
+ var _isElementFocusable = _interopRequireDefault(require("./isElementFocusable"));
66
73
  var _renderStructuredContent = _interopRequireDefault(require("./renderStructuredContent"));
67
74
  var _useOverlaidPosition = _interopRequireDefault(require("./useOverlaidPosition"));
68
75
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ /**
8
+ * Returns focusable elements inside of the Footnote
9
+ */
10
+ const isElementFocusable = element => {
11
+ const focusableElements = `a[href], button, textarea, input, select, form, label, audio, video, source, track, canvas, rect, polygon, iframe[data-src], [tabindex]:not([tabindex="-1"]), [contenteditable]`;
12
+ return element.matches(focusableElements) && !element.hasAttribute('disabled') && !element.matches('[tabindex="-1"]');
13
+ };
14
+ var _default = isElementFocusable;
15
+ exports.default = _default;
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import styled, { createGlobalStyle } from 'styled-components';
4
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
- import { htmlAttrs, media, renderStructuredContent } from '../utils';
6
+ import { htmlAttrs, media, renderStructuredContent, isElementFocusable } 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";
@@ -300,7 +300,7 @@ const Footnote = /*#__PURE__*/React.forwardRef((props, ref) => {
300
300
  const headerRef = React.useRef(null);
301
301
  const bodyRef = React.useRef(null);
302
302
  const contentRef = React.useRef(null);
303
- const headingRef = React.useRef(null);
303
+ const closeButtonRef = React.useRef(null);
304
304
  const [data, setData] = React.useState({
305
305
  content: null,
306
306
  number: null
@@ -321,8 +321,14 @@ const Footnote = /*#__PURE__*/React.forwardRef((props, ref) => {
321
321
  onClose(event, options);
322
322
  }, [onClose]);
323
323
 
324
- // Listen for ESCAPE, close button clicks, and clicks outside of the Footnote. Call onClose.
325
- const handleClose = React.useCallback(event => {
324
+ /**
325
+ * When listen for ESCAPE, close button clicks, and clicks outside of the Footnote. Call onClose.
326
+ * When the event type is a 'keydonw' and the event key is a 'Tab', using a 'querySelectorAll we obtain all
327
+ * the interactive elements within the footnote, we order and save the first and the last,
328
+ * if the footnote is active the focus will be inside the footnote until it is closed,
329
+ * if there are no interactive elements the focus will remain inside the close button.
330
+ */
331
+ const manageFootnoteFocusAndClose = React.useCallback(event => {
326
332
  var _footnoteRef$current, _footnoteRef$current2;
327
333
  if (!isVisible) {
328
334
  return;
@@ -332,6 +338,17 @@ const Footnote = /*#__PURE__*/React.forwardRef((props, ref) => {
332
338
  closeFootnote(event, {
333
339
  returnFocus: true
334
340
  });
341
+ } else if (event.key === 'Tab') {
342
+ const focusableElements = Array.from(footnoteRef.current.querySelectorAll('*')).filter(isElementFocusable);
343
+ const firstElement = focusableElements[0];
344
+ const lastElement = focusableElements[focusableElements.length - 1];
345
+ if (event.shiftKey && document.activeElement === firstElement) {
346
+ event.preventDefault();
347
+ lastElement.focus();
348
+ } else if (!event.shiftKey && document.activeElement === lastElement) {
349
+ event.preventDefault();
350
+ firstElement.focus();
351
+ }
335
352
  }
336
353
  } else if ((event.type === 'click' || event.type === 'mousedown') && footnoteRef !== null && footnoteRef !== void 0 && footnoteRef.current && event.target && !(footnoteRef !== null && footnoteRef !== void 0 && (_footnoteRef$current = footnoteRef.current) !== null && _footnoteRef$current !== void 0 && _footnoteRef$current.contains(event.target)) && event.target.getAttribute('data-tds-id') !== 'footnote-link') {
337
354
  closeFootnote(event, {
@@ -348,8 +365,8 @@ const Footnote = /*#__PURE__*/React.forwardRef((props, ref) => {
348
365
  setBodyHeight(oldHeight);
349
366
  };
350
367
  const focusHeading = () => {
351
- if (Boolean(content) && isVisible && headingRef && headingRef.current !== null) {
352
- headingRef.current.focus();
368
+ if (Boolean(content) && isVisible && closeButtonRef && closeButtonRef.current !== null) {
369
+ closeButtonRef.current.focus();
353
370
  }
354
371
  };
355
372
  const handleStyledFootnoteTransitionEnd = event => {
@@ -402,24 +419,24 @@ const Footnote = /*#__PURE__*/React.forwardRef((props, ref) => {
402
419
  React.useEffect(() => {
403
420
  if (isOpen) {
404
421
  setIsVisible(true);
405
- document.addEventListener('mousedown', handleClose);
406
- window.addEventListener('click', handleClose);
407
- window.addEventListener('keydown', handleClose);
408
- window.addEventListener('touchstart', handleClose);
422
+ document.addEventListener('mousedown', manageFootnoteFocusAndClose);
423
+ window.addEventListener('click', manageFootnoteFocusAndClose);
424
+ window.addEventListener('keydown', manageFootnoteFocusAndClose);
425
+ window.addEventListener('touchstart', manageFootnoteFocusAndClose);
409
426
  window.addEventListener('touchmove', preventDefault, {
410
427
  passive: false
411
428
  });
412
429
  }
413
430
  return () => {
414
431
  if (isOpen) {
415
- document.removeEventListener('mousedown', handleClose);
416
- window.removeEventListener('click', handleClose);
417
- window.removeEventListener('keydown', handleClose);
418
- window.removeEventListener('touchstart', handleClose);
432
+ document.removeEventListener('mousedown', manageFootnoteFocusAndClose);
433
+ window.removeEventListener('click', manageFootnoteFocusAndClose);
434
+ window.removeEventListener('keydown', manageFootnoteFocusAndClose);
435
+ window.removeEventListener('touchstart', manageFootnoteFocusAndClose);
419
436
  window.removeEventListener('touchmove', preventDefault);
420
437
  }
421
438
  };
422
- }, [handleClose, isOpen]);
439
+ }, [manageFootnoteFocusAndClose, isOpen]);
423
440
 
424
441
  // Set data if opening a new footnote
425
442
  React.useEffect(() => {
@@ -509,7 +526,6 @@ const Footnote = /*#__PURE__*/React.forwardRef((props, ref) => {
509
526
  ref: headerRef,
510
527
  viewport: viewport,
511
528
  children: /*#__PURE__*/_jsxs(StyledHeader, {
512
- ref: headingRef,
513
529
  footnoteHeaderPaddingLeft: footnoteHeaderPaddingLeft,
514
530
  footnoteHeaderPaddingRight: footnoteHeaderPaddingRight,
515
531
  footnoteHeaderPaddingTop: footnoteHeaderPaddingTop,
@@ -525,6 +541,7 @@ const Footnote = /*#__PURE__*/React.forwardRef((props, ref) => {
525
541
  },
526
542
  children: getCopy('heading')
527
543
  }), /*#__PURE__*/_jsx(CloseButton, {
544
+ ref: closeButtonRef,
528
545
  closeButtonBorder: `${closeButtonBorderSize} solid ${closeButtonBorderColor}`,
529
546
  closeButtonWidth: `${closeButtonWidth}px`,
530
547
  closeButtonHeight: `${closeButtonHeight}px`,
@@ -4,6 +4,7 @@ import { transformGradient } from './transforms';
4
4
  import useTypographyTheme from './useTypographyTheme';
5
5
  import media from './media';
6
6
  import ssrStyles from './ssr';
7
+ import isElementFocusable from './isElementFocusable';
7
8
  import renderStructuredContent from './renderStructuredContent';
8
9
  import useOverlaidPosition from './useOverlaidPosition';
9
- export { deprecate, htmlAttrs, transformGradient, useTypographyTheme, warn, media, renderStructuredContent, ssrStyles, useOverlaidPosition };
10
+ export { deprecate, htmlAttrs, transformGradient, useTypographyTheme, warn, media, renderStructuredContent, ssrStyles, isElementFocusable, useOverlaidPosition };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns focusable elements inside of the Footnote
3
+ */
4
+ const isElementFocusable = element => {
5
+ const focusableElements = `a[href], button, textarea, input, select, form, label, audio, video, source, track, canvas, rect, polygon, iframe[data-src], [tabindex]:not([tabindex="-1"]), [contenteditable]`;
6
+ return element.matches(focusableElements) && !element.hasAttribute('disabled') && !element.matches('[tabindex="-1"]');
7
+ };
8
+ export default isElementFocusable;
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.85.1",
8
+ "@telus-uds/components-base": "1.86.0",
9
9
  "@telus-uds/system-constants": "^1.3.0",
10
10
  "fscreen": "^1.2.0",
11
11
  "lodash.omit": "^4.5.0",
@@ -13,7 +13,7 @@
13
13
  "react-dates": "^21.8.0",
14
14
  "react-helmet-async": "^1.3.0",
15
15
  "react-moment-proptypes": "^1.8.1",
16
- "@telus-uds/system-theme-tokens": "^2.56.0",
16
+ "@telus-uds/system-theme-tokens": "^2.57.0",
17
17
  "prop-types": "^15.7.2",
18
18
  "lodash.throttle": "^4.1.1",
19
19
  "react-youtube": "^10.1.0",
@@ -83,5 +83,5 @@
83
83
  "skip": true
84
84
  },
85
85
  "types": "types/index.d.ts",
86
- "version": "2.34.2"
86
+ "version": "2.34.3"
87
87
  }
@@ -15,7 +15,7 @@ import {
15
15
  } from '@telus-uds/components-base'
16
16
 
17
17
  import OrderedListBase from '../OrderedList/OrderedListBase'
18
- import { htmlAttrs, media, renderStructuredContent } from '../utils'
18
+ import { htmlAttrs, media, renderStructuredContent, isElementFocusable } from '../utils'
19
19
  import defaultDictionary from './dictionary'
20
20
 
21
21
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
@@ -263,7 +263,7 @@ const Footnote = React.forwardRef((props, ref) => {
263
263
  const headerRef = React.useRef(null)
264
264
  const bodyRef = React.useRef(null)
265
265
  const contentRef = React.useRef(null)
266
- const headingRef = React.useRef(null)
266
+ const closeButtonRef = React.useRef(null)
267
267
  const [data, setData] = React.useState({ content: null, number: null })
268
268
  const [headerHeight, setHeaderHeight] = React.useState('auto')
269
269
  const [bodyHeight, setBodyHeight] = React.useState('auto')
@@ -283,8 +283,14 @@ const Footnote = React.forwardRef((props, ref) => {
283
283
  [onClose]
284
284
  )
285
285
 
286
- // Listen for ESCAPE, close button clicks, and clicks outside of the Footnote. Call onClose.
287
- const handleClose = React.useCallback(
286
+ /**
287
+ * When listen for ESCAPE, close button clicks, and clicks outside of the Footnote. Call onClose.
288
+ * When the event type is a 'keydonw' and the event key is a 'Tab', using a 'querySelectorAll we obtain all
289
+ * the interactive elements within the footnote, we order and save the first and the last,
290
+ * if the footnote is active the focus will be inside the footnote until it is closed,
291
+ * if there are no interactive elements the focus will remain inside the close button.
292
+ */
293
+ const manageFootnoteFocusAndClose = React.useCallback(
288
294
  (event) => {
289
295
  if (!isVisible) {
290
296
  return
@@ -293,6 +299,20 @@ const Footnote = React.forwardRef((props, ref) => {
293
299
  if (event.type === 'keydown') {
294
300
  if (event.key === 'Escape' || event.key === 27) {
295
301
  closeFootnote(event, { returnFocus: true })
302
+ } else if (event.key === 'Tab') {
303
+ const focusableElements = Array.from(footnoteRef.current.querySelectorAll('*')).filter(
304
+ isElementFocusable
305
+ )
306
+ const firstElement = focusableElements[0]
307
+ const lastElement = focusableElements[focusableElements.length - 1]
308
+
309
+ if (event.shiftKey && document.activeElement === firstElement) {
310
+ event.preventDefault()
311
+ lastElement.focus()
312
+ } else if (!event.shiftKey && document.activeElement === lastElement) {
313
+ event.preventDefault()
314
+ firstElement.focus()
315
+ }
296
316
  }
297
317
  } else if (
298
318
  (event.type === 'click' || event.type === 'mousedown') &&
@@ -321,8 +341,8 @@ const Footnote = React.forwardRef((props, ref) => {
321
341
  }
322
342
 
323
343
  const focusHeading = () => {
324
- if (Boolean(content) && isVisible && headingRef && headingRef.current !== null) {
325
- headingRef.current.focus()
344
+ if (Boolean(content) && isVisible && closeButtonRef && closeButtonRef.current !== null) {
345
+ closeButtonRef.current.focus()
326
346
  }
327
347
  }
328
348
 
@@ -376,22 +396,22 @@ const Footnote = React.forwardRef((props, ref) => {
376
396
  React.useEffect(() => {
377
397
  if (isOpen) {
378
398
  setIsVisible(true)
379
- document.addEventListener('mousedown', handleClose)
380
- window.addEventListener('click', handleClose)
381
- window.addEventListener('keydown', handleClose)
382
- window.addEventListener('touchstart', handleClose)
399
+ document.addEventListener('mousedown', manageFootnoteFocusAndClose)
400
+ window.addEventListener('click', manageFootnoteFocusAndClose)
401
+ window.addEventListener('keydown', manageFootnoteFocusAndClose)
402
+ window.addEventListener('touchstart', manageFootnoteFocusAndClose)
383
403
  window.addEventListener('touchmove', preventDefault, { passive: false })
384
404
  }
385
405
  return () => {
386
406
  if (isOpen) {
387
- document.removeEventListener('mousedown', handleClose)
388
- window.removeEventListener('click', handleClose)
389
- window.removeEventListener('keydown', handleClose)
390
- window.removeEventListener('touchstart', handleClose)
407
+ document.removeEventListener('mousedown', manageFootnoteFocusAndClose)
408
+ window.removeEventListener('click', manageFootnoteFocusAndClose)
409
+ window.removeEventListener('keydown', manageFootnoteFocusAndClose)
410
+ window.removeEventListener('touchstart', manageFootnoteFocusAndClose)
391
411
  window.removeEventListener('touchmove', preventDefault)
392
412
  }
393
413
  }
394
- }, [handleClose, isOpen])
414
+ }, [manageFootnoteFocusAndClose, isOpen])
395
415
 
396
416
  // Set data if opening a new footnote
397
417
  React.useEffect(() => {
@@ -496,7 +516,6 @@ const Footnote = React.forwardRef((props, ref) => {
496
516
  <ContentContainer maxWidth={maxWidth}>
497
517
  <StyledFootnoteHeader ref={headerRef} viewport={viewport}>
498
518
  <StyledHeader
499
- ref={headingRef}
500
519
  footnoteHeaderPaddingLeft={footnoteHeaderPaddingLeft}
501
520
  footnoteHeaderPaddingRight={footnoteHeaderPaddingRight}
502
521
  footnoteHeaderPaddingTop={footnoteHeaderPaddingTop}
@@ -513,6 +532,7 @@ const Footnote = React.forwardRef((props, ref) => {
513
532
  {getCopy('heading')}
514
533
  </Typography>
515
534
  <CloseButton
535
+ ref={closeButtonRef}
516
536
  closeButtonBorder={`${closeButtonBorderSize} solid ${closeButtonBorderColor}`}
517
537
  closeButtonWidth={`${closeButtonWidth}px`}
518
538
  closeButtonHeight={`${closeButtonHeight}px`}
@@ -4,6 +4,7 @@ import { transformGradient } from './transforms'
4
4
  import useTypographyTheme from './useTypographyTheme'
5
5
  import media from './media'
6
6
  import ssrStyles from './ssr'
7
+ import isElementFocusable from './isElementFocusable'
7
8
  import renderStructuredContent from './renderStructuredContent'
8
9
  import useOverlaidPosition from './useOverlaidPosition'
9
10
 
@@ -16,5 +17,6 @@ export {
16
17
  media,
17
18
  renderStructuredContent,
18
19
  ssrStyles,
20
+ isElementFocusable,
19
21
  useOverlaidPosition
20
22
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Returns focusable elements inside of the Footnote
3
+ */
4
+ const isElementFocusable = (element) => {
5
+ const focusableElements = `a[href], button, textarea, input, select, form, label, audio, video, source, track, canvas, rect, polygon, iframe[data-src], [tabindex]:not([tabindex="-1"]), [contenteditable]`
6
+ return (
7
+ element.matches(focusableElements) &&
8
+ !element.hasAttribute('disabled') &&
9
+ !element.matches('[tabindex="-1"]')
10
+ )
11
+ }
12
+
13
+ export default isElementFocusable