You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Drawer.js 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // @flow
  2. import React, { useEffect, useRef, useState } from 'react';
  3. import { translate } from '../../../base/i18n';
  4. import { Icon, IconArrowUpWide, IconArrowDownWide } from '../../../base/icons';
  5. type Props = {
  6. /**
  7. * Whether the drawer should have a button that expands its size or not.
  8. */
  9. canExpand: ?boolean,
  10. /**
  11. * The component(s) to be displayed within the drawer menu.
  12. */
  13. children: React$Node,
  14. /**
  15. Whether the drawer should be shown or not.
  16. */
  17. isOpen: boolean,
  18. /**
  19. Function that hides the drawer.
  20. */
  21. onClose: Function,
  22. /**
  23. * Invoked to obtain translated strings.
  24. */
  25. t: Function
  26. };
  27. /**
  28. * Component that displays the mobile friendly drawer on web.
  29. *
  30. * @returns {ReactElement}
  31. */
  32. function Drawer({
  33. canExpand,
  34. children,
  35. isOpen,
  36. onClose,
  37. t }: Props) {
  38. const [ expanded, setExpanded ] = useState(false);
  39. const drawerRef: Object = useRef(null);
  40. /**
  41. * Closes the drawer when clicking outside of it.
  42. *
  43. * @param {Event} event - Mouse down event object.
  44. * @returns {void}
  45. */
  46. function handleOutsideClick(event: MouseEvent) {
  47. if (drawerRef.current && !drawerRef.current.contains(event.target)) {
  48. onClose();
  49. }
  50. }
  51. useEffect(() => {
  52. window.addEventListener('mousedown', handleOutsideClick);
  53. return () => {
  54. window.removeEventListener('mousedown', handleOutsideClick);
  55. };
  56. }, [ drawerRef ]);
  57. /**
  58. * Toggles the menu state between expanded/collapsed.
  59. *
  60. * @returns {void}
  61. */
  62. function toggleExpanded() {
  63. setExpanded(!expanded);
  64. }
  65. /**
  66. * KeyPress handler for accessibility.
  67. *
  68. * @param {React.KeyboardEventHandler<HTMLDivElement>} e - The key event to handle.
  69. *
  70. * @returns {void}
  71. */
  72. function onKeyPress(e) {
  73. if (e.key === ' ' || e.key === 'Enter') {
  74. e.preventDefault();
  75. toggleExpanded();
  76. }
  77. }
  78. return (
  79. isOpen ? (
  80. <div
  81. className = { `drawer-menu${expanded ? ' expanded' : ''}` }
  82. ref = { drawerRef }>
  83. {canExpand && (
  84. <div
  85. aria-expanded = { expanded }
  86. aria-label = { expanded ? t('toolbar.accessibilityLabel.collapse')
  87. : t('toolbar.accessibilityLabel.expand') }
  88. className = 'drawer-toggle'
  89. onClick = { toggleExpanded }
  90. onKeyPress = { onKeyPress }
  91. role = 'button'
  92. tabIndex = { 0 }>
  93. <Icon
  94. size = { 24 }
  95. src = { expanded ? IconArrowDownWide : IconArrowUpWide } />
  96. </div>
  97. )}
  98. {children}
  99. </div>
  100. ) : null
  101. );
  102. }
  103. export default translate(Drawer);