import { useEffect, useState } from 'react' import { getCalendarDates, getL10Weekday, generateUniqueId, applyColor } from '../utils' export interface SingleDatePickerProps { /** * Control the selected * date programmatically, including situations like provide a default value or control the selected * date by parent component. Use 1-12 for month, instead of 0-11, if you are using object to set the * value. * @example { year: 2025, month: 1, day: 1 } * @example new Date(2025, 0, 1) * @default new Date() */ value?: Date | { year: number, month: number, day: number } /** * A callback function that will be called when a date is selected inside the panel. * @param date - The date user selected. * @returns {{ year: number, month: number, day: number }} - The date user selected. * @example { year: 2025, month: 1, day: 1 } // User selected 1 Jan 2025 */ onSelect?: (date: { year: number, month: number, day: number }) => void /** * The language code that will be used to localize the panel. * Accept standard ISO 639-1 language code, such as 'zh-CN', 'en-US', 'ja-JP', etc. Note * that it will not effect to the screen reader, but the screen reader will still read the * date in the user’s language. * @default navigator.language */ localization?: string /** * User requires to close the panel without select a specific date. Note that the close button is not * visible, but can be read by screen reader. The close button for the screen reader is only available * when this prop is not `undefined`. * @default undefined */ onClose?: () => void /** * The main color of the panel, including the text color and the border color. *@default '#000000' */ mainColor?: string /** * The accent color of the panel, including the background color of the selected date. *@default '#000000' */ accentColor?: string /** * The reversed color of the panel, including the text color of the selected date. *@default '#ffffff' */ reversedColor?: string /** * The hover color of the panel, including the hover background color of the date. *@default '#00000017' */ hoverColor?: string /** * The border color of the panel, including the divider color between the header and the body. *@default '#e0e0e0' */ borderColor?: string } /** * A panel that allows users to select a date. * * @component * * @param {SingleDatePickerProps} props */ const SingleDatePicker: React.FC = ({ value, onSelect, localization, onClose, mainColor = '#000000', accentColor = '#000000', reversedColor = '#ffffff', hoverColor = '#00000017', borderColor = '#e0e0e0' }: SingleDatePickerProps) => { const [currentMonth, setCurrentMonth] = useState(new Date().getMonth()) const [currentYear, setCurrentYear] = useState(new Date().getFullYear()) const [selectedDate, setSelectedDate] = useState(new Date()) const [dates, setDates] = useState([]) const [l10nDays, setL10nDays] = useState([]) const [selectMonth, setSelectMonth] = useState(false) const uniqueId = generateUniqueId() useEffect(() => { setDates(getCalendarDates(currentMonth, currentYear)) }, [currentMonth, currentYear]) useEffect(() => { if (!value) return if (!(value instanceof Date)) { if (value.year < 100) value.year = Number(`20${value.year}`) if (value.month < 0 || value.month > 11) return console.warn('Invalid value: Month should be between 1 and 12.') if (value.day < 1 || value.day > 31) return console.warn('Invalid value: Day should be between 1 and 31.') } const date = value instanceof Date ? value : new Date(value.year, value.month - 1, value.day) setSelectedDate(date) setCurrentMonth(date.getMonth()) setCurrentYear(date.getFullYear()) }, [value]) useEffect(() => { const i18n = localization || navigator.language setL10nDays(getL10Weekday(i18n)) }, [localization]) useEffect(() => { applyColor(uniqueId, { mainColor: mainColor, accentColor: accentColor, reversedColor: reversedColor, hoverColor: hoverColor, borderColor: borderColor }) } , [mainColor, accentColor, reversedColor, hoverColor, borderColor]) useEffect(() => { applyColor(uniqueId, { mainColor: mainColor, accentColor: accentColor, reversedColor: reversedColor, hoverColor: hoverColor, borderColor: borderColor }) }, []) function selectDate(date: Date) { setSelectedDate(date) onSelect?.({ year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate() }) } function skipToLastMonth() { if (currentMonth === 0) { setCurrentMonth(11) setCurrentYear(currentYear - 1) } else setCurrentMonth(currentMonth - 1) } function skipToNextMonth() { if (currentMonth === 11) { setCurrentMonth(0) setCurrentYear(currentYear + 1) } else setCurrentMonth(currentMonth + 1) } function changeYear(year: string) { if (isNaN(Number(year))) return if (Number(year) < 0) return setCurrentYear(Number(year)) } function adjustYear() { if (currentYear < 100) setCurrentYear(Number(`20${currentYear}`)) } if (selectMonth) return ( ) else return ( ) } export default SingleDatePicker