Spaces:
Build error
Build error
'use client'; | |
import * as DialogPrimitive from '@radix-ui/react-dialog'; | |
import { VisuallyHidden } from '@radix-ui/react-visually-hidden'; | |
import { cva } from 'class-variance-authority'; | |
import * as React from 'react'; | |
import { CloseButton } from '../button'; | |
import { cn, ComponentAnatomy, defineStyleAnatomy } from '../core/styling'; | |
/* ------------------------------------------------------------------------------------------------- | |
* Anatomy | |
* -----------------------------------------------------------------------------------------------*/ | |
export const ModalAnatomy = defineStyleAnatomy({ | |
overlay: cva([ | |
'UI-Modal__overlay', | |
'fixed inset-0 z-50 bg-black/80', | |
'data-[state=open]:animate-in data-[state=closed]:animate-out', | |
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', | |
// "overflow-y-auto p-0 md:p-4 grid place-items-center", | |
]), | |
content: cva([ | |
'UI-Modal__content', | |
'z-50 grid relative w-full w-full shadow-xl border border-[rgb(255_255_255_/_5%)] max-w-lg gap-4 bg-[--background] p-6 shadow-xl duration-200', | |
'data-[state=open]:animate-in data-[state=closed]:animate-out', | |
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', | |
// "data-[state=open]:slide-in-from-top-[40%] data-[state=closed]:slide-out-to-bottom-[40%]", | |
// "data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]", | |
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95', | |
// process.env.NEXT_PUBLIC_PLATFORM === "desktop" && "mt-10", | |
// process.env.NEXT_PUBLIC_PLATFORM === "desktop" && "select-none", | |
'sm:rounded-xl', | |
]), | |
close: cva(['UI-Modal__close', 'absolute right-4 top-4 !mt-0']), | |
header: cva([ | |
'UI-Modal__header', | |
'flex flex-col space-y-1.5 text-center sm:text-left', | |
]), | |
footer: cva([ | |
'UI-Modal__footer', | |
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', | |
]), | |
title: cva([ | |
'UI-Modal__title', | |
'text-xl font-semibold leading-none tracking-tight', | |
]), | |
description: cva(['UI-Modal__description', 'text-sm text-[--muted]']), | |
}); | |
/* ------------------------------------------------------------------------------------------------- | |
* Modal | |
* -----------------------------------------------------------------------------------------------*/ | |
export type ModalProps = Omit< | |
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root>, | |
'modal' | |
> & | |
Pick< | |
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>, | |
| 'onOpenAutoFocus' | |
| 'onCloseAutoFocus' | |
| 'onEscapeKeyDown' | |
| 'onPointerDownCapture' | |
| 'onInteractOutside' | |
> & | |
ComponentAnatomy<typeof ModalAnatomy> & { | |
/** | |
* Interaction with outside elements will be enabled and other elements will be visible to screen readers. | |
*/ | |
allowOutsideInteraction?: boolean; | |
/** | |
* The button that opens the modal | |
*/ | |
trigger?: React.ReactElement; | |
/** | |
* Title of the modal | |
*/ | |
title?: React.ReactNode; | |
/** | |
* An optional accessible description to be announced when the dialog is opened. | |
*/ | |
description?: React.ReactNode; | |
/** | |
* Footer of the modal | |
*/ | |
footer?: React.ReactNode; | |
/** | |
* Optional replacement for the default close button | |
*/ | |
closeButton?: React.ReactElement; | |
/** | |
* Whether to hide the close button | |
*/ | |
hideCloseButton?: boolean; | |
}; | |
export function Modal(props: ModalProps) { | |
const { | |
allowOutsideInteraction = false, | |
trigger, | |
title, | |
footer, | |
description, | |
children, | |
closeButton, | |
overlayClass, | |
contentClass, | |
closeClass, | |
headerClass, | |
footerClass, | |
titleClass, | |
descriptionClass, | |
hideCloseButton, | |
// Content | |
onOpenAutoFocus, | |
onCloseAutoFocus, | |
onEscapeKeyDown, | |
onPointerDownCapture, | |
onInteractOutside, | |
...rest | |
} = props; | |
return ( | |
<DialogPrimitive.Root modal={!allowOutsideInteraction} {...rest}> | |
{trigger && ( | |
<DialogPrimitive.Trigger asChild>{trigger}</DialogPrimitive.Trigger> | |
)} | |
<DialogPrimitive.Portal> | |
<DialogPrimitive.Overlay | |
className={cn(ModalAnatomy.overlay(), overlayClass)} | |
> | |
<div | |
className={cn( | |
'overflow-y-auto absolute inset-0 grid place-items-center p-0 md:p-4', | |
process.env.NEXT_PUBLIC_PLATFORM === 'desktop' && 'md:p-8' | |
)} | |
> | |
<DialogPrimitive.Content | |
className={cn(ModalAnatomy.content(), contentClass)} | |
onOpenAutoFocus={onOpenAutoFocus} | |
onCloseAutoFocus={onCloseAutoFocus} | |
onEscapeKeyDown={onEscapeKeyDown} | |
onPointerDownCapture={onPointerDownCapture} | |
onInteractOutside={onInteractOutside} | |
> | |
{!title && !description ? ( | |
<VisuallyHidden> | |
<DialogPrimitive.Title>Dialog</DialogPrimitive.Title> | |
</VisuallyHidden> | |
) : ( | |
<div className={cn(ModalAnatomy.header(), headerClass)}> | |
<DialogPrimitive.Title | |
className={cn(ModalAnatomy.title(), titleClass)} | |
> | |
{title} | |
</DialogPrimitive.Title> | |
{description && ( | |
<DialogPrimitive.Description | |
className={cn( | |
ModalAnatomy.description(), | |
descriptionClass | |
)} | |
> | |
{description} | |
</DialogPrimitive.Description> | |
)} | |
</div> | |
)} | |
{children} | |
{footer && ( | |
<div className={cn(ModalAnatomy.footer(), footerClass)}> | |
{footer} | |
</div> | |
)} | |
{!hideCloseButton && ( | |
<DialogPrimitive.Close | |
className={cn(ModalAnatomy.close(), closeClass)} | |
asChild | |
> | |
{closeButton ? closeButton : <CloseButton />} | |
</DialogPrimitive.Close> | |
)} | |
</DialogPrimitive.Content> | |
</div> | |
</DialogPrimitive.Overlay> | |
</DialogPrimitive.Portal> | |
</DialogPrimitive.Root> | |
); | |
} | |
Modal.displayName = 'Modal'; | |