@carbon/react
Version:
React components for the Carbon Design System
133 lines (131 loc) • 4.98 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2026
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import { ArrowDown, ArrowLeft, ArrowRight, Enter } from "../../../internal/keyboard/keys.js";
import { match } from "../../../internal/keyboard/match.js";
//#region src/components/DatePicker/plugins/fixEventsPlugin.ts
const fixEventsPlugin = (config) => (fp) => {
const { inputFrom, inputTo, lastStartValue, container } = config;
let mouseDownInside = false;
const getEventPath = (event) => typeof event.composedPath === "function" ? event.composedPath() : [];
const isEventInside = (event) => {
const path = getEventPath(event);
const { target } = event;
if (!(target instanceof Node)) return false;
return Boolean(container && (path.includes(container) || container.contains(target)) || fp.calendarContainer && (path.includes(fp.calendarContainer) || fp.calendarContainer.contains(target)) || inputFrom && (path.includes(inputFrom) || inputFrom.contains(target)) || inputTo && (path.includes(inputTo) || inputTo.contains(target)));
};
/**
* Handles `click` outside to close calendar
*/
const handleClickOutside = (event) => {
if (mouseDownInside) {
mouseDownInside = false;
return;
}
if (!fp.isOpen || isEventInside(event)) {
mouseDownInside = false;
return;
}
mouseDownInside = false;
fp.close();
};
/**
* Tracks the initial mouse target to avoid closing on click after scroll.
*/
const handleMouseDown = (event) => {
mouseDownInside = isEventInside(event);
};
/**
* Handles `keydown` event.
*/
const handleKeydown = (event) => {
const { target } = event;
if (inputFrom === target || inputTo === target) {
if (match(event, Enter)) {
mouseDownInside = false;
fp.setDate(inputTo ? [inputFrom.value, inputTo.value] : [inputFrom.value], true, fp.config.dateFormat);
event.stopPropagation();
if (inputTo === target && fp.config.closeOnSelect) requestAnimationFrame(() => {
fp.close();
});
} else if (match(event, ArrowLeft) || match(event, ArrowRight)) event.stopPropagation();
else if (match(event, ArrowDown)) {
event.preventDefault();
fp.open();
} else if (!fp.config.allowInput) {
event.stopPropagation();
event.preventDefault();
}
}
};
const parseDateWithFormat = (dateStr) => fp.parseDate(dateStr, fp.config.dateFormat);
/**
* Handles `blur` event.
*
* For whatever reason, manual changes within the `to` input do not update the
* calendar on blur. If a manual change is made within the input, this block will
* set the date again, triggering the calendar to update.
*/
const handleBlur = (event) => {
const { target } = event;
if (!inputTo) return;
if (inputTo === target && fp.selectedDates[1]) {
const withoutTime = (date) => date?.setHours(0, 0, 0, 0);
const selectedToDate = withoutTime(new Date(fp.selectedDates[1]));
const currentValueToDate = withoutTime(parseDateWithFormat(inputTo.value));
if (selectedToDate && currentValueToDate && selectedToDate !== currentValueToDate) fp.setDate([inputFrom.value, inputTo.value], true, fp.config.dateFormat);
}
const isValidDate = (date) => date?.toString() !== "Invalid Date";
if (inputTo === target && fp.selectedDates.length === 1 && inputTo.value) {
if (isValidDate(parseDateWithFormat(inputTo.value))) fp.setDate([inputFrom.value, inputTo.value], true, fp.config.dateFormat);
}
if (inputTo === target && !inputFrom.value && lastStartValue.current) {
if (isValidDate(parseDateWithFormat(lastStartValue.current))) {
inputFrom.value = lastStartValue.current;
if (inputTo.value) fp.setDate([inputFrom.value, inputTo.value], true, fp.config.dateFormat);
}
}
};
/**
* Releases event listeners used in this Flatpickr plugin.
*/
const release = () => {
const { inputFrom, inputTo } = config;
if (inputTo) {
inputTo.removeEventListener("keydown", handleKeydown, true);
inputTo.removeEventListener("blur", handleBlur, true);
}
inputFrom.removeEventListener("keydown", handleKeydown, true);
document.removeEventListener("mousedown", handleMouseDown, true);
document.removeEventListener("click", handleClickOutside, true);
};
/**
* Sets up event listeners used for this Flatpickr plugin.
*/
const init = () => {
release();
const { inputFrom, inputTo } = config;
inputFrom.addEventListener("keydown", handleKeydown, true);
if (inputTo) {
inputTo.addEventListener("keydown", handleKeydown, true);
inputTo.addEventListener("blur", handleBlur, true);
}
document.addEventListener("mousedown", handleMouseDown, true);
document.addEventListener("click", handleClickOutside, true);
};
/**
* Registers this Flatpickr plugin.
*/
const register = () => {
fp.loadedPlugins.push("carbonFlatpickrFixEventsPlugin");
};
return {
onReady: [register, init],
onDestroy: [release]
};
};
//#endregion
export { fixEventsPlugin as default };