(seed: Date | null)
| 220 | } |
| 221 | |
| 222 | function useCalendarView(seed: Date | null) { |
| 223 | const today = useMemo(() => new Date(), []) |
| 224 | const [view, setView] = useState(() => { |
| 225 | const base = seed ?? today |
| 226 | return { month: base.getMonth(), year: base.getFullYear() } |
| 227 | }) |
| 228 | |
| 229 | const goToPrevMonth = () => |
| 230 | setView((prev) => |
| 231 | prev.month === 0 |
| 232 | ? { month: 11, year: prev.year - 1 } |
| 233 | : { month: prev.month - 1, year: prev.year } |
| 234 | ) |
| 235 | |
| 236 | const goToNextMonth = () => |
| 237 | setView((prev) => |
| 238 | prev.month === 11 |
| 239 | ? { month: 0, year: prev.year + 1 } |
| 240 | : { month: prev.month + 1, year: prev.year } |
| 241 | ) |
| 242 | |
| 243 | const cells = useMemo<(number | null)[]>(() => { |
| 244 | const leading = getFirstDayOfMonth(view.year, view.month) |
| 245 | const total = getDaysInMonth(view.year, view.month) |
| 246 | const result: (number | null)[] = [] |
| 247 | for (let i = 0; i < leading; i++) result.push(null) |
| 248 | for (let day = 1; day <= total; day++) result.push(day) |
| 249 | return result |
| 250 | }, [view]) |
| 251 | |
| 252 | return { today, view, setView, goToPrevMonth, goToNextMonth, cells } |
| 253 | } |
| 254 | |
| 255 | function CalendarHeader({ |
| 256 | month, |
no test coverage detected