ar-design
Version:
AR Design is a (react | nextjs) ui library.
348 lines (347 loc) • 18.4 kB
JavaScript
"use client";
import React, { useEffect, useRef, useState } from "react";
import "../../../assets/css/components/form/date-picker/date-picker.css";
import Input from "../input";
import Button from "../button";
import Alert from "../../feedback/alert";
import ReactDOM from "react-dom";
import DATE from "./DATE";
const weekdays = ["Pzt", "Sal", "Çar", "Per", "Cum", "Cmt", "Paz"];
const months = [
{ value: 0, text: "Ocak" },
{ value: 1, text: "Şubat" },
{ value: 2, text: "Mart" },
{ value: 3, text: "Nisan" },
{ value: 4, text: "Mayıs" },
{ value: 5, text: "Haziran" },
{ value: 6, text: "Temmuz" },
{ value: 7, text: "Ağustos" },
{ value: 8, text: "Eylül" },
{ value: 9, text: "Ekim" },
{ value: 10, text: "Kasım" },
{ value: 11, text: "Aralık" },
];
const DatePicker = ({ onChange, isClock, validation, ...attributes }) => {
// refs
const _arCalendar = useRef(null);
const _arClock = useRef(null);
const _calendarHeader = useRef(null);
const _calendarFooter = useRef(null);
const _clockHeader = useRef(null);
const _clockFooter = useRef(null);
const _currentDate = useRef(new Date()).current;
const _beginDate = useRef(null);
// refs -> Geçerli Tarih ve Saat Bilgileri.
const _year = useRef(_currentDate.getFullYear());
const _month = useRef(_currentDate.getMonth());
const _day = useRef(_currentDate.getDate());
const _hours = useRef(_currentDate.getHours());
const _minutes = useRef(_currentDate.getMinutes());
// refs -> List Elements
const _hoursListElement = useRef(null);
const _hoursLiElements = useRef([]);
const _minutesListElement = useRef(null);
const _minutesLiElements = useRef([]);
// states
const [calendarIsOpen, setCalendarIsOpen] = useState(false);
const [calendarDays, setCalendarDays] = useState([]);
const [years, setYears] = useState([]);
const [hours, setHours] = useState();
const [minutes, setMinutes] = useState();
const [dateChanged, setDateChanged] = useState(false);
const [timeChanged, setTimeChanged] = useState(false);
// states => Seçilmiş Tarihler
const [selectedYear, setSelectedYear] = useState(_currentDate.getFullYear());
const [selectedMonth, setSelectedMonth] = useState(_currentDate.getMonth());
const [selectedDay, setSelectedDay] = useState(_currentDate.getDate());
const [selectedHours, setSelectedHours] = useState(_currentDate.getHours());
const [selectedMinutes, setSelectedMinutes] = useState(_currentDate.getMinutes());
// methods
const handleClickOutSide = (event) => {
const target = event.target;
if (target === _beginDate.current)
return;
if (_arCalendar.current && !_arCalendar.current.contains(target))
closeCalendar();
};
const handleKeys = (event) => {
const key = event.key;
if (key === "Escape") {
event.stopPropagation();
closeCalendar();
}
};
const handlePosition = () => {
if (_arCalendar.current && _beginDate.current) {
const arCalendarRect = _arCalendar.current.getBoundingClientRect();
const InpuRect = _beginDate.current?.getBoundingClientRect();
if (InpuRect) {
const screenCenterX = window.innerWidth / 2;
const screenCenterY = window.innerHeight / 2;
const sx = window.scrollX || document.documentElement.scrollLeft || document.body.scrollLeft;
const sy = window.scrollY || document.documentElement.scrollTop || document.body.scrollTop;
_arCalendar.current.style.visibility = "visible";
_arCalendar.current.style.opacity = "1";
_arCalendar.current.style.top = `${(InpuRect.top > screenCenterY ? InpuRect.top - arCalendarRect.height : InpuRect.top + InpuRect.height) + sy}px`;
_arCalendar.current.style.left = `${(InpuRect.left > screenCenterX ? InpuRect.right - arCalendarRect.width : InpuRect.left) + sx}px`;
}
}
};
const handleHeight = () => {
if (_arCalendar.current && _arClock.current) {
const calendar = _arCalendar.current?.getBoundingClientRect()?.height;
_arClock.current.style.maxHeight = `${calendar}px`;
}
if (_calendarHeader.current && _clockHeader.current) {
const calendarHeaderH = _calendarHeader.current?.getBoundingClientRect()?.height;
_clockHeader.current.style.minHeight = `${calendarHeaderH}px`;
}
if (_calendarFooter && _clockFooter.current) {
const calendarFooterH = _calendarFooter.current?.getBoundingClientRect()?.height;
_clockFooter.current.style.minHeight = `${calendarFooterH}px`;
}
};
const handleOk = (isShutdownOn = true) => {
// Stateler güncelleniyor...
setSelectedYear(_year.current);
setSelectedMonth(_month.current);
setSelectedDay(_day.current);
setSelectedHours(_hours.current);
setSelectedMinutes(_minutes.current);
const inputDate = new Date(Date.UTC(_year.current, _month.current, _day.current, !isClock ? 0 : _hours.current, !isClock ? 0 : _minutes.current, 0));
onChange(inputDate.toISOString());
isShutdownOn && setCalendarIsOpen(false);
};
const setNowButton = () => {
const now = new Date();
// Stateler güncelleniyor...
setSelectedYear(now.getFullYear());
setSelectedMonth(now.getMonth());
setSelectedDay(now.getDate());
setSelectedHours(now.getHours());
setSelectedMinutes(now.getMinutes());
_year.current = now.getFullYear();
_month.current = now.getMonth();
_day.current = now.getDate();
_hours.current = now.getHours();
_minutes.current = now.getMinutes();
// Takvim kapatılıyor...
setCalendarIsOpen(false);
// Değer gönderiliyor...
const inputDate = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate(), !isClock ? 0 : now.getHours(), !isClock ? 0 : now.getMinutes(), 0));
onChange(inputDate.toISOString());
};
const okayButton = () => {
return (React.createElement(Button, { variant: "borderless", status: "success", onClick: () => handleOk() }, "Tamam"));
};
const closeCalendar = () => {
const { year, month, day, hours, minutes } = DATE.Parse(String(attributes.value), isClock);
_year.current = attributes.value ? year : selectedYear;
_month.current = attributes.value ? month - 1 : selectedMonth;
_day.current = attributes.value ? day : selectedDay;
_hours.current = attributes.value ? hours : selectedHours;
_minutes.current = attributes.value ? minutes : selectedMinutes;
setCalendarIsOpen(false);
};
// useEffects
useEffect(() => {
if (calendarIsOpen) {
setTimeout(() => {
handleHeight();
handlePosition();
}, 0);
const days = [];
const firstDayOfMonth = new Date(_year.current, _month.current, 1);
const lastDayOfMonth = new Date(_year.current, _month.current + 1, 0);
const startingDay = firstDayOfMonth.getDay() === 0 ? 7 : firstDayOfMonth.getDay();
const endingDay = lastDayOfMonth.getDay() === 0 ? 7 : lastDayOfMonth.getDay();
for (let i = 1; i < startingDay; i++) {
days.push(React.createElement("span", { key: `prev-${i}`, className: "empty-day" }));
}
for (let i = firstDayOfMonth.getDate(); i <= lastDayOfMonth.getDate(); i++) {
const isSelected = !isNaN(firstDayOfMonth.getTime())
? firstDayOfMonth.getFullYear() === _year.current &&
firstDayOfMonth.getMonth() === _month.current &&
i === _day.current
: _currentDate.getFullYear() === _year.current &&
_currentDate.getMonth() === _month.current &&
i === _day.current;
days.push(React.createElement("span", { key: `current-${i}`, className: isSelected ? "selection-day" : "", onClick: (event) => {
event.preventDefault();
_day.current = i;
setSelectedDay(i);
setDateChanged(!dateChanged);
handleOk(false);
} },
React.createElement("span", null, i)));
}
for (let i = endingDay; i < 7; i++) {
days.push(React.createElement("span", { key: `next-${i}`, className: "empty-day" }));
}
setCalendarDays(days);
// window.addEventListener("blur", () => closeCalendar());
document.addEventListener("click", handleClickOutSide);
document.addEventListener("keydown", handleKeys);
}
return () => {
// window.removeEventListener("blur", () => closeCalendar());
document.removeEventListener("click", handleClickOutSide);
document.removeEventListener("keydown", handleKeys);
};
}, [dateChanged, calendarIsOpen]);
useEffect(() => {
const generateList = (count, current, setFunc) => {
const items = Array.from({ length: count }, (_, i) => (React.createElement("li", { ref: (element) => count === 24 ? (_hoursLiElements.current[i] = element) : (_minutesLiElements.current[i] = element), key: i, ...(current === i ? { className: "selection-time" } : {}), onClick: () => {
if (count === 24) {
setTimeChanged((prev) => !prev);
_hours.current = i;
setSelectedHours(i);
}
else {
setTimeChanged((prev) => !prev);
_minutes.current = i;
setSelectedMinutes(i);
}
handleOk(false);
} },
React.createElement("span", null,
React.createElement("span", null, i.toString().padStart(2, "0"))))));
setFunc(items);
};
// Listeler oluşturuyor...
generateList(24, _hours.current, setHours);
generateList(60, _minutes.current, setMinutes);
if (!isClock)
return;
if (calendarIsOpen)
handleHeight();
// Seçim sonrasında en yukarı getirme işlemi için aşağıda yer alan kodlar yazılmıştır
const hourLiElement = _hoursLiElements.current[_hours.current];
const minuteLiElement = _minutesLiElements.current[_minutes.current];
if (hourLiElement) {
_hoursListElement.current?.scrollTo({
top: hourLiElement.offsetTop - _hoursListElement.current.offsetTop - 8,
behavior: "smooth",
});
}
if (minuteLiElement) {
_minutesListElement.current?.scrollTo({
top: minuteLiElement.offsetTop - _minutesListElement.current.offsetTop - 8,
behavior: "smooth",
});
}
}, [timeChanged, calendarIsOpen, isClock]);
useEffect(() => {
if (isNaN(_year.current))
return;
const years = [];
// Son 20 yıl
for (let i = _year.current - 20; i <= _year.current; i++) {
years.push({ value: i, text: `${i}` });
}
// Önümüzdeki 20 yıl
for (let i = _year.current + 1; i <= _year.current + 20; i++) {
years.push({ value: i, text: `${i}` });
}
setYears(years);
}, [selectedYear]);
return (React.createElement("div", { className: "ar-date-picker" },
attributes.placeholder && attributes.placeholder.length > 0 && (React.createElement("label", null,
validation ? "* " : "",
attributes.placeholder)),
React.createElement(Input, { ref: _beginDate, ...attributes, value: DATE.ParseValue(String(attributes.value), isClock), type: isClock ? "datetime-local" : "date", onKeyDown: (event) => {
if (event.code === "Space")
event.preventDefault();
else if (event.code === "Enter")
handleOk();
}, onChange: (event) => {
// Disabled gelmesi durumunda işlem yapmasına izin verme...
if (attributes.disabled)
return;
(() => {
if (!calendarIsOpen)
setCalendarIsOpen(true);
const value = event.target.value;
const [date, time] = value.split("T");
const [year, month, day] = date.split("-").map(Number);
const hours = time ? time.split(".")[0].split(":").map(Number)[0] : 0;
const minutes = time ? time.split(".")[0].split(":").map(Number)[1] : 0;
_year.current = year;
_month.current = month - 1;
_day.current = day;
if (hours || minutes) {
_hours.current = hours;
_minutes.current = minutes;
}
// Yıl ve Ay'ı anlık yeniler.
setSelectedYear(_year.current);
setSelectedMonth(_month.current);
// Takvimi anlık yeniler.
setDateChanged((prev) => !prev);
setTimeChanged((prev) => !prev);
onChange(value);
})();
}, onClick: (event) => {
event.preventDefault();
setCalendarIsOpen(true);
}, autoComplete: "off", validation: validation }),
calendarIsOpen &&
ReactDOM.createPortal(React.createElement("div", { ref: _arCalendar, className: "ar-date-calendar" },
React.createElement("div", { ref: _calendarHeader, className: "header" },
React.createElement("div", { className: "select-field" },
React.createElement("div", { className: "prev" },
React.createElement("span", { onClick: () => {
_year.current -= 1;
setSelectedYear(_year.current);
setDateChanged((prev) => !prev);
} }),
React.createElement("span", { onClick: () => {
if (_month.current <= 0) {
_year.current -= 1;
_month.current = 12;
}
_month.current -= 1;
setSelectedYear(_year.current);
setSelectedMonth(_month.current);
setDateChanged((prev) => !prev);
} })),
React.createElement("div", { className: "selects" },
React.createElement("div", null,
React.createElement("span", null, months.find((month) => month.value === selectedMonth)?.text)),
React.createElement("div", null,
React.createElement("span", null, years.find((year) => year.value === selectedYear)?.text))),
React.createElement("div", { className: "next" },
React.createElement("span", { onClick: () => {
if (_month.current >= 11) {
_year.current += 1;
_month.current = -1;
}
_month.current += 1;
setSelectedYear(_year.current);
setSelectedMonth(_month.current);
setDateChanged((prev) => !prev);
} }),
React.createElement("span", { onClick: () => {
_year.current += 1;
setSelectedYear(_year.current);
setDateChanged((prev) => !prev);
} })))),
React.createElement("div", { className: "content" }, !isNaN(_month.current) && !isNaN(_year.current) ? (React.createElement("div", { className: "calendar" },
React.createElement("div", { className: "weekdays" }, weekdays.map((weekday, index) => (React.createElement("span", { key: index }, weekday)))),
React.createElement("div", { className: "days" }, calendarDays))) : (React.createElement(Alert, { status: "warning" }, "Ay veya y\u0131l se\u00E7imi yapman\u0131z gerekmektedir."))),
React.createElement("div", { ref: _calendarFooter, className: "footer" },
React.createElement("div", null,
React.createElement(Button, { variant: "borderless", onClick: () => setNowButton() }, "\u015Eimdi")),
React.createElement("div", null, !isClock && okayButton())),
isClock && (React.createElement("div", { ref: _arClock, className: "clock" },
React.createElement("div", { ref: _clockHeader, className: "header" },
_hours.current.toString().padStart(2, "0"),
" : ",
_minutes.current.toString().padStart(2, "0")),
React.createElement("div", { className: "content" },
React.createElement("ul", { ref: _hoursListElement }, hours),
React.createElement("ul", { ref: _minutesListElement }, minutes)),
React.createElement("div", { ref: _clockFooter, className: "footer" }, okayButton())))), document.body)));
};
DatePicker.displayName = "DatePicker";
export default DatePicker;