From cd425240a0dbfbbe409ec5f9a70c6784da995dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Leszczyk?= Date: Sun, 13 Mar 2022 10:44:20 +0100 Subject: [PATCH] feat(dashboard-v2): implement PopoverMenu --- .../src/components/PopoverMenu/PopoverMenu.js | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/packages/dashboard-v2/src/components/PopoverMenu/PopoverMenu.js b/packages/dashboard-v2/src/components/PopoverMenu/PopoverMenu.js index e69de29b..1826cd92 100644 --- a/packages/dashboard-v2/src/components/PopoverMenu/PopoverMenu.js +++ b/packages/dashboard-v2/src/components/PopoverMenu/PopoverMenu.js @@ -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 ( + + {Children.only( + cloneElement(children, { + onClick: () => setOpen((open) => !open), + className: `${children.props.className ?? ""} ${open ? openClassName : ""}`, + }) + )} + {open && ( + + {options.map(({ label, callback }) => ( + + ))} + + )} + + ); +}; + +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, +};