summaryrefslogtreecommitdiffstats
path: root/src/utils/hooks/use-on-click-outside.tsx
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-06-08 12:07:08 +0200
committerArmand Philippot <git@armandphilippot.com>2022-06-08 12:19:28 +0200
commit58cb40f031f395ca9efccff674ba0f2dae723f50 (patch)
treed69539a66a83da85689b8f7e835492eedc068e1f /src/utils/hooks/use-on-click-outside.tsx
parent43bddd9506d790ad6707fe71f28a4ecfa635c8f1 (diff)
fix(settings): close tooltip when modal is closing
The event was not captured so the tooltip remained open when the settings was closed. It prevented to click on the toolbar buttons.
Diffstat (limited to 'src/utils/hooks/use-on-click-outside.tsx')
-rw-r--r--src/utils/hooks/use-on-click-outside.tsx52
1 files changed, 52 insertions, 0 deletions
diff --git a/src/utils/hooks/use-on-click-outside.tsx b/src/utils/hooks/use-on-click-outside.tsx
new file mode 100644
index 0000000..04827b8
--- /dev/null
+++ b/src/utils/hooks/use-on-click-outside.tsx
@@ -0,0 +1,52 @@
+import { RefObject, useCallback, useEffect, useRef } from 'react';
+
+export type UseOnClickOutsideCallback = (target: Node) => void;
+
+/**
+ * Detect click/focus outside an element and fire a callback function.
+ *
+ * @param {UseOnClickOutsideCallback} callback - A callback function to fire.
+ * @param {boolean} useCapture - Define event propagation method. Default: true.
+ * @returns {RefObject} A React reference object.
+ */
+const useOnClickOutside = <T extends HTMLElement>(
+ callback: UseOnClickOutsideCallback,
+ useCapture: boolean = true
+): RefObject<T> => {
+ const ref = useRef<T | null>(null);
+
+ /**
+ * Check if the target is outside the ref.
+ *
+ * @param {Node} target - The event target.
+ * @returns {boolean | null} True if the target is outside the ref.
+ */
+ const isTargetOutside = (target: Node): boolean | null => {
+ return ref.current && !ref.current.contains(target);
+ };
+
+ /**
+ * Fire the callback if the event target is outside.
+ */
+ const handler = useCallback(
+ (e: MouseEvent | FocusEvent) => {
+ if (e.target && isTargetOutside(e.target as Node))
+ callback(e.target as Node);
+ },
+ [callback]
+ );
+
+ useEffect(() => {
+ document.addEventListener('click', handler, useCapture);
+ document.addEventListener('focusin', handler, useCapture);
+
+ return () => {
+ document.removeEventListener('click', handler);
+ document.removeEventListener('focusin', handler);
+ };
+ }, [handler, useCapture]);
+
+ return ref;
+};
+
+export default useOnClickOutside;