I have a Tooltip that serves as a date filter. It has two different date inputs one is for from date and other is for to date, there are also two buttons one is to clear filters and other is to apply them. When I clear filter tooltip is closed, but I also want to close tooltip without clearing dates just by clicking outside of tooltip area. I have made it work but when I press on a date and open options to select date and press on that open popper, tooltip closes because it detects pooper as outside click.
My question is how to prevent outside click when selecting dates?
This is dates component that sits inside tooltip:
import { EtsButton } from '@components/utils/ets/buttons/ets-button/ets-button';
import { CustomDatePicker } from '@components/utils/ets/inputs/custom-input-date/custom-date-picker';
import {
mergeDateFiltersData,
setDateFiltersData
} from '@store/modules/modals-and-forms/actions';
import { useDispatch, useSelector } from '@utilsFn/hooks/use-selector';
import { useTranslation } from 'next-i18next';
import React from 'react';
import styled from 'styled-components';
export const DateFilters = (props: NTableColumnsFilter.IProps) => {
const { t } = useTranslation();
const fromDate = useSelector(
(s) => s?.modalsAndForms?.dateFiltersData?.fromDate
);
const toDate = useSelector((s) => s?.modalsAndForms?.dateFiltersData?.toDate);
const dispatch = useDispatch();
return (
<TableColumnsFilterMenu>
<div className="item">
<p className="label">{t('page-sales-analysis:::main::Date from')}</p>
<CustomDatePicker
value={fromDate || null}
onChange={(val) => {
dispatch(
mergeDateFiltersData({
fromDate: val
})
);
}}
/>
</div>
<div className="item">
<p className="label">{t('page-sales-analysis:::main::Date until')}</p>
<CustomDatePicker
value={toDate || null}
onChange={(val) => {
dispatch(
mergeDateFiltersData({
toDate: val
})
);
}}
/>
</div>
<div className="action-buttons">
<EtsButton
button={{
onClick: () => {
dispatch(
setDateFiltersData({
openModalType: null,
fromDate: null,
toDate: null
})
);
props.setFromDateHandler(null);
props.setToDateHandler(null);
props.setShowMenuHandler(false);
}
}}
height="Height33"
padding="Padding7x15"
color="grey"
background="whiteFFF"
fontStyle="bold14"
>
{t('page-sales-analysis:::main::Clear the filters')}
</EtsButton>
<EtsButton
button={{
onClick: () => {
dispatch(
mergeDateFiltersData({
openModalType: null
})
);
props.setFromDateHandler(fromDate || null);
props.setToDateHandler(toDate || null);
props.setShowMenuHandler(false);
}
}}
height="Height33"
padding="Padding7x15"
color="white"
background="redC20"
fontStyle="bold14"
>
{t('page-sales-analysis:::main::Filter')}
</EtsButton>
</div>
</TableColumnsFilterMenu>
);
};
export namespace NTableColumnsFilter {
export interface IProps {
setFromDateHandler: (val: Date | null) => void;
setToDateHandler: (val: Date | null) => void;
setShowMenuHandler: (val: boolean) => void;
}
}
const TableColumnsFilterMenu = styled.div`
border-radius: 7px;
background-color: #ffffff;
box-shadow: 0px 3px 6px #00000029;
padding: 16px 21px 20px 21px;
.label {
font: normal normal 600 14px/20px 'Open Sans';
color: #000000;
}
.item {
display: flex;
flex-direction: column;
}
.action-buttons {
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 20px;
button:first-child {
margin-right: 10px;
}
button {
height: 33px;
}
}
`;
this is date filters tooltip component
import Tooltip, { TooltipProps } from '@mui/material/Tooltip';
import { SVGIconCalendar } from '@styles/global-icons/icons/svg-icon-calendar';
import { useOutsideClick } from '@utilsFn/hooks/use-outside-click';
import { useSelector } from '@utilsFn/hooks/use-selector';
import React from 'react';
import styled from 'styled-components';
import { DateFilters } from './components/date-filters';
interface ITooltipProps extends TooltipProps {
mobile: boolean | number;
}
const MenuTooltip = styled(({ className, ...props }: ITooltipProps) => (
<Tooltip
{...props}
classes={{ popper: className }}
componentsProps={{
tooltip: {
sx: {
backgroundColor: 'transparent',
padding: '0',
margin: '0',
minWidth: props?.mobile ? 200 : 419
}
}
}}
/>
))(() => ({}));
export const MenuDateTooltipFilter = (props: NTableColumnsFilter.IProps) => {
const isMobile = useSelector((s) => s.device.isMobile);
const refMenu = React.useRef<HTMLDivElement>(null);
const [showMenu, setShowMenu] = React.useState<boolean>(false);
const setShowMenuHandler = (val: boolean) => {
setShowMenu(val);
};
const handlerCloseMenu = () => {
setShowMenu(() => false);
};
useOutsideClick(refMenu, handlerCloseMenu);
return (
<ContainerTableColumnsFilter>
<MenuTooltip
mobile={isMobile ? 1 : 0}
placement="bottom-end"
open={showMenu}
title={
<div ref={refMenu}>
<DateFilters
setShowMenuHandler={setShowMenuHandler}
setFromDateHandler={props.setFromDateHandler}
setToDateHandler={props.setToDateHandler}
/>
</div>
}
>
<button
type="button"
className="icon-button"
onClick={() => {
setShowMenu(() => true);
}}
>
<SVGIconCalendar />
</button>
</MenuTooltip>
</ContainerTableColumnsFilter>
);
};
export namespace NTableColumnsFilter {
export interface IProps {
setFromDateHandler: (val: Date | null) => void;
setToDateHandler: (val: Date | null) => void;
}
}
const ContainerTableColumnsFilter = styled.div`
width: 50px;
height: 50px;
.icon-button {
cursor: pointer;
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border: none;
background-color: #ffffff;
:hover {
svg {
path {
fill: #c20b0b;
}
}
}
}
`;
Date picker itself is a customized mui datepicker
Update: I have achieved my desired result by using onOpen and onClose event existing in on date picker and disabling outside click function when popper is open ,but each time i select date popper flickers for a second before closing
onOpen and OnClose
onOpen={() => {
props.setIsDatePickerOpensHandler(true);
}}
onClose={() => {
props.setIsDatePickerOpensHandler(false);
}}
type of the handler
setIsDatePickerOpensHandler: (val: boolean) => void;
state and handler function in menu-date-tooltip-filter.tsx
const [isDatePickerOpen, setIsDatePickerOpen] =
React.useState<boolean>(false);
const setIsDatePickerOpensHandler = (val: boolean) => {
setIsDatePickerOpen(val);
};
if date picker is not open allow the use of outside Click function
useOutsideClick(refMenu, () => {
if (!isDatePickerOpen) {
setShowMenu(() => false);
}
});
It looks like after selecting date popper, it gets rerendered several times before closing
My updated question is how to solve this flickering bug?