react-anpicker
Version:
a react date picker for supporting persian dates
211 lines (210 loc) • 10.8 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useRef, useEffect } from "react";
import Days from "./days";
import { getMonthName } from "./helpers";
import { Modes } from "./Models/MainProps";
import faLocale from "./Locales/faLocale";
import Years from "./Years";
import Monthes from "./Monthes";
import Sidebar from "./Sidebar";
import ChevronIcon from "./ChevronIcon";
import { createPortal } from "react-dom";
import useControl from "./Hooks/useControl";
// function isMobile() {
// if (
// ("navigator" in window && window.navigator.userAgent.match(/Android/i)) ||
// window.navigator.userAgent.match(/webOS/i) ||
// window.navigator.userAgent.match(/iPhone/i) ||
// window.navigator.userAgent.match(/iPad/i) ||
// window.navigator.userAgent.match(/iPod/i) ||
// window.navigator.userAgent.match(/BlackBerry/i) ||
// window.navigator.userAgent.match(/Windows Phone/i)
// ) {
// return true;
// } else {
// return false;
// }
// }
export const AnPicker = ({ className = "", onChange, value = "", showTodayBottom = true, locale = faLocale, showSidebar = true, inputControl: Input, popupParentRef, popupVPosition, popupHPosition, }) => {
const inputRef = useRef(null);
const anPickerRef = useRef(null);
const popupRef = useRef(null);
const { state, tempValue, toggle, handleFocus, handleBlure, setPopupStyles, handleChange, setMode, nextYear, prevYear, nextMonth, prevMonth, onSelectYear, onSelectMonth, onSelectDay, setToday, } = useControl({
anPickerRef,
inputRef: inputRef,
locale: locale,
value: value,
onChange,
});
// function getRelativeTop(child: HTMLElement, ancestor: HTMLElement) {
// const childRect = child.getBoundingClientRect();
// const ancestorRect = ancestor.getBoundingClientRect();
// return childRect.top - ancestorRect.top + ancestor.scrollTop;
// }
const adjustPosition = () => {
const popupParent = popupParentRef ? popupParentRef.current : null;
const inputEl = anPickerRef.current;
const popupEl = popupRef.current;
if (!inputEl || !popupEl)
return;
const inputRect = inputEl.getBoundingClientRect();
const mobileMode = document.documentElement.clientWidth < 1200;
const popupHeight = 268 - (showTodayBottom ? 6 : 0);
const popupWidth = mobileMode ? 272 : 422;
//const scrollTop = window.scrollY || document.documentElement.scrollTop;
const scrollLeft = window.scrollX || document.documentElement.scrollLeft;
let spaceAbove;
let spaceBelow;
let parentRect;
if (popupParent) {
parentRect = popupParent.getBoundingClientRect();
spaceAbove = inputRect.top - parentRect.top;
spaceBelow = parentRect.bottom - inputRect.bottom;
}
else {
spaceAbove = inputRect.top;
spaceBelow = window.innerHeight - inputRect.bottom;
}
const showAbove = typeof popupVPosition !== "undefined"
? popupVPosition === "top"
: spaceBelow < popupHeight && spaceAbove > popupHeight;
let top = "auto";
let bottom = "auto";
if (popupParent) {
const relativeTop = inputRect.top - parentRect.top + popupParent.scrollTop;
if (showAbove) {
bottom = parentRect.bottom - inputRect.top;
}
else {
top = relativeTop + inputEl.offsetHeight;
}
}
else {
if (showAbove) {
bottom = window.innerHeight - inputRect.top;
}
else {
top = inputRect.bottom;
}
}
//=== H position
let left = "auto";
let right = "auto";
let spaceOnLeft;
let spaceOnRight;
if (popupParent) {
spaceOnLeft = inputRect.right - parentRect.left;
spaceOnRight = parentRect.right - inputRect.left;
// console.log({
// spaceOnLeft,
// spaceOnRight,
// parentRect: {
// width: parentRect!.width,
// left: parentRect!.left,
// right: parentRect!.right,
// },
// });
}
else {
spaceOnLeft = inputRect.right;
spaceOnRight = window.innerWidth - inputRect.left;
}
// console.log({
// spaceOnLeft,
// spaceOnRight,
// });
const showRight = typeof popupHPosition !== "undefined"
? popupHPosition === "left"
: spaceOnRight > popupWidth && spaceOnLeft < popupWidth;
console.log("showRight", showRight);
// const showOnLeft =
if (popupParent) {
if (!showRight) {
right = parentRect.right - inputRect.right;
}
else {
left = inputRect.left - parentRect.left;
}
}
else {
//const spaceOnLeft = inputRect.right;
if (!showRight) {
right = document.documentElement.clientWidth - inputRect.right;
}
else {
left = inputRect.left + scrollLeft;
}
}
setPopupStyles({
top,
bottom,
left,
right,
visibility: "visible",
});
};
useEffect(() => {
if (!state.open)
return;
// Initial adjustment
adjustPosition();
const observer = new IntersectionObserver((entries) => {
const entry = entries[0];
if (entry && entry.isIntersecting) {
adjustPosition();
}
}, {
root: null,
threshold: 0.1,
});
const inputEl = anPickerRef.current;
if (inputEl)
observer.observe(inputEl);
const scrollableParents = [];
// Find scrollable ancestors and attach scroll event listeners
let parent = inputEl === null || inputEl === void 0 ? void 0 : inputEl.parentElement;
while (parent) {
const overflowY = window.getComputedStyle(parent).overflowY;
if (overflowY === "scroll" || overflowY === "auto") {
scrollableParents.push(parent);
parent.addEventListener("scroll", adjustPosition);
}
parent = parent.parentElement;
}
// Also listen to window scroll
window.addEventListener("scroll", adjustPosition, true);
return () => {
if (inputEl)
observer.unobserve(inputEl);
scrollableParents.forEach((p) => {
p.removeEventListener("scroll", adjustPosition);
});
window.removeEventListener("scroll", adjustPosition, true);
};
}, [state.open]);
useEffect(() => {
const handleClickOutside = (e) => {
var _a, _b;
if (!((_a = anPickerRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target)) &&
!((_b = popupRef.current) === null || _b === void 0 ? void 0 : _b.contains(e.target))) {
toggle(false);
}
};
// const onScrolled = function () {
// if (isMobile()) adjustPosition();
// else {
// toggle(false);
// handleBlure();
// }
// };
// document.addEventListener("scroll", onScrolled);
document.addEventListener("click", handleClickOutside);
return () => {
//document.removeEventListener("scroll", onScrolled);
document.removeEventListener("click", handleClickOutside);
};
}, []);
return (_jsxs("div", Object.assign({ className: `anpicker ${className}`, ref: anPickerRef, dir: locale.rtl ? "rtl" : "ltr" }, { children: [Input ? (_jsx(Input, { ref: inputRef, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlure, value: tempValue !== null && tempValue !== void 0 ? tempValue : "" })) : (_jsx("input", { ref: inputRef, value: tempValue !== null && tempValue !== void 0 ? tempValue : "", onChange: handleChange, onFocus: handleFocus, onBlur: handleBlure })), state.open
? createPortal(_jsxs("div", Object.assign({ className: `anpicker-popup${popupParentRef ? "" : " fixed"}`, ref: popupRef, style: state.popupStyle, dir: locale.rtl ? "rtl" : "ltr" }, { children: [showSidebar ? (_jsx(Sidebar, { locale: locale, localYear: state.year, localMonth: state.month, localDay: state.day })) : null, _jsxs("div", Object.assign({ className: "main" }, { children: [_jsxs("div", Object.assign({ className: "selector-heading" }, { children: [_jsxs("div", Object.assign({ className: "monthes" }, { children: [_jsx("a", Object.assign({ className: "next", onClick: nextMonth, role: "button" }, { children: _jsx(ChevronIcon, { type: "next", rtl: locale.rtl }) })), _jsx("a", Object.assign({ role: "button", onClick: () => setMode(Modes.monthes) }, { children: getMonthName(locale.convertToDate(state.year, state.month, state.day), locale.name) })), _jsx("a", Object.assign({ className: "prev", onClick: prevMonth, role: "button" }, { children: _jsx(ChevronIcon, { type: "prev", rtl: locale.rtl }) }))] })), _jsxs("div", Object.assign({ className: "years" }, { children: [_jsx("a", Object.assign({ className: "next", onClick: nextYear, role: "button" }, { children: _jsx(ChevronIcon, { type: "next", rtl: locale.rtl }) })), _jsx("a", Object.assign({ role: "button", onClick: () => setMode(Modes.years) }, { children: state.year })), _jsx("a", Object.assign({ className: "prev", onClick: prevYear, role: "button" }, { children: _jsx(ChevronIcon, { type: "prev", rtl: locale.rtl }) }))] }))] })), _jsx(Years, { hidden: state.mode !== Modes.years, locale: locale, pageNumber: state.yearPageNumber, onSelectYear: onSelectYear, localYear: state.year }), _jsx(Monthes, { hidden: state.mode !== Modes.monthes, locale: locale, onSelect: onSelectMonth, localMonth: state.month }), _jsx(Days, { hidden: state.mode !== Modes.days, locale: locale, localYear: state.year, localMonth: state.month, localDay: state.day, onSelect: onSelectDay }), showTodayBottom && (_jsx("button", Object.assign({ className: "today-button", onClick: setToday }, { children: locale.todayButtonText })))] }))] })), (popupParentRef === null || popupParentRef === void 0 ? void 0 : popupParentRef.current) ? popupParentRef.current : document.body)
: null] })));
};