UNPKG

tharikida-ui

Version:

A modern, lightweight React UI component library with built-in theming, accessibility, and full TypeScript support. Create beautiful, responsive, and customizable web apps faster with ready-to-use components for any project.

212 lines (211 loc) 10.8 kB
"use client"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState } from "react"; import Dropdown from "./DropDown"; import { useTheme } from "../../theme/ThemeProvider"; const Calendar = ({ size, handleDateClick, initialDate, cornerRadius, primaryColor, textColor, backgroundColor, fontSize, fontFamily, borderColor, borderWidth, borderStyle, fontWeight, transitionDuration, hoverColor, }) => { const theme = useTheme(); const [showCalendar, setShowCalendar] = useState(false); const [selectedDate, setSelectedDate] = useState(initialDate || null); // Use prop > theme > fallback const t = { primaryColor: primaryColor || theme.primaryColor, textColor: textColor || theme.textColor, backgroundColor: backgroundColor || theme.backgroundColor, fontSize: fontSize || theme.fontSize, fontFamily: fontFamily || theme.fontFamily, cornerRadius: typeof cornerRadius === "number" ? cornerRadius : theme.cornerRadius ?? theme.spacingfactor * 2, borderColor: borderColor || theme.borderColor, borderWidth: borderWidth ?? theme.borderWidth, borderStyle: borderStyle ?? theme.borderStyle, fontWeight: fontWeight ?? theme.fontWeight, transitionDuration: transitionDuration ?? theme.transitionDuration, hoverColor: hoverColor || theme.hoverColor, // fallback for removed props padding: theme.padding, margin: theme.margin, shadowOffsetX: theme.shadowOffsetX, shadowOffsetY: theme.shadowOffsetY, shadowBlur: theme.shadowBlur, shadowSpread: theme.shadowSpread, shadowColor: theme.shadowColor, shadowInset: theme.shadowInset, }; const generateCalendar = (month, year) => { const daysInMonth = new Date(year, month + 1, 0).getDate(); const firstDay = new Date(year, month, 1).getDay(); const dates = Array(firstDay).fill(null); for (let i = 1; i <= daysInMonth; i++) dates.push(i); return dates; }; const today = new Date(); const [currentMonth, setCurrentMonth] = useState(today.getMonth()); const [currentYear, setCurrentYear] = useState(today.getFullYear()); const dates = generateCalendar(currentMonth, currentYear); const handleDateClickInternal = (day) => { if (day !== null) { const date = new Date(currentYear, currentMonth, day); setSelectedDate(date); setShowCalendar(false); handleDateClick && handleDateClick(day); } }; const changeMonth = (offset) => { let newMonth = currentMonth + offset; let newYear = currentYear; if (newMonth > 11) { newMonth = 0; newYear++; } else if (newMonth < 0) { newMonth = 11; newYear--; } setCurrentMonth(newMonth); setCurrentYear(newYear); }; const handleMonthChange = (value) => { setCurrentMonth(months.indexOf(value)); }; const handleYearChange = (event) => { setCurrentYear(parseInt(event.target.value, 10)); }; const years = Array.from({ length: 101 }, (_, i) => 1950 + i); const months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ]; const formatDate = (date) => { if (!date) return "Pick a Date"; const options = { year: "numeric", month: "short", day: "numeric", }; return date.toLocaleDateString(undefined, options); }; return (_jsx("div", { style: { width: size || "300px" }, children: _jsxs("div", { style: { boxSizing: "border-box", display: "flex", flexDirection: "column", alignItems: "center", position: "relative", width: "100%", padding: t.padding, fontFamily: t.fontFamily, fontSize: t.fontSize, fontWeight: t.fontWeight, lineHeight: theme.lineHeight, letterSpacing: theme.letterSpacing, margin: t.margin, }, children: [_jsx("div", { style: { boxSizing: "border-box", padding: t.padding, border: `${t.borderWidth} ${t.borderStyle} ${t.borderColor}`, borderRadius: t.cornerRadius, textAlign: "center", cursor: "pointer", backgroundColor: t.backgroundColor, width: "100%", boxShadow: `${t.shadowOffsetX} ${t.shadowOffsetY} ${t.shadowBlur} ${t.shadowSpread} ${t.shadowColor}`, fontSize: t.fontSize, color: t.textColor, transition: t.transitionDuration, }, onClick: () => setShowCalendar(!showCalendar), children: formatDate(selectedDate) }), showCalendar && (_jsxs("div", { style: { position: "absolute", top: "60px", backgroundColor: t.backgroundColor, zIndex: 10, width: "100%", border: `${t.borderWidth} ${t.borderStyle} ${t.borderColor}`, boxShadow: `${t.shadowInset ? "inset " : ""}${t.shadowOffsetX} ${t.shadowOffsetY} ${t.shadowBlur} ${t.shadowSpread} ${t.shadowColor}`, borderRadius: t.cornerRadius, gap: theme.spacingfactor, padding: t.padding, transition: t.transitionDuration, }, children: [_jsxs("div", { style: { display: "flex", justifyContent: "space-between", gap: theme.spacingfactor, }, children: [_jsx(Dropdown, { options: months, defaultOption: months[currentMonth], onChange: handleMonthChange }), _jsx(Dropdown, { options: years.map(String), defaultOption: String(currentYear), onChange: (value) => handleYearChange({ target: { value }, }) })] }), _jsx("div", { style: { boxSizing: "border-box", textAlign: "center", padding: `${theme.spacingfactor * 2}px ${theme.spacingfactor * 1.5}px`, display: "grid", gridTemplateColumns: "repeat(7, 1fr)", width: "100%", color: t.textColor, fontFamily: t.fontFamily, fontWeight: t.fontWeight, fontSize: t.fontSize, }, children: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].map((day) => (_jsx("div", { style: { fontFamily: t.fontFamily }, children: day }, day))) }), _jsx("div", { style: { boxSizing: "border-box", padding: t.padding, gap: theme.spacingfactor, display: "grid", width: "100%", gridTemplateColumns: "repeat(7, 1fr)", textAlign: "center", }, children: dates.map((day, index) => { const isSelected = day !== null && selectedDate && selectedDate.toISOString().split("T")[0] === new Date(currentYear, currentMonth, day) .toISOString() .split("T")[0]; const isToday = day !== null && today.getDate() === day && today.getMonth() === currentMonth && today.getFullYear() === currentYear; return (_jsx("div", { style: { boxSizing: "border-box", width: "100%", aspectRatio: "1/1", display: "flex", justifyContent: "center", alignItems: "center", borderRadius: t.cornerRadius, transition: t.transitionDuration, color: t.textColor, fontFamily: t.fontFamily, fontWeight: t.fontWeight, fontSize: t.fontSize, ...(day && { cursor: "pointer" }), ...(isSelected && { backgroundColor: t.primaryColor, color: "#fff", borderRadius: "50%", border: `2px solid ${t.primaryColor}`, }), ...(!isSelected && isToday && { border: `2px solid ${t.primaryColor}`, }), }, onClick: () => handleDateClickInternal(day), onMouseOver: (e) => { if (day && !isSelected) { e.currentTarget.style.backgroundColor = t.hoverColor; } }, onMouseOut: (e) => { if (day && !isSelected) { e.currentTarget.style.backgroundColor = ""; } }, children: day || "" }, index)); }) })] }))] }) })); }; export default Calendar;