import * as RadixDialog from '@radix-ui/react-dialog'; import { motion, type Variants } from 'framer-motion'; import React, { memo, type ReactNode } from 'react'; import { classNames } from '~/utils/classNames'; import { cubicEasingFn } from '~/utils/easings'; import { IconButton } from './IconButton'; export { Close as DialogClose, Root as DialogRoot } from '@radix-ui/react-dialog'; const transition = { duration: 0.15, ease: cubicEasingFn, }; export const dialogBackdropVariants = { closed: { opacity: 0, transition, }, open: { opacity: 1, transition, }, } satisfies Variants; export const dialogVariants = { closed: { x: '-50%', y: '-40%', scale: 0.96, opacity: 0, transition, }, open: { x: '-50%', y: '-50%', scale: 1, opacity: 1, transition, }, } satisfies Variants; interface DialogButtonProps { type: 'primary' | 'secondary' | 'danger'; children: ReactNode; onClick?: (event: React.UIEvent) => void; } export const DialogButton = memo(({ type, children, onClick }: DialogButtonProps) => { return ( <button className={classNames( 'inline-flex h-[35px] items-center justify-center rounded-lg px-4 text-sm leading-none focus:outline-none', { 'bg-bolt-elements-button-primary-background text-bolt-elements-button-primary-text hover:bg-bolt-elements-button-primary-backgroundHover': type === 'primary', 'bg-bolt-elements-button-secondary-background text-bolt-elements-button-secondary-text hover:bg-bolt-elements-button-secondary-backgroundHover': type === 'secondary', 'bg-bolt-elements-button-danger-background text-bolt-elements-button-danger-text hover:bg-bolt-elements-button-danger-backgroundHover': type === 'danger', }, )} onClick={onClick} > {children} </button> ); }); export const DialogTitle = memo(({ className, children, ...props }: RadixDialog.DialogTitleProps) => { return ( <RadixDialog.Title className={classNames( 'px-5 py-4 flex items-center justify-between border-b border-bolt-elements-borderColor text-lg font-semibold leading-6 text-bolt-elements-textPrimary', className, )} {...props} > {children} </RadixDialog.Title> ); }); export const DialogDescription = memo(({ className, children, ...props }: RadixDialog.DialogDescriptionProps) => { return ( <RadixDialog.Description className={classNames('px-5 py-4 text-bolt-elements-textPrimary text-md', className)} {...props} > {children} </RadixDialog.Description> ); }); interface DialogProps { children: ReactNode | ReactNode[]; className?: string; onBackdrop?: (event: React.UIEvent) => void; onClose?: (event: React.UIEvent) => void; } export const Dialog = memo(({ className, children, onBackdrop, onClose }: DialogProps) => { return ( <RadixDialog.Portal> <RadixDialog.Overlay onClick={onBackdrop} asChild> <motion.div className="bg-black/50 fixed inset-0 z-max" initial="closed" animate="open" exit="closed" variants={dialogBackdropVariants} /> </RadixDialog.Overlay> <RadixDialog.Content asChild> <motion.div className={classNames( 'fixed top-[50%] left-[50%] z-max max-h-[85vh] w-[90vw] max-w-[450px] translate-x-[-50%] translate-y-[-50%] border border-bolt-elements-borderColor rounded-lg bg-bolt-elements-background-depth-2 shadow-lg focus:outline-none overflow-hidden', className, )} initial="closed" animate="open" exit="closed" variants={dialogVariants} > {children} <RadixDialog.Close asChild onClick={onClose}> <IconButton icon="i-ph:x" className="absolute top-[10px] right-[10px]" /> </RadixDialog.Close> </motion.div> </RadixDialog.Content> </RadixDialog.Portal> ); });