Spaces:
Runtime error
Runtime error
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'; | |
interface DialogButtonProps { | |
type: 'primary' | 'secondary' | 'danger'; | |
children: ReactNode; | |
onClick?: (event: React.MouseEvent) => void; | |
disabled?: boolean; | |
} | |
export const DialogButton = memo(({ type, children, onClick, disabled }: DialogButtonProps) => { | |
return ( | |
<button | |
className={classNames('inline-flex items-center gap-2 px-4 py-2 rounded-lg text-sm transition-colors', { | |
'bg-purple-500 text-white hover:bg-purple-600 dark:bg-purple-500 dark:hover:bg-purple-600': type === 'primary', | |
'bg-transparent text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-gray-100': | |
type === 'secondary', | |
'bg-transparent text-red-500 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-500/10': type === 'danger', | |
})} | |
onClick={onClick} | |
disabled={disabled} | |
> | |
{children} | |
</button> | |
); | |
}); | |
export const DialogTitle = memo(({ className, children, ...props }: RadixDialog.DialogTitleProps) => { | |
return ( | |
<RadixDialog.Title | |
className={classNames('text-lg font-medium text-bolt-elements-textPrimary', 'flex items-center gap-2', className)} | |
{...props} | |
> | |
{children} | |
</RadixDialog.Title> | |
); | |
}); | |
export const DialogDescription = memo(({ className, children, ...props }: RadixDialog.DialogDescriptionProps) => { | |
return ( | |
<RadixDialog.Description | |
className={classNames('text-sm text-bolt-elements-textSecondary', 'mt-1', className)} | |
{...props} | |
> | |
{children} | |
</RadixDialog.Description> | |
); | |
}); | |
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 DialogProps { | |
children: ReactNode; | |
className?: string; | |
showCloseButton?: boolean; | |
onClose?: () => void; | |
onBackdrop?: () => void; | |
} | |
export const Dialog = memo(({ children, className, showCloseButton = true, onClose, onBackdrop }: DialogProps) => { | |
return ( | |
<RadixDialog.Portal> | |
<RadixDialog.Overlay asChild> | |
<motion.div | |
className={classNames( | |
'fixed inset-0 z-[9999]', | |
'bg-[#FAFAFA]/80 dark:bg-[#0A0A0A]/80', | |
'backdrop-blur-[2px]', | |
)} | |
initial="closed" | |
animate="open" | |
exit="closed" | |
variants={dialogBackdropVariants} | |
onClick={onBackdrop} | |
/> | |
</RadixDialog.Overlay> | |
<RadixDialog.Content asChild> | |
<motion.div | |
className={classNames( | |
'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2', | |
'bg-[#FAFAFA] dark:bg-[#0A0A0A]', | |
'rounded-lg shadow-lg', | |
'border border-[#E5E5E5] dark:border-[#1A1A1A]', | |
'z-[9999] w-[520px]', | |
className, | |
)} | |
initial="closed" | |
animate="open" | |
exit="closed" | |
variants={dialogVariants} | |
> | |
<div className="flex flex-col"> | |
{children} | |
{showCloseButton && ( | |
<RadixDialog.Close asChild onClick={onClose}> | |
<IconButton | |
icon="i-ph:x" | |
className="absolute top-3 right-3 text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary" | |
/> | |
</RadixDialog.Close> | |
)} | |
</div> | |
</motion.div> | |
</RadixDialog.Content> | |
</RadixDialog.Portal> | |
); | |
}); | |