Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

ContextMenu.tsx 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /* eslint-disable lines-around-comment */
  2. import { Theme } from '@mui/material';
  3. import React, { ReactNode, useEffect, useLayoutEffect, useRef, useState } from 'react';
  4. import { useSelector } from 'react-redux';
  5. import { makeStyles } from 'tss-react/mui';
  6. import { getComputedOuterHeight } from '../../../participants-pane/functions';
  7. // @ts-ignore
  8. import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
  9. // @ts-ignore
  10. import { showOverflowDrawer } from '../../../toolbox/functions.web';
  11. import { withPixelLineHeight } from '../../styles/functions.web';
  12. import participantsPaneTheme from '../themes/participantsPaneTheme.json';
  13. type Props = {
  14. /**
  15. * Accessibility label for menu container.
  16. */
  17. accessibilityLabel?: string;
  18. /**
  19. * Children of the context menu.
  20. */
  21. children: ReactNode;
  22. /**
  23. * Class name for context menu. Used to overwrite default styles.
  24. */
  25. className?: string;
  26. /**
  27. * The entity for which the context menu is displayed.
  28. */
  29. entity?: Object;
  30. /**
  31. * Whether or not the menu is hidden. Used to overwrite the internal isHidden.
  32. */
  33. hidden?: boolean;
  34. /**
  35. * Whether or not the menu is already in a drawer.
  36. */
  37. inDrawer?: boolean;
  38. /**
  39. * Whether or not drawer should be open.
  40. */
  41. isDrawerOpen?: boolean;
  42. /**
  43. * Target elements against which positioning calculations are made.
  44. */
  45. offsetTarget?: HTMLElement;
  46. /**
  47. * Callback for click on an item in the menu.
  48. */
  49. onClick?: (e?: React.MouseEvent) => void;
  50. /**
  51. * Callback for drawer close.
  52. */
  53. onDrawerClose?: (e?: React.MouseEvent) => void;
  54. /**
  55. * Keydown handler.
  56. */
  57. onKeyDown?: (e?: React.KeyboardEvent) => void;
  58. /**
  59. * Callback for the mouse entering the component.
  60. */
  61. onMouseEnter?: (e?: React.MouseEvent) => void;
  62. /**
  63. * Callback for the mouse leaving the component.
  64. */
  65. onMouseLeave?: (e?: React.MouseEvent) => void;
  66. };
  67. const MAX_HEIGHT = 400;
  68. const useStyles = makeStyles()((theme: Theme) => {
  69. return {
  70. contextMenu: {
  71. backgroundColor: theme.palette.ui02,
  72. borderRadius: `${Number(theme.shape.borderRadius) / 2}px`,
  73. boxShadow: '0px 3px 16px rgba(0, 0, 0, 0.6), 0px 0px 4px 1px rgba(0, 0, 0, 0.25)',
  74. color: theme.palette.text01,
  75. ...withPixelLineHeight(theme.typography.bodyShortRegular),
  76. marginTop: `${(participantsPaneTheme.panePadding * 2) + theme.typography.bodyShortRegular.fontSize}px`,
  77. position: 'absolute',
  78. right: `${participantsPaneTheme.panePadding}px`,
  79. top: 0,
  80. zIndex: 2,
  81. maxHeight: `${MAX_HEIGHT}px`,
  82. overflowY: 'auto'
  83. },
  84. contextMenuHidden: {
  85. pointerEvents: 'none',
  86. visibility: 'hidden'
  87. },
  88. drawer: {
  89. '& > div': {
  90. ...withPixelLineHeight(theme.typography.bodyShortRegularLarge),
  91. '& svg': {
  92. fill: theme.palette.icon01
  93. }
  94. },
  95. '& > *:first-child': {
  96. paddingTop: '15px!important'
  97. }
  98. }
  99. };
  100. });
  101. const ContextMenu = ({
  102. accessibilityLabel,
  103. children,
  104. className,
  105. entity,
  106. hidden,
  107. inDrawer,
  108. isDrawerOpen,
  109. offsetTarget,
  110. onClick,
  111. onKeyDown,
  112. onDrawerClose,
  113. onMouseEnter,
  114. onMouseLeave
  115. }: Props) => {
  116. const [ isHidden, setIsHidden ] = useState(true);
  117. const containerRef = useRef<HTMLDivElement | null>(null);
  118. const { classes: styles, cx } = useStyles();
  119. const _overflowDrawer = useSelector(showOverflowDrawer);
  120. useLayoutEffect(() => {
  121. if (_overflowDrawer) {
  122. return;
  123. }
  124. if (entity && offsetTarget
  125. && containerRef.current
  126. && offsetTarget?.offsetParent
  127. && offsetTarget.offsetParent instanceof HTMLElement
  128. ) {
  129. const { current: container } = containerRef;
  130. const { offsetTop, offsetParent: { offsetHeight, scrollTop } } = offsetTarget;
  131. const outerHeight = getComputedOuterHeight(container);
  132. const height = Math.min(MAX_HEIGHT, outerHeight);
  133. container.style.top = offsetTop + height > offsetHeight + scrollTop
  134. ? `${offsetTop - outerHeight}`
  135. : `${offsetTop}`;
  136. setIsHidden(false);
  137. } else {
  138. hidden === undefined && setIsHidden(true);
  139. }
  140. }, [ entity, offsetTarget, _overflowDrawer ]);
  141. useEffect(() => {
  142. if (hidden !== undefined) {
  143. setIsHidden(hidden);
  144. }
  145. }, [ hidden ]);
  146. if (_overflowDrawer && inDrawer) {
  147. return (<div
  148. className = { styles.drawer }
  149. onClick = { onDrawerClose }>
  150. {children}
  151. </div>);
  152. }
  153. return _overflowDrawer
  154. ? <JitsiPortal>
  155. <Drawer
  156. isOpen = { isDrawerOpen && _overflowDrawer }
  157. onClose = { onDrawerClose }>
  158. <div
  159. className = { styles.drawer }
  160. onClick = { onDrawerClose }>
  161. {children}
  162. </div>
  163. </Drawer>
  164. </JitsiPortal>
  165. : <div
  166. aria-label = { accessibilityLabel }
  167. className = { cx(participantsPaneTheme.ignoredChildClassName,
  168. styles.contextMenu,
  169. isHidden && styles.contextMenuHidden,
  170. className
  171. ) }
  172. onClick = { onClick }
  173. onKeyDown = { onKeyDown }
  174. onMouseEnter = { onMouseEnter }
  175. onMouseLeave = { onMouseLeave }
  176. ref = { containerRef }>
  177. {children}
  178. </div>;
  179. };
  180. export default ContextMenu;