feat(dashboard-v2): implement PopoverMenu

This commit is contained in:
Michał Leszczyk 2022-03-13 10:44:20 +01:00
parent cb5a162fe4
commit cd425240a0
No known key found for this signature in database
GPG Key ID: FA123CA8BAA2FBF4
1 changed files with 90 additions and 0 deletions

View File

@ -0,0 +1,90 @@
import { Children, cloneElement, useRef, useState } from "react";
import PropTypes from "prop-types";
import { useClickAway } from "react-use";
import styled, { css, keyframes } from "styled-components";
const dropDown = keyframes`
0% {
transform: scaleY(0);
}
80% {
transform: scaleY(1.1);
}
100% {
transform: scaleY(1);
}
`;
const Container = styled.div.attrs({ className: "relative inline-flex" })``;
const Flyout = styled.ul.attrs({
className: `absolute right-0 z-10 py-2
border rounded bg-white
overflow-hidden pointer-events-none
shadow-md shadow-palette-200/50
pointer-events-auto h-auto overflow-visible border-primary`,
})`
top: calc(100% + 2px);
animation: ${css`
${dropDown} 0.1s ease-in-out
`};
`;
const Option = styled.li.attrs({
className: `font-sans text-xs uppercase
relative pl-3 pr-5 py-1
text-palette-600 cursor-pointer
hover:text-primary hover:font-normal
active:text-primary active:font-normal
before:content-[initial] before:absolute before:left-0 before:h-3 before:w-0.5 before:bg-primary before:top-1.5
hover:before:content-['']`,
})``;
export const PopoverMenu = ({ options, children, openClassName, ...props }) => {
const containerRef = useRef();
const [open, setOpen] = useState(false);
useClickAway(containerRef, () => setOpen(false));
const handleChoice = (callback) => () => {
setOpen(false);
callback();
};
return (
<Container ref={containerRef} {...props}>
{Children.only(
cloneElement(children, {
onClick: () => setOpen((open) => !open),
className: `${children.props.className ?? ""} ${open ? openClassName : ""}`,
})
)}
{open && (
<Flyout>
{options.map(({ label, callback }) => (
<Option key={label} onClick={handleChoice(callback)}>
{label}
</Option>
))}
</Flyout>
)}
</Container>
);
};
PopoverMenu.propTypes = {
/**
* Accepts a single child node that will become a menu toggle.
*/
children: PropTypes.element.isRequired,
/**
* Positions in the menu
*/
options: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
callback: PropTypes.func.isRequired,
})
).isRequired,
};