119 lines
3.5 KiB
TypeScript

/* -------------------------------------------------------------------------- */
/* Imports */
/* -------------------------------------------------------------------------- */
import React, { Fragment } from "react";
import { Menu, Transition } from "@headlessui/react";
import { PropsPartion } from "./ContextMenuItem";
import classNames from "classnames";
import { SVGCaretDown } from "components/icons";
type ChildType = React.ReactElement<any & PropsPartion[]>;
type ChildrenType = ChildType[] | ChildType;
/* -------------------------------------------------------------------------- */
/* Component props */
/* -------------------------------------------------------------------------- */
type MenuProps = {
emphasis?: "high" | "low";
disabled?: boolean;
className?: string | undefined;
button: React.ReactNode;
children: ChildrenType;
};
/* -------------------------------------------------------------------------- */
/* Styles */
/* -------------------------------------------------------------------------- */
const MenuButtonStyle = `
items-center
inline-flex
justify-center w-full
cursor-default
rounded
border border-gray-100
outline-8
py-2
pl-4
pr-1
text-base`;
const MenuItemStyle = `
absolute
left-0
mt-2 w-60
origin-top-left
rounded
bg-white
shadow-lg
focus:outline-none
py-2 px-4 sm:text-sm`;
/* -------------------------------------------------------------------------- */
/* Component implementation */
/* -------------------------------------------------------------------------- */
/**
* Use width ContextMenuAction.tsx , for example:
* <ContextMenu button="MyButton" emphasis="low/high">
* <ContextMenuAction
* caption="First Menu"
* icon={icon}
* action={() => alert('click')}
* ></ContextMenuAction>
* ...
* </ContextMenu>
*/
export default function ContextMenu({
button,
children,
className,
emphasis = "low",
}: MenuProps) {
return (
<Menu as="div" className="relative inline-block text-right">
{({ open }) => (
<>
<Menu.Button
className={classNames([
`${MenuButtonStyle}`,
{
"hover:bg-gray-100 font-bold uppercase": emphasis === "high",
},
className,
])}
>
{button}
<SVGCaretDown
className={`${
open ? "rotate-180 transform" : "font-normal"
} my-2 mx-3 w-4 flex-center fill-gray-900 stroke-gray-900`}
aria-hidden="true"
/>
</Menu.Button>
<Transition
as={Fragment}
show={open}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
static
className={classNames([
className,
`${MenuItemStyle}`,
{ "ml-2": emphasis === "high" },
])}
>
{children}
</Menu.Items>
</Transition>
</>
)}
</Menu>
);
}