119 lines
3.5 KiB
TypeScript
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>
|
|
);
|
|
}
|