95 lines
3.6 KiB
TypeScript
95 lines
3.6 KiB
TypeScript
import { ReactNode, Fragment } from "react";
|
|
import { Dialog, DialogBackdrop, DialogPanel, Transition, TransitionChild } from "@headlessui/react";
|
|
import clsx from "clsx";
|
|
|
|
interface Props {
|
|
className?: string;
|
|
children: ReactNode;
|
|
open: boolean;
|
|
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
|
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl" | "7xl" | "full";
|
|
padding?: "none" | "sm";
|
|
position?: 0 | 1 | 2 | 3 | 4 | 5;
|
|
title?: ReactNode;
|
|
"data-ui-id"?: string;
|
|
}
|
|
export default function Modal({ className, children, open, setOpen, size = "3xl", padding = "sm", position = 5, title, "data-ui-id": dataUiId }: Props) {
|
|
function onClose() {
|
|
setOpen(false);
|
|
}
|
|
return (
|
|
<Dialog
|
|
open={open}
|
|
onClose={onClose}
|
|
as="div"
|
|
className={clsx(
|
|
"text-text-neutral-primary fixed inset-0 overflow-y-auto",
|
|
position === 0 && "z-0",
|
|
position === 1 && "z-10",
|
|
position === 2 && "z-20",
|
|
position === 3 && "z-30",
|
|
position === 4 && "z-40",
|
|
position === 5 && "z-50"
|
|
)}
|
|
>
|
|
<div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
|
<TransitionChild
|
|
as={Fragment}
|
|
enter="ease-out duration-300"
|
|
enterFrom="opacity-0"
|
|
enterTo="opacity-100"
|
|
leave="ease-in duration-200"
|
|
leaveFrom="opacity-100"
|
|
leaveTo="opacity-0"
|
|
>
|
|
<DialogBackdrop className="fixed inset-0 bg-gray-500/75 transition-opacity" />
|
|
</TransitionChild>
|
|
|
|
{/* This element is to trick the browser into centering the modal contents. */}
|
|
<span className="hidden sm:inline-block sm:h-screen sm:align-middle" aria-hidden="true">
|
|
​
|
|
</span>
|
|
<TransitionChild
|
|
as={Fragment}
|
|
enter="ease-out duration-300"
|
|
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
|
leave="ease-in duration-200"
|
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
>
|
|
<DialogPanel
|
|
data-ui-id={dataUiId}
|
|
className={clsx(
|
|
className,
|
|
// Subframe ModalBlank panel radius: rounded-md. Kept: overflow-visible (poppers escape panel), configurable padding/size system, headlessui transitions.
|
|
"bg-surface-neutral-modal relative inline-block w-full transform overflow-visible rounded-md text-left align-bottom shadow-xl transition-all sm:align-middle",
|
|
padding === "none" && "px-0 pt-0 pb-0 sm:my-0 sm:p-0",
|
|
padding === "sm" && "px-4 pt-5 pb-4 sm:my-8 sm:p-6",
|
|
size === "xs" && "sm:max-w-xs",
|
|
size === "sm" && "sm:max-w-sm",
|
|
size === "md" && "sm:max-w-md",
|
|
size === "lg" && "sm:max-w-lg",
|
|
size === "xl" && "sm:max-w-xl",
|
|
size === "2xl" && "sm:max-w-2xl",
|
|
size === "3xl" && "sm:max-w-3xl",
|
|
size === "4xl" && "sm:max-w-4xl",
|
|
size === "5xl" && "sm:max-w-5xl",
|
|
size === "6xl" && "sm:max-w-6xl",
|
|
size === "7xl" && "sm:max-w-7xl",
|
|
size === "full" && "sm:max-w-full"
|
|
)}
|
|
>
|
|
{title && (
|
|
<div className="mb-4 border-b border-border-default pb-4">
|
|
<h3 className="text-lg font-medium">{title}</h3>
|
|
</div>
|
|
)}
|
|
{children}
|
|
</DialogPanel>
|
|
</TransitionChild>
|
|
</div>
|
|
</Dialog>
|
|
);
|
|
}
|