123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- // @flow
- import { makeStyles } from '@material-ui/core';
- import clsx from 'clsx';
- import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
- import { useSelector } from 'react-redux';
-
- import { getComputedOuterHeight } from '../../../participants-pane/functions';
- import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
- import { showOverflowDrawer } from '../../../toolbox/functions.web';
- import participantsPaneTheme from '../themes/participantsPaneTheme.json';
-
- type Props = {
-
- /**
- * Accessibility label for menu container.
- */
- accessibilityLabel?: string,
-
- /**
- * Children of the context menu.
- */
- children: React$Node,
-
- /**
- * Class name for context menu. Used to overwrite default styles.
- */
- className?: ?string,
-
- /**
- * The entity for which the context menu is displayed.
- */
- entity?: Object,
-
- /**
- * Whether or not the menu is hidden. Used to overwrite the internal isHidden.
- */
- hidden?: boolean,
-
- /**
- * Whether or not the menu is already in a drawer.
- */
- inDrawer?: ?boolean,
-
- /**
- * Whether or not drawer should be open.
- */
- isDrawerOpen?: boolean,
-
- /**
- * Target elements against which positioning calculations are made.
- */
- offsetTarget?: HTMLElement,
-
- /**
- * Callback for click on an item in the menu.
- */
- onClick?: Function,
-
- /**
- * Keydown handler.
- */
- onKeyDown?: Function,
-
- /**
- * Callback for drawer close.
- */
- onDrawerClose?: Function,
-
- /**
- * Callback for the mouse entering the component.
- */
- onMouseEnter?: Function,
-
- /**
- * Callback for the mouse leaving the component.
- */
- onMouseLeave?: Function
- };
-
- const MAX_HEIGHT = 400;
-
- const useStyles = makeStyles(theme => {
- return {
- contextMenu: {
- backgroundColor: theme.palette.ui02,
- borderRadius: `${theme.shape.borderRadius / 2}px`,
- boxShadow: '0px 3px 16px rgba(0, 0, 0, 0.6), 0px 0px 4px 1px rgba(0, 0, 0, 0.25)',
- color: theme.palette.text01,
- ...theme.typography.bodyShortRegular,
- lineHeight: `${theme.typography.bodyShortRegular.lineHeight}px`,
- marginTop: `${(participantsPaneTheme.panePadding * 2) + theme.typography.bodyShortRegular.fontSize}px`,
- position: 'absolute',
- right: `${participantsPaneTheme.panePadding}px`,
- top: 0,
- zIndex: 2,
- maxHeight: `${MAX_HEIGHT}px`,
- overflowY: 'auto'
- },
-
- contextMenuHidden: {
- pointerEvents: 'none',
- visibility: 'hidden'
- },
-
- drawer: {
-
- '& > div': {
- ...theme.typography.bodyShortRegularLarge,
- lineHeight: `${theme.typography.bodyShortRegularLarge.lineHeight}px`,
-
- '& svg': {
- fill: theme.palette.icon01
- }
- },
-
- '& > *:first-child': {
- paddingTop: '15px!important'
- }
- }
- };
- });
-
- const ContextMenu = ({
- accessibilityLabel,
- children,
- className,
- entity,
- hidden,
- inDrawer,
- isDrawerOpen,
- offsetTarget,
- onClick,
- onKeyDown,
- onDrawerClose,
- onMouseEnter,
- onMouseLeave
- }: Props) => {
- const [ isHidden, setIsHidden ] = useState(true);
- const containerRef = useRef<HTMLDivElement | null>(null);
- const styles = useStyles();
- const _overflowDrawer = useSelector(showOverflowDrawer);
-
- useLayoutEffect(() => {
- if (_overflowDrawer) {
- return;
- }
- if (entity && offsetTarget
- && containerRef.current
- && offsetTarget?.offsetParent
- && offsetTarget.offsetParent instanceof HTMLElement
- ) {
- const { current: container } = containerRef;
- const { offsetTop, offsetParent: { offsetHeight, scrollTop } } = offsetTarget;
- const outerHeight = getComputedOuterHeight(container);
- const height = Math.min(MAX_HEIGHT, outerHeight);
-
- container.style.top = offsetTop + height > offsetHeight + scrollTop
- ? `${offsetTop - outerHeight}`
- : `${offsetTop}`;
-
- setIsHidden(false);
- } else {
- hidden === undefined && setIsHidden(true);
- }
- }, [ entity, offsetTarget, _overflowDrawer ]);
-
- useEffect(() => {
- if (hidden !== undefined) {
- setIsHidden(hidden);
- }
- }, [ hidden ]);
-
- if (_overflowDrawer && inDrawer) {
- return (<div
- className = { styles.drawer }
- onClick = { onDrawerClose }>
- {children}
- </div>);
- }
-
- return _overflowDrawer
- ? <JitsiPortal>
- <Drawer
- isOpen = { isDrawerOpen && _overflowDrawer }
- onClose = { onDrawerClose }>
- <div
- className = { styles.drawer }
- onClick = { onDrawerClose }>
- {children}
- </div>
- </Drawer>
- </JitsiPortal>
- : <div
- aria-label = { accessibilityLabel }
- className = { clsx(participantsPaneTheme.ignoredChildClassName,
- styles.contextMenu,
- isHidden && styles.contextMenuHidden,
- className
- ) }
- onClick = { onClick }
- onKeyDown = { onKeyDown }
- onMouseEnter = { onMouseEnter }
- onMouseLeave = { onMouseLeave }
- ref = { containerRef }>
- {children}
- </div>
- ;
- };
-
- export default ContextMenu;
|