Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ContextMenu.js 4.8KB

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