{"version":3,"file":"use-focus-within.mjs","names":[],"sources":["../../src/use-focus-within/use-focus-within.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useCallbackRef } from '../utils';\n\nfunction containsRelatedTarget(event: FocusEvent) {\n  if (event.currentTarget instanceof HTMLElement && event.relatedTarget instanceof HTMLElement) {\n    return event.currentTarget.contains(event.relatedTarget);\n  }\n\n  return false;\n}\n\nexport interface UseFocusWithinOptions {\n  onFocus?: (event: FocusEvent) => void;\n  onBlur?: (event: FocusEvent) => void;\n}\n\nexport interface UseFocusWithinReturnValue<T extends HTMLElement = any> {\n  ref: React.RefCallback<T | null>;\n  focused: boolean;\n}\n\nexport function useFocusWithin<T extends HTMLElement = any>({\n  onBlur,\n  onFocus,\n}: UseFocusWithinOptions = {}): UseFocusWithinReturnValue<T> {\n  const [focused, setFocused] = useState(false);\n  const focusedRef = useRef(false);\n  const previousNode = useRef<T | null>(null);\n\n  const onFocusRef = useCallbackRef(onFocus);\n  const onBlurRef = useCallbackRef(onBlur);\n\n  const _setFocused = useCallback((value: boolean) => {\n    setFocused(value);\n    focusedRef.current = value;\n  }, []);\n\n  const handleFocusIn = useCallback((event: FocusEvent) => {\n    if (!focusedRef.current) {\n      _setFocused(true);\n      onFocusRef(event);\n    }\n  }, []);\n\n  const handleFocusOut = useCallback((event: FocusEvent) => {\n    if (focusedRef.current && !containsRelatedTarget(event)) {\n      _setFocused(false);\n      onBlurRef(event);\n    }\n  }, []);\n\n  const callbackRef: React.RefCallback<T | null> = useCallback(\n    (node) => {\n      if (!node) {\n        return;\n      }\n\n      if (previousNode.current) {\n        previousNode.current.removeEventListener('focusin', handleFocusIn);\n        previousNode.current.removeEventListener('focusout', handleFocusOut);\n      }\n\n      node.addEventListener('focusin', handleFocusIn);\n      node.addEventListener('focusout', handleFocusOut);\n      previousNode.current = node;\n    },\n    [handleFocusIn, handleFocusOut]\n  );\n\n  useEffect(\n    () => () => {\n      if (previousNode.current) {\n        previousNode.current.removeEventListener('focusin', handleFocusIn);\n        previousNode.current.removeEventListener('focusout', handleFocusOut);\n      }\n    },\n    []\n  );\n\n  return { ref: callbackRef, focused };\n}\n\nexport namespace useFocusWithin {\n  export type Options = UseFocusWithinOptions;\n  export type ReturnValue<T extends HTMLElement> = UseFocusWithinReturnValue<T>;\n}\n"],"mappings":";;;;AAGA,SAAS,sBAAsB,OAAmB;AAChD,KAAI,MAAM,yBAAyB,eAAe,MAAM,yBAAyB,YAC/E,QAAO,MAAM,cAAc,SAAS,MAAM,cAAc;AAG1D,QAAO;;AAaT,SAAgB,eAA4C,EAC1D,QACA,YACyB,EAAE,EAAgC;CAC3D,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,aAAa,OAAO,MAAM;CAChC,MAAM,eAAe,OAAiB,KAAK;CAE3C,MAAM,aAAa,eAAe,QAAQ;CAC1C,MAAM,YAAY,eAAe,OAAO;CAExC,MAAM,cAAc,aAAa,UAAmB;AAClD,aAAW,MAAM;AACjB,aAAW,UAAU;IACpB,EAAE,CAAC;CAEN,MAAM,gBAAgB,aAAa,UAAsB;AACvD,MAAI,CAAC,WAAW,SAAS;AACvB,eAAY,KAAK;AACjB,cAAW,MAAM;;IAElB,EAAE,CAAC;CAEN,MAAM,iBAAiB,aAAa,UAAsB;AACxD,MAAI,WAAW,WAAW,CAAC,sBAAsB,MAAM,EAAE;AACvD,eAAY,MAAM;AAClB,aAAU,MAAM;;IAEjB,EAAE,CAAC;CAEN,MAAM,cAA2C,aAC9C,SAAS;AACR,MAAI,CAAC,KACH;AAGF,MAAI,aAAa,SAAS;AACxB,gBAAa,QAAQ,oBAAoB,WAAW,cAAc;AAClE,gBAAa,QAAQ,oBAAoB,YAAY,eAAe;;AAGtE,OAAK,iBAAiB,WAAW,cAAc;AAC/C,OAAK,iBAAiB,YAAY,eAAe;AACjD,eAAa,UAAU;IAEzB,CAAC,eAAe,eAAe,CAChC;AAED,uBACc;AACV,MAAI,aAAa,SAAS;AACxB,gBAAa,QAAQ,oBAAoB,WAAW,cAAc;AAClE,gBAAa,QAAQ,oBAAoB,YAAY,eAAe;;IAGxE,EAAE,CACH;AAED,QAAO;EAAE,KAAK;EAAa;EAAS"}