1- /* eslint-disable no-unused-vars */
2- import React , { useState } from "react" ;
1+ import React , { useState , useRef , useEffect } from "react" ;
32import PropTypes from "prop-types" ;
43import "react-datepicker/dist/react-datepicker.css" ;
54import {
@@ -110,6 +109,18 @@ const ProjectTableColumnHeader = ({
110109 const theme = useTheme ( ) ;
111110 const classes = useStyles ( theme ) ;
112111 const [ isPopoverOpen , setIsPopoverOpen ] = useState ( false ) ;
112+ const columnHeaderRef = useRef ( null ) ;
113+ const popoverContentRef = useRef ( null ) ;
114+ const suppressNextOutsideClickRef = useRef ( false ) ;
115+ const internalInteractionTimeoutRef = useRef ( null ) ;
116+
117+ useEffect ( ( ) => {
118+ return ( ) => {
119+ if ( internalInteractionTimeoutRef . current ) {
120+ clearTimeout ( internalInteractionTimeoutRef . current ) ;
121+ }
122+ } ;
123+ } , [ ] ) ;
113124
114125 // Filter is considered Applied if it is not set
115126 // to the default criteria values.
@@ -157,6 +168,56 @@ const ProjectTableColumnHeader = ({
157168 setIsPopoverOpen ( flag ) ;
158169 } ;
159170
171+ const handleClickOutside = event => {
172+ if ( suppressNextOutsideClickRef . current ) {
173+ suppressNextOutsideClickRef . current = false ;
174+ if ( internalInteractionTimeoutRef . current ) {
175+ clearTimeout ( internalInteractionTimeoutRef . current ) ;
176+ internalInteractionTimeoutRef . current = null ;
177+ }
178+ return ;
179+ }
180+
181+ const target = event ?. target ;
182+
183+ if ( ! target ) {
184+ handlePopoverToggle ( false ) ;
185+ return ;
186+ }
187+
188+ const isWithinTrigger = columnHeaderRef . current ?. contains ( target ) ;
189+ const isWithinContent = popoverContentRef . current ?. contains ( target ) ;
190+
191+ if ( isWithinTrigger || isWithinContent ) {
192+ return ;
193+ }
194+
195+ if ( target instanceof Element ) {
196+ const isWithinDatepicker = target . closest (
197+ ".react-datepicker, .react-datepicker__portal"
198+ ) ;
199+
200+ if ( isWithinDatepicker ) {
201+ return ;
202+ }
203+ }
204+
205+ handlePopoverToggle ( false ) ;
206+ } ;
207+
208+ const handleInternalInteraction = ( ) => {
209+ suppressNextOutsideClickRef . current = true ;
210+
211+ if ( internalInteractionTimeoutRef . current ) {
212+ clearTimeout ( internalInteractionTimeoutRef . current ) ;
213+ }
214+
215+ internalInteractionTimeoutRef . current = setTimeout ( ( ) => {
216+ suppressNextOutsideClickRef . current = false ;
217+ internalInteractionTimeoutRef . current = null ;
218+ } , 150 ) ;
219+ } ;
220+
160221 return (
161222 < div style = { { width : "100%" , height : "100%" } } >
162223 { header . id !== "checkAllProjects" &&
@@ -165,13 +226,18 @@ const ProjectTableColumnHeader = ({
165226 < Popover
166227 containerStyle = { { zIndex : 20 } }
167228 isOpen = { isPopoverOpen }
168- onClickOutside = { ( ) => handlePopoverToggle ( false ) }
229+ onClickOutside = { handleClickOutside }
169230 clickOutsideCapture = { true }
170231 positions = { [ "bottom" , "left" , "right" , "top" ] } // preferred positions by priority
171232 align = "start"
172233 padding = { 10 }
173234 content = {
174- < div className = { classes . popoverContent } >
235+ < div
236+ ref = { popoverContentRef }
237+ className = { classes . popoverContent }
238+ onMouseDownCapture = { handleInternalInteraction }
239+ onTouchStartCapture = { handleInternalInteraction }
240+ >
175241 { ! header . popupType ? null : header . popupType === "datetime" ? (
176242 < DatePopup
177243 close = { ( ) => handlePopoverToggle ( false ) }
@@ -285,6 +351,7 @@ const ProjectTableColumnHeader = ({
285351 }
286352 >
287353 < ColumnHeader
354+ ref = { columnHeaderRef }
288355 onClick = { ( ) => setIsPopoverOpen ( ! isPopoverOpen ) }
289356 header = { header }
290357 isFilterApplied = { ( ) => isFilterApplied ( ) }
0 commit comments