import * as React from 'react'; import { createContextScope } from '@radix-ui/react-context'; import { useComposedRefs } from '@radix-ui/react-compose-refs'; import * as DialogPrimitive from '@radix-ui/react-dialog'; import { createDialogScope } from '@radix-ui/react-dialog'; import { composeEventHandlers } from '@radix-ui/primitive'; import { Slottable } from '@radix-ui/react-slot'; import type { Scope } from '@radix-ui/react-context'; /* ------------------------------------------------------------------------------------------------- * AlertDialog * -----------------------------------------------------------------------------------------------*/ const ROOT_NAME = 'AlertDialog'; type ScopedProps

= P & { __scopeAlertDialog?: Scope }; const [createAlertDialogContext, createAlertDialogScope] = createContextScope(ROOT_NAME, [ createDialogScope, ]); const useDialogScope = createDialogScope(); type DialogProps = React.ComponentPropsWithoutRef; interface AlertDialogProps extends Omit {} const AlertDialog: React.FC = (props: ScopedProps) => { const { __scopeAlertDialog, ...alertDialogProps } = props; const dialogScope = useDialogScope(__scopeAlertDialog); return ; }; AlertDialog.displayName = ROOT_NAME; /* ------------------------------------------------------------------------------------------------- * AlertDialogTrigger * -----------------------------------------------------------------------------------------------*/ const TRIGGER_NAME = 'AlertDialogTrigger'; type AlertDialogTriggerElement = React.ElementRef; type DialogTriggerProps = React.ComponentPropsWithoutRef; interface AlertDialogTriggerProps extends DialogTriggerProps {} const AlertDialogTrigger = React.forwardRef( (props: ScopedProps, forwardedRef) => { const { __scopeAlertDialog, ...triggerProps } = props; const dialogScope = useDialogScope(__scopeAlertDialog); return ; } ); AlertDialogTrigger.displayName = TRIGGER_NAME; /* ------------------------------------------------------------------------------------------------- * AlertDialogPortal * -----------------------------------------------------------------------------------------------*/ const PORTAL_NAME = 'AlertDialogPortal'; type DialogPortalProps = React.ComponentPropsWithoutRef; interface AlertDialogPortalProps extends DialogPortalProps {} const AlertDialogPortal: React.FC = ( props: ScopedProps ) => { const { __scopeAlertDialog, ...portalProps } = props; const dialogScope = useDialogScope(__scopeAlertDialog); return ; }; AlertDialogPortal.displayName = PORTAL_NAME; /* ------------------------------------------------------------------------------------------------- * AlertDialogOverlay * -----------------------------------------------------------------------------------------------*/ const OVERLAY_NAME = 'AlertDialogOverlay'; type AlertDialogOverlayElement = React.ElementRef; type DialogOverlayProps = React.ComponentPropsWithoutRef; interface AlertDialogOverlayProps extends DialogOverlayProps {} const AlertDialogOverlay = React.forwardRef( (props: ScopedProps, forwardedRef) => { const { __scopeAlertDialog, ...overlayProps } = props; const dialogScope = useDialogScope(__scopeAlertDialog); return ; } ); AlertDialogOverlay.displayName = OVERLAY_NAME; /* ------------------------------------------------------------------------------------------------- * AlertDialogContent * -----------------------------------------------------------------------------------------------*/ const CONTENT_NAME = 'AlertDialogContent'; type AlertDialogContentContextValue = { cancelRef: React.MutableRefObject; }; const [AlertDialogContentProvider, useAlertDialogContentContext] = createAlertDialogContext(CONTENT_NAME); type AlertDialogContentElement = React.ElementRef; type DialogContentProps = React.ComponentPropsWithoutRef; interface AlertDialogContentProps extends Omit {} const AlertDialogContent = React.forwardRef( (props: ScopedProps, forwardedRef) => { const { __scopeAlertDialog, children, ...contentProps } = props; const dialogScope = useDialogScope(__scopeAlertDialog); const contentRef = React.useRef(null); const composedRefs = useComposedRefs(forwardedRef, contentRef); const cancelRef = React.useRef(null); return ( { event.preventDefault(); cancelRef.current?.focus({ preventScroll: true }); })} onPointerDownOutside={(event) => event.preventDefault()} onInteractOutside={(event) => event.preventDefault()} > {/** * We have to use `Slottable` here as we cannot wrap the `AlertDialogContentProvider` * around everything, otherwise the `DescriptionWarning` would be rendered straight away. * This is because we want the accessibility checks to run only once the content is actually * open and that behaviour is already encapsulated in `DialogContent`. */} {children} {process.env.NODE_ENV === 'development' && ( )} ); } ); AlertDialogContent.displayName = CONTENT_NAME; /* ------------------------------------------------------------------------------------------------- * AlertDialogTitle * -----------------------------------------------------------------------------------------------*/ const TITLE_NAME = 'AlertDialogTitle'; type AlertDialogTitleElement = React.ElementRef; type DialogTitleProps = React.ComponentPropsWithoutRef; interface AlertDialogTitleProps extends DialogTitleProps {} const AlertDialogTitle = React.forwardRef( (props: ScopedProps, forwardedRef) => { const { __scopeAlertDialog, ...titleProps } = props; const dialogScope = useDialogScope(__scopeAlertDialog); return ; } ); AlertDialogTitle.displayName = TITLE_NAME; /* ------------------------------------------------------------------------------------------------- * AlertDialogDescription * -----------------------------------------------------------------------------------------------*/ const DESCRIPTION_NAME = 'AlertDialogDescription'; type AlertDialogDescriptionElement = React.ElementRef; type DialogDescriptionProps = React.ComponentPropsWithoutRef; interface AlertDialogDescriptionProps extends DialogDescriptionProps {} const AlertDialogDescription = React.forwardRef< AlertDialogDescriptionElement, AlertDialogDescriptionProps >((props: ScopedProps, forwardedRef) => { const { __scopeAlertDialog, ...descriptionProps } = props; const dialogScope = useDialogScope(__scopeAlertDialog); return ; }); AlertDialogDescription.displayName = DESCRIPTION_NAME; /* ------------------------------------------------------------------------------------------------- * AlertDialogAction * -----------------------------------------------------------------------------------------------*/ const ACTION_NAME = 'AlertDialogAction'; type AlertDialogActionElement = React.ElementRef; type DialogCloseProps = React.ComponentPropsWithoutRef; interface AlertDialogActionProps extends DialogCloseProps {} const AlertDialogAction = React.forwardRef( (props: ScopedProps, forwardedRef) => { const { __scopeAlertDialog, ...actionProps } = props; const dialogScope = useDialogScope(__scopeAlertDialog); return ; } ); AlertDialogAction.displayName = ACTION_NAME; /* ------------------------------------------------------------------------------------------------- * AlertDialogCancel * -----------------------------------------------------------------------------------------------*/ const CANCEL_NAME = 'AlertDialogCancel'; type AlertDialogCancelElement = React.ElementRef; interface AlertDialogCancelProps extends DialogCloseProps {} const AlertDialogCancel = React.forwardRef( (props: ScopedProps, forwardedRef) => { const { __scopeAlertDialog, ...cancelProps } = props; const { cancelRef } = useAlertDialogContentContext(CANCEL_NAME, __scopeAlertDialog); const dialogScope = useDialogScope(__scopeAlertDialog); const ref = useComposedRefs(forwardedRef, cancelRef); return ; } ); AlertDialogCancel.displayName = CANCEL_NAME; /* ---------------------------------------------------------------------------------------------- */ type DescriptionWarningProps = { contentRef: React.RefObject; }; const DescriptionWarning: React.FC = ({ contentRef }) => { const MESSAGE = `\`${CONTENT_NAME}\` requires a description for the component to be accessible for screen reader users. You can add a description to the \`${CONTENT_NAME}\` by passing a \`${DESCRIPTION_NAME}\` component as a child, which also benefits sighted users by adding visible context to the dialog. Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${CONTENT_NAME}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component. For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`; React.useEffect(() => { const hasDescription = document.getElementById( contentRef.current?.getAttribute('aria-describedby')! ); if (!hasDescription) console.warn(MESSAGE); }, [MESSAGE, contentRef]); return null; }; const Root = AlertDialog; const Trigger = AlertDialogTrigger; const Portal = AlertDialogPortal; const Overlay = AlertDialogOverlay; const Content = AlertDialogContent; const Action = AlertDialogAction; const Cancel = AlertDialogCancel; const Title = AlertDialogTitle; const Description = AlertDialogDescription; export { createAlertDialogScope, // AlertDialog, AlertDialogTrigger, AlertDialogPortal, AlertDialogOverlay, AlertDialogContent, AlertDialogAction, AlertDialogCancel, AlertDialogTitle, AlertDialogDescription, // Root, Trigger, Portal, Overlay, Content, Action, Cancel, Title, Description, }; export type { AlertDialogProps, AlertDialogTriggerProps, AlertDialogPortalProps, AlertDialogOverlayProps, AlertDialogContentProps, AlertDialogActionProps, AlertDialogCancelProps, AlertDialogTitleProps, AlertDialogDescriptionProps, };