@mantine/hooks
Version:
A collection of 50+ hooks for state and UI management
1 lines • 3.63 kB
Source Map (JSON)
{"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"}