1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-26 12:29:06 +01:00
metamask-extension/ui/components/component-library/popover/popover.tsx
2023-05-29 16:16:11 -07:00

134 lines
3.2 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { createPortal } from 'react-dom';
import { usePopper } from 'react-popper';
import classnames from 'classnames';
import {
AlignItems,
BackgroundColor,
BorderColor,
BorderRadius,
Display,
JustifyContent,
} from '../../../helpers/constants/design-system';
import Box from '../../ui/box/box';
import { PopoverPosition, PopoverProps, PopoverRole } from '.';
export const Popover = ({
children,
className = '',
position = PopoverPosition.Auto,
role = PopoverRole.Tooltip,
hasArrow = false,
matchWidth,
preventOverflow = false,
offset = [0, 8],
flip = false,
referenceHidden = true,
referenceElement,
isOpen,
title,
isPortal = false,
arrowProps,
onPressEscKey,
...props
}: PopoverProps) => {
const [popperElement, setPopperElement] = useState<HTMLElement | null>(null);
const [arrowElement, setArrowElement] = useState<HTMLElement | null>(null);
// Define Popper options
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: position,
modifiers: [
{
name: 'preventOverflow',
enabled: position === PopoverPosition.Auto ? true : preventOverflow,
},
{
name: 'flip',
enabled: position === PopoverPosition.Auto ? true : flip,
},
{
name: 'arrow',
enabled: hasArrow,
options: {
element: arrowElement,
},
},
{
name: 'offset',
options: {
offset,
},
},
],
});
// Define width to match reference element or auto
const contentStyle = {
width: matchWidth ? referenceElement?.clientWidth : 'auto',
};
// Esc key press
const handleEscKey = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
// Close the popover when the "Esc" key is pressed
if (onPressEscKey) {
onPressEscKey();
}
}
};
useEffect(() => {
document.addEventListener('keydown', handleEscKey);
return () => {
document.removeEventListener('keydown', handleEscKey);
};
}, [onPressEscKey]);
const PopoverContent = (
<Box
borderColor={BorderColor.borderMuted}
borderRadius={BorderRadius.LG}
backgroundColor={BackgroundColor.backgroundDefault}
padding={4}
role={role}
className={classnames(
'mm-popover',
{
'mm-popover--open': Boolean(isOpen),
'mm-popover--reference-hidden': Boolean(referenceHidden),
},
className,
)}
ref={setPopperElement}
{...attributes.popper}
{...props}
style={{ ...styles.popper, ...contentStyle, ...props.style }}
>
{children}
{hasArrow && (
<Box
borderColor={BorderColor.borderMuted}
className={classnames('mm-popover__arrow')}
ref={setArrowElement}
display={Display.Flex}
justifyContent={JustifyContent.center}
alignItems={AlignItems.center}
style={styles.arrow}
{...attributes.arrow}
{...arrowProps}
/>
)}
</Box>
);
return (
<>
{isPortal
? isOpen && createPortal(PopoverContent, document.body)
: isOpen && PopoverContent}
</>
);
};