From 7e7355de8058abfff8fc1f1908e2b66dce0e752b Mon Sep 17 00:00:00 2001 From: Hazem Krimi Date: Thu, 22 Apr 2021 01:52:40 +0100 Subject: [PATCH] Complete menu component --- src/components/Menu/index.tsx | 75 +++++++++++++++++++++++++++++++++-- src/components/Menu/styles.ts | 41 ++++++++++++++++++- src/components/index.tsx | 2 + 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx index 5772ebb..0aea451 100644 --- a/src/components/Menu/index.tsx +++ b/src/components/Menu/index.tsx @@ -1,7 +1,76 @@ +import { useEffect, useRef, useState } from 'react'; import { Wrapper } from './styles'; +import { Text } from '..'; -const Modal = () => { - return ; +type MenuProps = { + className?: string; + items: Array<{ + icon: React.SVGProps; + avoid?: boolean; + label: string; + action: () => void; + }>; + component: string; }; -export default Modal; +const Menu = ({ items, component, className }: MenuProps) => { + const [open, setOpen] = useState(false); + const ref = useRef(null); + + useEffect(() => { + const openMenu = () => setOpen(true); + const handleClickOutside = (event: MouseEvent) => { + if (ref.current && !ref.current.contains(event.target as Node)) { + setOpen(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + (document.querySelector(`#${component}`) as HTMLElement)?.addEventListener( + 'mouseenter', + openMenu + ); + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + (document.querySelector( + `#${component}` + ) as HTMLElement)?.removeEventListener('mouseenter', openMenu); + }; + + // eslint-disable-next-line + }, [ref]); + + return ( + + {open && ( +
    + {items.map(({ icon, label, avoid, action }) => ( + // eslint-disable-next-line +
  • { + setOpen(false); + action(); + }} + key={label} + > + {icon} + {label} +
  • + ))} +
+ )} +
+ ); +}; + +export default Menu; diff --git a/src/components/Menu/styles.ts b/src/components/Menu/styles.ts index 14ea300..8cfc719 100644 --- a/src/components/Menu/styles.ts +++ b/src/components/Menu/styles.ts @@ -1,3 +1,42 @@ import styled from 'styled-components'; -export const Wrapper = styled.div``; +type WrapperProps = { + top: number; + left: number; +}; + +export const Wrapper = styled.div` + ul { + position: fixed; + top: ${({ top }) => top}px; + left: ${({ left }) => left}px; + background: ${({ theme }) => theme.colors.white.main}; + display: grid; + grid-template-columns: auto; + row-gap: 0.5rem; + border-radius: 3px; + padding: 15px 30px 15px 15px; + box-shadow: 1px 1px 15px 0px rgba(50, 59, 105, 0.25); + + li { + cursor: pointer; + display: flex; + flex-direction: row; + + .icon { + margin-right: 10px; + display: flex; + align-items: center; + justify-content: center; + + svg path { + stroke: ${({ theme }) => theme.colors.black.main}; + } + + &.avoid svg path { + stroke: ${({ theme }) => theme.colors.error.main}; + } + } + } + } +`; diff --git a/src/components/index.tsx b/src/components/index.tsx index 711f044..167170c 100644 --- a/src/components/index.tsx +++ b/src/components/index.tsx @@ -12,6 +12,7 @@ import ContextMenu from './ContextMenu'; import Spinner from './Spinner'; import Alert from './Alert'; import CheckBox from './CheckBox'; +import Menu from './Menu'; export { Button, @@ -25,6 +26,7 @@ export { Search, Avatar, ContextMenu, + Menu, Spinner, Alert, CheckBox,