@modern-kit/react
Version:
1 lines • 4.17 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../../../src/hooks/useOutsidePointerDown/index.ts"],"sourcesContent":["import { useRef, useMemo } from 'react';\nimport { isMobile } from '@modern-kit/utils';\nimport { useEventListener } from '../useEventListener';\n\n/**\n * @description 특정 요소 외부에서 마우스 또는 터치 이벤트가 발생할 때 호출되는 콜백을 등록하는 커스텀 훅입니다.\n *\n * `useOutsidePointerDown` 훅은 지정된 요소(ref로 지정된 요소) 외부에서 사용자가 마우스를 클릭하거나\n * 터치 이벤트가 발생할 때마다 제공된 `callback` 함수를 호출합니다.\n *\n * 모바일 환경에서는 `touchstart` 이벤트를, 데스크탑 환경에서는 `mousedown` 이벤트를 감지합니다.\n *\n * @template T - HTML 요소의 타입. 기본적으로 `HTMLElement`를 상속합니다.\n * @param {(targetElement: T) => void} callback - 요소 외부에서 포인터 다운 이벤트가 발생할 때 호출되는 콜백 함수입니다.\n * 해당 요소의 레퍼런스를 매개변수로 받습니다.\n * @param {UseOutsidePointerDownOptions} options - `useOutsidePointerDown` 훅의 옵션 객체입니다.\n * @param {React.RefObject<HTMLElement>[]} options.excludeRefs - 외부 클릭 및 터치 감지를 제외할 요소의 ref 배열입니다.\n *\n * @returns {React.RefObject<T>} - 외부 클릭 감지를 원하는 DOM 요소에 연결할 ref 객체를 반환합니다.\n *\n * @example\n * ```tsx\n * const Example = () => {\n * const targetRef = useOutsidePointerDown<HTMLDivElement>((targetElement) => {\n * console.log('외부 클릭 감지:', targetElement);\n * });\n *\n * return (\n * <div ref={targetRef}>\n * target box\n * </div>\n * );\n * };\n * ```\n *\n * @example\n * ```tsx\n * const Example = () => {\n * // 외부 요소에서 특정 요소를 제외하고 클릭/터치 감지\n * const excludeRef = useRef<HTMLDivElement>(null);\n * const targetRef = useOutsidePointerDown<HTMLDivElement>(callback, { excludeRefs: [excludeRef] });\n *\n * return (\n * <div>\n * <div ref={targetRef}>\n * target box\n * </div>\n * <div ref={excludeRef}>\n * exclude box\n * </div>\n * </div>\n * );\n * };\n * ```\n */\nexport function useOutsidePointerDown<T extends HTMLElement>(\n callback: (targetElement: T) => void,\n options?: { excludeRefs: React.RefObject<HTMLElement>[] }\n): { ref: React.RefObject<T> } {\n const { excludeRefs } = options ?? {};\n const targetRef = useRef<T>(null);\n const eventType = useMemo(\n () => (isMobile() ? 'touchstart' : 'mousedown'),\n []\n );\n\n const handleOutsidePointerDown = ({ target }: MouseEvent | TouchEvent) => {\n if (!targetRef.current) return;\n const targetElement = targetRef.current;\n\n const isInExcluded = excludeRefs?.some((excludeRef) =>\n excludeRef.current?.contains(target as Node)\n );\n const isOutside = !targetElement.contains(target as Node);\n const shouldTriggerCallback = isOutside && !isInExcluded;\n\n if (shouldTriggerCallback) {\n callback(targetElement);\n }\n };\n\n useEventListener(\n typeof document !== 'undefined' ? document : null,\n eventType,\n handleOutsidePointerDown\n );\n\n return { ref: targetRef };\n}\n"],"names":[],"mappings":";;;;;;AAuDO,SAAS,qBAAA,CACd,UACA,OAAA,EAC6B;AAC7B,EAAA,MAAM,EAAE,WAAA,EAAY,GAAI,OAAA,IAAW,EAAC;AACpC,EAAA,MAAM,SAAA,GAAY,OAAU,IAAI,CAAA;AAChC,EAAA,MAAM,SAAA,GAAY,OAAA;AAAA,IAChB,MAAO,QAAA,EAAS,GAAI,YAAA,GAAe,WAAA;AAAA,IACnC;AAAC,GACH;AAEA,EAAA,MAAM,wBAAA,GAA2B,CAAC,EAAE,MAAA,EAAO,KAA+B;AACxE,IAAA,IAAI,CAAC,UAAU,OAAA,EAAS;AACxB,IAAA,MAAM,gBAAgB,SAAA,CAAU,OAAA;AAEhC,IAAA,MAAM,eAAe,WAAA,EAAa,IAAA;AAAA,MAAK,CAAC,UAAA,KACtC,UAAA,CAAW,OAAA,EAAS,SAAS,MAAc;AAAA,KAC7C;AACA,IAAA,MAAM,SAAA,GAAY,CAAC,aAAA,CAAc,QAAA,CAAS,MAAc,CAAA;AACxD,IAAA,MAAM,qBAAA,GAAwB,aAAa,CAAC,YAAA;AAE5C,IAAA,IAAI,qBAAA,EAAuB;AACzB,MAAA,QAAA,CAAS,aAAa,CAAA;AAAA,IACxB;AAAA,EACF,CAAA;AAEA,EAAA,gBAAA;AAAA,IACE,OAAO,QAAA,KAAa,WAAA,GAAc,QAAA,GAAW,IAAA;AAAA,IAC7C,SAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,OAAO,EAAE,KAAK,SAAA,EAAU;AAC1B;;;;"}