@loke/ui
Version:
6 lines (3 loc) • 9.3 kB
JavaScript
import{composeEventHandlers}from"@loke/ui/compose-events";import{useComposedRefs}from"@loke/ui/compose-refs";import{createContext,createContextScope}from"@loke/ui/context";import{DismissableLayer}from"@loke/ui/dismissable-layer";import{useFocusGuards}from"@loke/ui/focus-guards";import{FocusScope}from"@loke/ui/focus-scope";import{Portal as PortalPrimitive}from"@loke/ui/portal";import{Presence}from"@loke/ui/presence";import{Primitive}from"@loke/ui/primitive";import{createSlot}from"@loke/ui/slot";import{useControllableState}from"@loke/ui/use-controllable-state";import{useId}from"@loke/ui/use-id";import{hideOthers}from"aria-hidden";import{Children,forwardRef,useCallback,useEffect,useRef}from"react";import{RemoveScroll}from"react-remove-scroll";import{jsx,jsxs,Fragment}from"react/jsx-runtime";var DIALOG_NAME="Dialog",[createDialogContext,createDialogScope]=createContextScope(DIALOG_NAME),[DialogProvider,useDialogContext]=createDialogContext(DIALOG_NAME),Dialog=(props)=>{let{__scopeDialog,children,open:openProp,defaultOpen,onOpenChange,modal=!0}=props,triggerRef=useRef(null),contentRef=useRef(null),[open,setOpen]=useControllableState({caller:DIALOG_NAME,defaultProp:defaultOpen??!1,onChange:onOpenChange,prop:openProp});return jsx(DialogProvider,{contentId:useId(),contentRef,descriptionId:useId(),modal,onOpenChange:setOpen,onOpenToggle:useCallback(()=>setOpen((prevOpen)=>!prevOpen),[setOpen]),open,scope:__scopeDialog,titleId:useId(),triggerRef,children})};Dialog.displayName=DIALOG_NAME;var TRIGGER_NAME="DialogTrigger",DialogTrigger=forwardRef((props,forwardedRef)=>{let{__scopeDialog,...triggerProps}=props,context=useDialogContext(TRIGGER_NAME,__scopeDialog),composedTriggerRef=useComposedRefs(forwardedRef,context.triggerRef);return jsx(Primitive.button,{"aria-controls":context.contentId,"aria-expanded":context.open,"aria-haspopup":"dialog","data-state":getState(context.open),type:"button",...triggerProps,onClick:composeEventHandlers(props.onClick,context.onOpenToggle),ref:composedTriggerRef})});DialogTrigger.displayName=TRIGGER_NAME;var PORTAL_NAME="DialogPortal",[PortalProvider,usePortalContext]=createDialogContext(PORTAL_NAME,{forceMount:void 0}),DialogPortal=(props)=>{let{__scopeDialog,forceMount,children,container}=props,context=useDialogContext(PORTAL_NAME,__scopeDialog);return jsx(PortalProvider,{forceMount,scope:__scopeDialog,children:Children.map(children,(child)=>jsx(Presence,{present:forceMount||context.open,children:jsx(PortalPrimitive,{asChild:!0,container,children:child})}))})};DialogPortal.displayName=PORTAL_NAME;var OVERLAY_NAME="DialogOverlay",DialogOverlay=forwardRef((props,forwardedRef)=>{let portalContext=usePortalContext(OVERLAY_NAME,props.__scopeDialog),{forceMount=portalContext.forceMount,...overlayProps}=props,context=useDialogContext(OVERLAY_NAME,props.__scopeDialog);return context.modal?jsx(Presence,{present:forceMount||context.open,children:jsx(DialogOverlayImpl,{...overlayProps,ref:forwardedRef})}):null});DialogOverlay.displayName=OVERLAY_NAME;var Slot=createSlot("DialogOverlay.RemoveScroll"),DialogOverlayImpl=forwardRef((props,forwardedRef)=>{let{__scopeDialog,...overlayProps}=props,context=useDialogContext(OVERLAY_NAME,__scopeDialog);return jsx(RemoveScroll,{allowPinchZoom:!0,as:Slot,shards:[context.contentRef],children:jsx(Primitive.div,{"data-state":getState(context.open),...overlayProps,ref:forwardedRef,style:{pointerEvents:"auto",...overlayProps.style}})})}),CONTENT_NAME="DialogContent",DialogContent=forwardRef((props,forwardedRef)=>{let portalContext=usePortalContext(CONTENT_NAME,props.__scopeDialog),{forceMount=portalContext.forceMount,...contentProps}=props,context=useDialogContext(CONTENT_NAME,props.__scopeDialog);return jsx(Presence,{present:forceMount||context.open,children:context.modal?jsx(DialogContentModal,{...contentProps,ref:forwardedRef}):jsx(DialogContentNonModal,{...contentProps,ref:forwardedRef})})});DialogContent.displayName=CONTENT_NAME;var DialogContentModal=forwardRef((props,forwardedRef)=>{let context=useDialogContext(CONTENT_NAME,props.__scopeDialog),contentRef=useRef(null),composedRefs=useComposedRefs(forwardedRef,context.contentRef,contentRef);return useEffect(()=>{let content=contentRef.current;if(content)return hideOthers(content)},[]),jsx(DialogContentImpl,{...props,disableOutsidePointerEvents:!0,onCloseAutoFocus:composeEventHandlers(props.onCloseAutoFocus,(event)=>{event.preventDefault(),context.triggerRef.current?.focus()}),onFocusOutside:composeEventHandlers(props.onFocusOutside,(event)=>event.preventDefault()),onPointerDownOutside:composeEventHandlers(props.onPointerDownOutside,(event)=>{let{originalEvent}=event.detail,ctrlLeftClick=originalEvent.button===0&&originalEvent.ctrlKey===!0;if(originalEvent.button===2||ctrlLeftClick)event.preventDefault()}),ref:composedRefs,trapFocus:context.open})}),DialogContentNonModal=forwardRef((props,forwardedRef)=>{let context=useDialogContext(CONTENT_NAME,props.__scopeDialog),hasInteractedOutsideRef=useRef(!1),hasPointerDownOutsideRef=useRef(!1);return jsx(DialogContentImpl,{...props,disableOutsidePointerEvents:!1,onCloseAutoFocus:(event)=>{if(props.onCloseAutoFocus?.(event),!event.defaultPrevented){if(!hasInteractedOutsideRef.current)context.triggerRef.current?.focus();event.preventDefault()}hasInteractedOutsideRef.current=!1,hasPointerDownOutsideRef.current=!1},onInteractOutside:(event)=>{if(props.onInteractOutside?.(event),!event.defaultPrevented){if(hasInteractedOutsideRef.current=!0,event.detail.originalEvent.type==="pointerdown")hasPointerDownOutsideRef.current=!0}let target=event.target;if(context.triggerRef.current?.contains(target))event.preventDefault();if(event.detail.originalEvent.type==="focusin"&&hasPointerDownOutsideRef.current)event.preventDefault()},ref:forwardedRef,trapFocus:!1})}),DialogContentImpl=forwardRef((props,forwardedRef)=>{let{__scopeDialog,trapFocus,onOpenAutoFocus,onCloseAutoFocus,...contentProps}=props,context=useDialogContext(CONTENT_NAME,__scopeDialog),contentRef=useRef(null),composedRefs=useComposedRefs(forwardedRef,contentRef);return useFocusGuards(),jsxs(Fragment,{children:[jsx(FocusScope,{asChild:!0,loop:!0,onMountAutoFocus:onOpenAutoFocus,onUnmountAutoFocus:onCloseAutoFocus,trapped:trapFocus,children:jsx(DismissableLayer,{"aria-describedby":context.descriptionId,"aria-labelledby":context.titleId,"data-state":getState(context.open),id:context.contentId,role:"dialog",...contentProps,onDismiss:()=>context.onOpenChange(!1),ref:composedRefs})}),process.env.NODE_ENV!=="production"&&jsxs(Fragment,{children:[jsx(TitleWarning,{titleId:context.titleId}),jsx(DescriptionWarning,{contentRef,descriptionId:context.descriptionId})]})]})}),TITLE_NAME="DialogTitle",DialogTitle=forwardRef((props,forwardedRef)=>{let{__scopeDialog,...titleProps}=props,context=useDialogContext(TITLE_NAME,__scopeDialog);return jsx(Primitive.h2,{id:context.titleId,...titleProps,ref:forwardedRef})});DialogTitle.displayName=TITLE_NAME;var DESCRIPTION_NAME="DialogDescription",DialogDescription=forwardRef((props,forwardedRef)=>{let{__scopeDialog,...descriptionProps}=props,context=useDialogContext(DESCRIPTION_NAME,__scopeDialog);return jsx(Primitive.p,{id:context.descriptionId,...descriptionProps,ref:forwardedRef})});DialogDescription.displayName=DESCRIPTION_NAME;var CLOSE_NAME="DialogClose",DialogClose=forwardRef((props,forwardedRef)=>{let{__scopeDialog,...closeProps}=props,context=useDialogContext(CLOSE_NAME,__scopeDialog);return jsx(Primitive.button,{type:"button",...closeProps,onClick:composeEventHandlers(props.onClick,()=>context.onOpenChange(!1)),ref:forwardedRef})});DialogClose.displayName=CLOSE_NAME;function getState(open){return open?"open":"closed"}var TITLE_WARNING_NAME="DialogTitleWarning",[WarningProvider,useWarningContext]=createContext(TITLE_WARNING_NAME,{contentName:CONTENT_NAME,docsSlug:"dialog",titleName:TITLE_NAME}),TitleWarning=({titleId})=>{let titleWarningContext=useWarningContext(TITLE_WARNING_NAME),MESSAGE=`\`${titleWarningContext.contentName}\` requires a \`${titleWarningContext.titleName}\` for the component to be accessible for screen reader users.
If you want to hide the \`${titleWarningContext.titleName}\`, you can wrap it with our VisuallyHidden component.
For more information, see https://loke-ds-url.com/components/${titleWarningContext.docsSlug}`;return useEffect(()=>{if(titleId){if(!document.getElementById(titleId))console.error(MESSAGE)}},[MESSAGE,titleId]),null},DESCRIPTION_WARNING_NAME="DialogDescriptionWarning",DescriptionWarning=({contentRef,descriptionId})=>{let MESSAGE=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${useWarningContext(DESCRIPTION_WARNING_NAME).contentName}}.`;return useEffect(()=>{let describedById=contentRef.current?.getAttribute("aria-describedby");if(descriptionId&&describedById){if(!document.getElementById(descriptionId))console.warn(MESSAGE)}},[MESSAGE,contentRef,descriptionId]),null},Root=Dialog,Trigger=DialogTrigger,Portal=DialogPortal,Overlay=DialogOverlay,Content=DialogContent,Title=DialogTitle,Description=DialogDescription,Close=DialogClose;export{createDialogScope,WarningProvider,Trigger,Title,Root,Portal,Overlay,DialogTrigger,DialogTitle,DialogPortal,DialogOverlay,DialogDescription,DialogContent,DialogClose,Dialog,Description,Content,Close};