File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 11import { useEffect , useRef , useState } from "react" ;
22import "./BorderedAppMenu.scss" ;
33import useSystemSettings from "../../../stores/systemSettingsStore" ;
4+ import useDetectClickOutside from "../../../hooks/useDetectClickOutside" ;
45
56export interface BorderedAppMenuItemProps {
67 title : string ;
@@ -155,6 +156,9 @@ function BorderedAppMenu({ title, items }: BorderedAppMenuProps) {
155156 position . current = { x : ( rect ?. left ?? 0 ) - 12 , y : rect ?. height ?? 0 } ;
156157 } , [ elementRef ] ) ;
157158
159+ // Close the menu if an outside click occurs
160+ useDetectClickOutside ( { elementRef, onClick : ( ) => setOpen ( false ) } ) ;
161+
158162 return (
159163 < div
160164 ref = { elementRef }
Original file line number Diff line number Diff line change 1+ import React , { useEffect } from "react" ;
2+
3+ interface UseDetectClickOutsideProps < Element extends HTMLElement > {
4+ /**
5+ * A reference to the top-most element./
6+ * Clicks on any parents of this element will trigger the callback.
7+ * Clicking this element or any of it's children will not trigger the callback.
8+ */
9+ elementRef : React . RefObject < Element > ;
10+
11+ /**
12+ * The callback to be invoked when a click
13+ * has been detected outside
14+ */
15+ onClick : ( ) => void ;
16+ }
17+
18+ /**
19+ * Detects a click that has occurred outside of the specified element.
20+ */
21+ function useDetectClickOutside < Element extends HTMLElement > ( {
22+ elementRef,
23+ onClick,
24+ } : UseDetectClickOutsideProps < Element > ) {
25+ useEffect ( ( ) => {
26+ function clickHandler ( e : MouseEvent ) {
27+ // If the element has been clicked on, we dont want to invoke the callback
28+ if ( e . target === elementRef . current ) return ;
29+
30+ for ( const child of elementRef . current ?. childNodes ?? [ ] ) {
31+ // If any of the elements children have been clicked,
32+ // we dont want to invoke the callback
33+ if ( e . target === child ) return ;
34+ }
35+
36+ // Click must be outside, so invoke callback
37+ onClick ( ) ;
38+ }
39+
40+ window . addEventListener ( "click" , clickHandler ) ;
41+
42+ return ( ) => window . removeEventListener ( "click" , clickHandler ) ;
43+ } ) ;
44+ }
45+
46+ export default useDetectClickOutside ;
You can’t perform that action at this time.
0 commit comments