From 6315d418700a69e598f11767642840536cd71ae8 Mon Sep 17 00:00:00 2001 From: Balaji Date: Thu, 15 Feb 2024 20:45:51 +0530 Subject: [PATCH] implemented useOuterClick - mantine calendar modal issue (#199) --- src/components/Header/TimeRange.tsx | 72 ++++++++++++++++++++--------- src/hooks/useOuterClick.ts | 21 +++++++++ 2 files changed, 72 insertions(+), 21 deletions(-) create mode 100644 src/hooks/useOuterClick.ts diff --git a/src/components/Header/TimeRange.tsx b/src/components/Header/TimeRange.tsx index 8a97db32..266c9bdb 100644 --- a/src/components/Header/TimeRange.tsx +++ b/src/components/Header/TimeRange.tsx @@ -5,9 +5,10 @@ import { DateTimePicker } from '@mantine/dates'; import { IconClock } from '@tabler/icons-react'; import dayjs from 'dayjs'; import type { FC } from 'react'; -import { Fragment, useEffect, useMemo } from 'react'; +import { Fragment, useCallback, useEffect, useMemo } from 'react'; import { FIXED_DURATIONS } from '@/constants/timeConstants'; -import logQueryStyles from './styles/LogQuery.module.css' +import logQueryStyles from './styles/LogQuery.module.css'; +import { useOuterClick } from '@/hooks/useOuterClick'; type FixedDurations = (typeof FIXED_DURATIONS)[number]; @@ -16,9 +17,31 @@ const TimeRange: FC = () => { state: { subLogQuery, subLogSelectedTimeRange }, } = useHeaderContext(); + const handleOuterClick = (event: any) => { + const targetClassNames: string[] = event.target?.classList || []; + const maybeSubmitBtnClassNames: string[] = event.target.closest('button')?.classList || []; + const classNames: string[] = [ + ...(typeof targetClassNames[Symbol.iterator] === 'function' ? [...targetClassNames] : []), + ...(typeof maybeSubmitBtnClassNames[Symbol.iterator] === 'function' ? [...maybeSubmitBtnClassNames] : []), + ]; + const shouldIgnoreClick = classNames.some((className) => { + return ( + className.startsWith('mantine-DateTimePicker') || + className.startsWith('mantine-TimeInput') || + className === 'mantine-Popover-dropdown' + ); + }); + !shouldIgnoreClick && setOpened(false); + }; + + const innerRef = useOuterClick(handleOuterClick); const [opened, setOpened] = useMountedState(false); const [selectedRange, setSelectedRange] = useMountedState(subLogSelectedTimeRange.get().value); + const toggleMenu = useCallback(() => { + setOpened((prev) => !prev); + }, []); + useEffect(() => { const listener = subLogSelectedTimeRange.subscribe((state) => { setSelectedRange(state.value); @@ -51,31 +74,38 @@ const TimeRange: FC = () => { } = logQueryStyles; return ( - + - - - - {FIXED_DURATIONS.map((duration) => { - return ( - onDurationSelect(duration)}> - {duration.name} - - ); - })} - - - +
+ + + {FIXED_DURATIONS.map((duration) => { + return ( + onDurationSelect(duration)}> + {duration.name} + + ); + })} + + + + - +
); diff --git a/src/hooks/useOuterClick.ts b/src/hooks/useOuterClick.ts new file mode 100644 index 00000000..fdd4a178 --- /dev/null +++ b/src/hooks/useOuterClick.ts @@ -0,0 +1,21 @@ +import type { MutableRefObject } from 'react'; +import { useEffect, useRef } from 'react'; + +export const useOuterClick = (callback: (event: any) => void): MutableRefObject => { + const innerRef: MutableRefObject = useRef(null); + useEffect(() => { + const handleClickOutside = (event: any) => { + if (innerRef.current && !(innerRef.current as any).contains(event.target)) { + callback(event); + } + }; + + document.addEventListener('click', handleClickOutside); + + return () => { + document.removeEventListener('click', handleClickOutside); + }; + }, [callback]); + + return innerRef; +};