1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00
metamask-extension/ui/components/ui/popover/popover.component.js
2022-03-17 19:23:56 +01:00

224 lines
5.0 KiB
JavaScript

import React, { PureComponent } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { useI18nContext } from '../../../hooks/useI18nContext';
import Box from '../box';
import {
ALIGN_ITEMS,
COLORS,
FLEX_DIRECTION,
JUSTIFY_CONTENT,
} from '../../../helpers/constants/design-system';
const defaultHeaderProps = {
padding: [6, 4, 4],
display: 'flex',
flexDirection: FLEX_DIRECTION.COLUMN,
backgroundColor: COLORS.BACKGROUND_DEFAULT,
borderRadius: 'xl',
};
const defaultContentProps = {
display: 'flex',
flexDirection: FLEX_DIRECTION.COLUMN,
justifyContent: JUSTIFY_CONTENT.FLEX_START,
alignItems: ALIGN_ITEMS.STRETCH,
borderRadius: 'xl',
};
const defaultFooterProps = {
display: 'flex',
justifyContent: JUSTIFY_CONTENT.SPACE_BETWEEN,
padding: [4, 6, 6],
};
const Popover = ({
title,
subtitle = '',
children,
footer,
footerClassName,
onBack,
onClose,
className,
contentClassName,
showArrow,
CustomBackground,
popoverRef,
centerTitle,
headerProps = defaultHeaderProps,
contentProps = defaultContentProps,
footerProps = defaultFooterProps,
}) => {
const t = useI18nContext();
const showHeader = title || onBack || subtitle || onClose;
const Header = () => {
return (
<Box
{...{ ...defaultHeaderProps, ...headerProps }}
className="popover-header"
>
<div
className={classnames(
'popover-header__title',
centerTitle ? 'center' : '',
)}
>
<h2 title="popover">
{onBack ? (
<button
className="fas fa-chevron-left popover-header__button"
title={t('back')}
onClick={onBack}
/>
) : null}
{title}
</h2>
{onClose ? (
<button
className="fas fa-times popover-header__button"
title={t('close')}
data-testid="popover-close"
onClick={onClose}
/>
) : null}
</div>
{subtitle ? (
<p className="popover-header__subtitle">{subtitle}</p>
) : null}
</Box>
);
};
return (
<div className="popover-container">
{CustomBackground ? (
<CustomBackground onClose={onClose} />
) : (
<div className="popover-bg" onClick={onClose} />
)}
<section
className={classnames('popover-wrap', className)}
ref={popoverRef}
>
{showArrow ? <div className="popover-arrow" /> : null}
{showHeader && <Header />}
{children ? (
<Box
className={classnames('popover-content', contentClassName)}
{...{ ...defaultContentProps, ...contentProps }}
>
{children}
</Box>
) : null}
{footer ? (
<Box
className={classnames('popover-footer', footerClassName)}
{...{ ...defaultFooterProps, ...footerProps }}
>
{footer}
</Box>
) : null}
</section>
</div>
);
};
Popover.propTypes = {
/**
* Show title of the popover
*/
title: PropTypes.node,
/**
* Show subtitle label on popover
*/
subtitle: PropTypes.string,
/**
* Show children content could be react child or text
*/
children: PropTypes.node,
/**
* Show footer content could be react child or text
*/
footer: PropTypes.node,
/**
* Add custom CSS class for footer
*/
footerClassName: PropTypes.string,
/**
* onBack handler
*/
onBack: PropTypes.func,
/**
* onClose handler
*/
onClose: PropTypes.func,
CustomBackground: PropTypes.func,
/**
* Add custom CSS class for content
*/
contentClassName: PropTypes.string,
/**
* Add custom CSS class
*/
className: PropTypes.string,
/**
* Check if component would show arror
*/
showArrow: PropTypes.bool,
/**
* The ref of the popover-wrap element
*/
popoverRef: PropTypes.shape({
current: PropTypes.instanceOf(window.Element),
}),
/**
* Check if use centered title
*/
centerTitle: PropTypes.bool,
/**
* Box props for the header
*/
headerProps: PropTypes.shape({ ...Box.propTypes }),
/**
* Box props for the content
*/
contentProps: PropTypes.shape({ ...Box.propTypes }),
/**
* Box props for the footer
*/
footerProps: PropTypes.shape({ ...Box.propTypes }),
};
export default class PopoverPortal extends PureComponent {
static propTypes = Popover.propTypes;
rootNode = document.getElementById('popover-content');
instanceNode = document.createElement('div');
componentDidMount() {
if (!this.rootNode) {
return;
}
this.rootNode.appendChild(this.instanceNode);
}
componentWillUnmount() {
if (!this.rootNode) {
return;
}
this.rootNode.removeChild(this.instanceNode);
}
render() {
const children = <Popover {...this.props} />;
return this.rootNode
? ReactDOM.createPortal(children, this.instanceNode)
: children;
}
}