diff --git a/packages/radix-vue/src/shared/index.ts b/packages/radix-vue/src/shared/index.ts index 7cc74fa1f..45c8c29f1 100644 --- a/packages/radix-vue/src/shared/index.ts +++ b/packages/radix-vue/src/shared/index.ts @@ -1,3 +1,4 @@ +export { onFocusOutside } from "./onFocusOutside"; export { useArrowNavigation } from "./useArrowNavigation"; export { useMouseInElement } from "./useMouseInElement"; export { useHoverDelay } from "./useHoverDelay"; diff --git a/packages/radix-vue/src/shared/onFocusOutside.ts b/packages/radix-vue/src/shared/onFocusOutside.ts new file mode 100644 index 000000000..05b4163d6 --- /dev/null +++ b/packages/radix-vue/src/shared/onFocusOutside.ts @@ -0,0 +1,27 @@ +import { type MaybeElementRef, unrefElement } from "@vueuse/core"; +import { onMounted, onUnmounted } from "vue"; + +export const onFocusOutside = ( + element: MaybeElementRef, + handler: (event: FocusEvent) => void +) => { + const handleFocusOut = (ev: FocusEvent) => { + const el = unrefElement(element); + const isFocusInsideElement = el?.contains(ev.relatedTarget as Node); + + if (!isFocusInsideElement) { + handler(ev); + } + }; + + onMounted(() => { + const el = unrefElement(element); + // @ts-ignore + el?.addEventListener("focusout", handleFocusOut); + }); + onUnmounted(() => { + const el = unrefElement(element); + // @ts-ignore + el?.removeEventListener("focusout", handleFocusOut); + }); +};