import {computed, ref} from "vue"; import { addMonths, addYears, eachDayOfInterval, endOfISOWeek, getYear, getDate, isSameMonth, startOfISOWeek, startOfMonth, subMonths, subYears, addWeeks, startOfYear, endOfYear, eachMonthOfInterval, format, isSameDay, } from "date-fns"; interface Day { date: Date; number: number; active: boolean; currentMonth: boolean; } interface Month { date: Date; label: string; active: boolean; } enum ViewMode { Days, Months, Years, } function getVisibleDays(selectedDate: Date, startOfCurrentMonth: Date): Day[] { const startDate = startOfISOWeek(startOfCurrentMonth); const endDate = endOfISOWeek(addWeeks(startDate, 5)); return eachDayOfInterval({ start: startDate, end: endDate }).map((day: Date) => ({ date: day, number: getDate(day), active: isSameDay(day, selectedDate), currentMonth: isSameMonth(day, startOfCurrentMonth), })); } function getVisibleMonths(startOfCurrentYear: Date, startOfCurrentMonth: Date): Month[] { const startDate = startOfCurrentYear; const endDate = endOfYear(startOfCurrentYear); return eachMonthOfInterval({ start: startDate, end: endDate, }).map(month => ({ date: month, label: format(month, 'MMMM'), active: isSameMonth(month, startOfCurrentMonth), })); } export default function (initialDate?: Date|string|number) { const visible = ref(false); const selectedDate = ref(initialDate ? new Date(initialDate) : new Date()); const startOfCurrentMonth = ref(startOfMonth(selectedDate.value)); const currentYear = computed(() => getYear(startOfCurrentMonth.value)); const visibleDays = computed(() => getVisibleDays(selectedDate.value, startOfCurrentMonth.value)); const visibleMonths = computed(() => getVisibleMonths( startOfYear(startOfCurrentMonth.value), startOfCurrentMonth.value) ); const viewMode = ref(ViewMode.Days); const showingDays = computed(() => viewMode.value === ViewMode.Days); const showingMonths = computed(() => viewMode.value === ViewMode.Months); return { selectedDate, currentYear, visibleDays, visibleMonths, visible, startOfCurrentMonth, showingDays, showingMonths, open() { visible.value = true; }, close() { visible.value = false; }, toggle() { visible.value = !visible.value; }, select(date: Date, close: boolean = false) { selectedDate.value = date; startOfCurrentMonth.value = startOfMonth(date) if (close) { visible.value = false; } }, showMonths() { viewMode.value = ViewMode.Months; }, selectMonth(month: Month) { startOfCurrentMonth.value = month.date; viewMode.value = ViewMode.Days; }, nextMonth() { startOfCurrentMonth.value = startOfMonth(addMonths(startOfCurrentMonth.value, 1)); }, previousMonth() { startOfCurrentMonth.value = startOfMonth(subMonths(startOfCurrentMonth.value, 1)); }, nextYear() { startOfCurrentMonth.value = startOfMonth(addYears(startOfCurrentMonth.value, 1)); }, previousYear() { startOfCurrentMonth.value = startOfMonth(subYears(startOfCurrentMonth.value, 1)); }, }; };