Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(16740): DatePicker calendar close issue on clickAway, DatePicker not running onChange events, DatePicker setting and clearing date in range issues #17072

Merged
merged 10 commits into from
Aug 6, 2024
2 changes: 1 addition & 1 deletion e2e/components/DatePicker/DatePicker-test.avt.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ test.describe('@avt DatePicker', () => {
await page.keyboard.press('Enter');
await page.keyboard.press('Enter');
await expect(
page.locator('input#date-picker-input-id-finish')
page.locator('input#date-picker-input-id-start')
).toBeFocused();
await expect(page.locator('div.flatpickr-calendar')).not.toHaveClass(
/open/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ test.describe('@avt FluidDatePicker', () => {
await page.keyboard.press('ArrowDown');
await page.keyboard.press('Enter');
await expect(
page.locator('input#date-picker-input-id-finish')
page.locator('input#date-picker-input-id-start')
).toBeFocused();
await expect(page.locator('div.flatpickr-calendar')).not.toHaveClass(
/open/
Expand Down
102 changes: 80 additions & 22 deletions packages/react/src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -443,11 +443,17 @@ const DatePicker = React.forwardRef(function DatePicker(

const lastStartValue = useRef('');

interface CalendarCloseEvent {
selectedDates: Date[];
dateStr: string;
instance: object; //This is `Intance` of flatpicker
}
const [calendarCloseEvent, setCalendarCloseEvent] =
useState<CalendarCloseEvent | null>(null);

// fix datepicker deleting the selectedDate when the calendar closes
const onCalendarClose = (selectedDates, dateStr) => {
endInputField?.current?.focus();
calendarRef?.current?.calendarContainer?.classList.remove('open');
setTimeout(() => {
const handleCalendarClose = useCallback(
(selectedDates, dateStr, instance) => {
if (
lastStartValue.current &&
selectedDates[0] &&
Expand All @@ -461,21 +467,29 @@ const DatePicker = React.forwardRef(function DatePicker(
);
}
if (onClose) {
onClose(
calendarRef.current.selectedDates,
dateStr,
calendarRef.current
);
onClose(selectedDates, dateStr, instance);
}
});
},
[onClose]
);
const onCalendarClose = (selectedDates, dateStr, instance, e) => {
if (e && e.type === 'clickOutside') {
return;
}
setCalendarCloseEvent({ selectedDates, dateStr, instance });
};
useEffect(() => {
if (calendarCloseEvent) {
const { selectedDates, dateStr, instance } = calendarCloseEvent;
handleCalendarClose(selectedDates, dateStr, instance);
setCalendarCloseEvent(null);
}
}, [calendarCloseEvent, handleCalendarClose]);

const endInputField = useRef<HTMLTextAreaElement>(null);
const calendarRef: any | undefined = useRef(null);
const savedOnChange = useSavedCallback(onChange);
const savedOnClose = useSavedCallback(
datePickerType === 'range' ? onCalendarClose : onClose
);

const savedOnOpen = useSavedCallback(onOpen);

const datePickerClasses = cx(`${prefix}--date-picker`, {
Expand Down Expand Up @@ -610,6 +624,7 @@ const DatePicker = React.forwardRef(function DatePicker(
const { current: end } = endInputField;
const flatpickerconfig: any = {
inline: inline ?? false,
onClose: onCalendarClose,
disableMobile: true,
defaultDate: value,
closeOnSelect: closeOnSelect,
Expand Down Expand Up @@ -653,7 +668,7 @@ const DatePicker = React.forwardRef(function DatePicker(
savedOnChange(...args);
}
},
onClose: savedOnClose,

2nikhiltom marked this conversation as resolved.
Show resolved Hide resolved
onReady: onHook,
onMonthChange: onHook,
onYearChange: onHook,
Expand Down Expand Up @@ -772,14 +787,7 @@ const DatePicker = React.forwardRef(function DatePicker(
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
savedOnChange,
savedOnClose,
savedOnOpen,
readOnly,
closeOnSelect,
hasInput,
]);
}, [savedOnChange, savedOnOpen, readOnly, closeOnSelect, hasInput]);

// this hook allows consumers to access the flatpickr calendar
// instance for cases where functions like open() or close()
Expand Down Expand Up @@ -831,6 +839,56 @@ const DatePicker = React.forwardRef(function DatePicker(
calendarRef.current.set('inline', inline);
}
}, [inline]);
useEffect(() => {
//when value prop is set to empty, this clears the faltpicker's calendar instance and text input
if (value === '') {
calendarRef.current?.clear();
if (startInputField.current) {
startInputField.current.value = '';
}

if (endInputField.current) {
endInputField.current.value = '';
}
}
}, [value]);

useEffect(() => {
let isMouseDown = false;

const handleMouseDown = (event) => {
if (
calendarRef.current &&
calendarRef.current.isOpen &&
!calendarRef.current.calendarContainer.contains(event.target) &&
!startInputField.current.contains(event.target) &&
!endInputField.current?.contains(event.target)
) {
isMouseDown = true;
// Close the calendar immediately on mousedown
closeCalendar(event);
}
};

const closeCalendar = (event) => {
calendarRef.current.close();
// Remove focus from endDate calendar input
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur();
}
onCalendarClose(
calendarRef.current.selectedDates,
'',
calendarRef.current,
{ type: 'clickOutside' }
);
};
document.addEventListener('mousedown', handleMouseDown, true);

return () => {
document.removeEventListener('mousedown', handleMouseDown, true);
};
}, [calendarRef, startInputField, endInputField, onCalendarClose]);

useEffect(() => {
if (calendarRef?.current?.set) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ import { match, keys } from '../../../internal/keyboard';
*/
export default (config) => (fp) => {
const { inputFrom, inputTo, lastStartValue } = config;
/**
* Handles `click` outside to close calendar
*/
const handleClickOutside = (event) => {
if (
!fp.isOpen ||
fp.calendarContainer.contains(event.target) ||
event.target === inputFrom ||
event.target === inputTo
) {
return;
}
fp.close();
};
/**
* Handles `keydown` event.
*/
Expand Down Expand Up @@ -127,6 +141,7 @@ export default (config) => (fp) => {
inputTo.removeEventListener('blur', handleBlur, true);
}
inputFrom.removeEventListener('keydown', handleKeydown, true);
document.removeEventListener('click', handleClickOutside, true);
};

/**
Expand All @@ -140,6 +155,7 @@ export default (config) => (fp) => {
inputTo.addEventListener('keydown', handleKeydown, true);
inputTo.addEventListener('blur', handleBlur, true);
}
document.addEventListener('click', handleClickOutside, true);
};

/**
Expand Down
Loading