import { MaybeElementRef , useRef } from "@chakra-ui/vue-utils" ; import { AnyFunction , focus , getAllFocusable , getFirstFocusable , } from "@chakra-ui/utils" ; import { watch , ref , Ref , UnwrapRef , onBeforeUnmount , nextTick } from "vue" ; import { createFocusTrap } from "focus-trap" ; import type { ActivateOptions , DeactivateOptions , FocusTarget , FocusTrap , Options , } from "focus-trap" ; export interface UseFocusLockOptions extends Options { /**
     * Immediately activate the trap
     */ immediate ? : boolean ; } export interface UseFocusLockReturn { /**
     * Indicates if the focus trap is currently active
     */ hasFocus : Ref < boolean > ; /**
     * Indicates if the focus trap is currently paused
     */ isPaused : Ref < boolean > ; link param opts activate : ( opts ? : ActivateOptions ) => void ; link param opts deactivate : ( opts ? : DeactivateOptions ) => void ; link pause : AnyFunction ; link unpause : AnyFunction ; /**
     * Node ref getter for initial focus element inside the focus trap
     */ initialFocus : ( el : UnwrapRef < MaybeElementRef > ) => void ; /**
     * Node ref of the actual content node towhich focus lock should be scoped
     */ content : ( el : UnwrapRef < MaybeElementRef > ) => void ; /**
     * Node ref getter for focus lock element
     */ lock : ( el : UnwrapRef < MaybeElementRef > ) => void ; } param target param options export function useFocusLock ( options = { } ) { let trap ; const [ lock , lockEl ] = useRef ( ) ; const [ initialFocus , initialFocusEl ] = useRef ( ) ; const [ content , contentEl ] = useRef ( ) ; const { immediate , ... focusLockOptions } = options ; const hasFocus = ref ( false ) ; const isPaused = ref ( false ) ; const activate = ( opts ? ) => setTimeout ( ( ) => trap && trap . activate ( opts ) ) ; const deactivate = ( opts ? ) => setTimeout ( ( ) => trap && trap . deactivate ( opts ) ) ; const pause = ( ) => { if ( trap ) { trap . pause ( ) ; isPaused . value = true ; } } ; const unpause = ( ) => { if ( trap ) { trap . unpause ( ) ; isPaused . value = false ; } } ; watch ( lockEl , ( el ) => { nextTick ( ) . then ( ( ) => { if ( ! el ) return ; trap = createFocusTrap ( el , { initialFocus : initialFocusEl . value as FocusTarget , ... focusLockOptions , onActivate ( ) { hasFocus . value = true ; const container = contentEl . value || el ; let initialFocus = initialFocusEl . value ?? getFirstFocusable ( el ) ; if ( initialFocusEl . value ) { initialFocus = initialFocusEl . value ; } else { const focusables = getAllFocusable ( contentEl . value || el ) ; if ( focusables . length ) { ; [ initialFocus ] = focusables . filter ( ( el ) => el !== container ) ; } } setTimeout ( ( ) => focus ( initialFocus ) ) ; if ( options . onActivate ) options . onActivate ( ) ; } , onDeactivate ( ) { hasFocus . value = false ; if ( options . onDeactivate ) options . onDeactivate ( ) ; } , } ) ; if ( immediate ) activate ( ) ; } ) ; } , { flush : "post" , immediate : true } ) ; onBeforeUnmount ( ( ) => { deactivate ( ) ; } ) ; return { lock , initialFocus , hasFocus , isPaused , activate , deactivate , pause , unpause , content , } ; }