UNPKG

vuetify

Version:

Vue Material Component Framework

281 lines (274 loc) 10.7 kB
import { createVNode as _createVNode, createTextVNode as _createTextVNode } from "vue"; // Styles import "./VDatePickerMonth.css"; // Components import { VBtn } from "../../components/VBtn/index.mjs"; // Composables import { useDatePicker } from "./composables.mjs"; import { useBackgroundColor } from "../../composables/color.mjs"; // Utilities import { computed, ref } from 'vue'; import { genericComponent, omit, propsFactory } from "../../util/index.mjs"; // Types import { getWeek, toIso } from "../date/date.mjs"; import { dateEmits, makeDateProps } from "../VDateInput/composables.mjs"; import { useDate } from "../date/index.mjs"; export const makeVDatePickerMonthProps = propsFactory({ color: String, showAdjacentMonths: Boolean, hideWeekdays: Boolean, showWeek: Boolean, hoverDate: null, multiple: Boolean, side: { type: String }, ...omit(makeDateProps(), ['inputMode', 'viewMode']) }, 'VDatePickerMonth'); export const VDatePickerMonth = genericComponent()({ name: 'VDatePickerMonth', props: makeVDatePickerMonthProps({ color: 'surface-variant' }), emits: { ...omit(dateEmits, ['update:inputMode', 'update:viewMode']), 'update:hoverDate': date => true }, setup(props, _ref) { let { emit, slots } = _ref; const adapter = useDate(); const { isDragging, dragHandle, hasScrolled } = useDatePicker(); const month = computed(() => props.displayDate); const findClosestDate = (date, dates) => { const { isSameDay, getDiff } = adapter; const [startDate, endDate] = dates; if (isSameDay(startDate, endDate)) { return getDiff(date, startDate, 'days') > 0 ? endDate : startDate; } const distStart = Math.abs(getDiff(date, startDate)); const distEnd = Math.abs(getDiff(date, endDate)); return distStart < distEnd ? startDate : endDate; }; // const hoverRange = computed<[any, any] | null>(() => { // if (!props.hoverDate) return null // const closestDate = findClosestDate(props.hoverDate, props.modelValue) // if (!closestDate) return null // return adapter.isAfter(props.hoverDate, closestDate) ? [closestDate, props.hoverDate] : [props.hoverDate, closestDate] // }) const weeksInMonth = computed(() => { const weeks = adapter.getWeekArray(month.value); const days = weeks.flat(); // Make sure there's always 6 weeks in month (6 * 7 days) // But only do it if we're not hiding adjacent months? const daysInMonth = 6 * 7; if (days.length < daysInMonth && props.showAdjacentMonths) { const lastDay = days[days.length - 1]; let week = []; for (let day = 1; day <= daysInMonth - days.length; day++) { week.push(adapter.addDays(lastDay, day)); if (day % 7 === 0) { weeks.push(week); week = []; } } } return weeks; }); const daysInMonth = computed(() => { const validDates = props.modelValue.filter(v => !!v); const isRange = validDates.length > 1; const days = weeksInMonth.value.flat(); const today = adapter.date(); const startDate = validDates[0]; const endDate = validDates[1]; return days.map((date, index) => { const isStart = startDate && adapter.isSameDay(date, startDate); const isEnd = endDate && adapter.isSameDay(date, endDate); const isAdjacent = !adapter.isSameMonth(date, month.value); const isSame = validDates.length === 2 && adapter.isSameDay(startDate, endDate); return { date, isoDate: toIso(adapter, date), formatted: adapter.format(date, 'keyboardDate'), year: adapter.getYear(date), month: adapter.getMonth(date), isWeekStart: index % 7 === 0, isWeekEnd: index % 7 === 6, isSelected: isStart || isEnd, isStart, isEnd, isToday: adapter.isSameDay(date, today), isAdjacent, isHidden: isAdjacent && !props.showAdjacentMonths, inRange: isRange && !isSame && (isStart || isEnd || validDates.length === 2 && adapter.isWithinRange(date, validDates)), // isHovered: props.hoverDate === date, // inHover: hoverRange.value && isWithinRange(date, hoverRange.value), isHovered: false, inHover: false, localized: adapter.format(date, 'dayOfMonth') }; }); }); const weeks = computed(() => { return weeksInMonth.value.map(week => { return getWeek(adapter, week[0]); }); }); const { backgroundColorClasses, backgroundColorStyles } = useBackgroundColor(props, 'color'); function selectDate(date) { let newModel = props.modelValue.slice(); if (props.multiple) { if (isDragging.value && dragHandle.value != null) { const otherIndex = (dragHandle.value + 1) % 2; const fn = otherIndex === 0 ? 'isBefore' : 'isAfter'; if (adapter[fn](date, newModel[otherIndex])) { newModel[dragHandle.value] = newModel[otherIndex]; newModel[otherIndex] = date; dragHandle.value = otherIndex; } else { newModel[dragHandle.value] = date; } } else { if (newModel.find(d => adapter.isSameDay(d, date))) { newModel = newModel.filter(v => !adapter.isSameDay(v, date)); } else if (newModel.length === 2) { let index; if (!props.side || adapter.isSameMonth(newModel[0], newModel[1])) { const closest = findClosestDate(date, newModel); index = newModel.indexOf(closest); } else { index = props.side === 'start' ? 0 : props.side === 'end' ? 1 : undefined; } newModel = newModel.map((v, i) => i === index ? date : v); } else { if (newModel[0] && adapter.isBefore(newModel[0], date)) { newModel = [newModel[0], date]; } else { newModel = [date, newModel[0]]; } } } } else { newModel = [date]; } emit('update:modelValue', newModel.filter(v => !!v)); } const daysRef = ref(); function findElement(el) { if (!el || el === daysRef.value) return null; if ('vDate' in el.dataset) { return adapter.date(el.dataset.vDate); } return findElement(el.parentElement); } function findDate(e) { const x = 'changedTouches' in e ? e.changedTouches[0]?.clientX : e.clientX; const y = 'changedTouches' in e ? e.changedTouches[0]?.clientY : e.clientY; const el = document.elementFromPoint(x, y); return findElement(el); } let canDrag = false; function handleMousedown(e) { hasScrolled.value = false; const selected = findDate(e); if (!selected) return; const modelIndex = props.modelValue.findIndex(d => adapter.isEqual(d, selected)); if (modelIndex >= 0) { canDrag = true; dragHandle.value = modelIndex; window.addEventListener('touchmove', handleTouchmove, { passive: false }); window.addEventListener('mousemove', handleTouchmove, { passive: false }); e.preventDefault(); } window.addEventListener('touchend', handleTouchend, { passive: false }); window.addEventListener('mouseup', handleTouchend, { passive: false }); } function handleTouchmove(e) { if (!canDrag) return; e.preventDefault(); isDragging.value = true; const over = findDate(e); if (!over) return; selectDate(over); } function handleTouchend(e) { if (e.cancelable) e.preventDefault(); window.removeEventListener('touchmove', handleTouchmove); window.removeEventListener('mousemove', handleTouchmove); window.removeEventListener('touchend', handleTouchend); window.removeEventListener('mouseup', handleTouchend); const end = findDate(e); if (!end) return; if (!hasScrolled.value) { selectDate(end); } isDragging.value = false; dragHandle.value = null; canDrag = false; } return () => _createVNode("div", { "class": "v-date-picker-month" }, [props.showWeek && _createVNode("div", { "key": "weeks", "class": "v-date-picker-month__weeks" }, [!props.hideWeekdays && _createVNode("div", { "key": "hide-week-days", "class": "v-date-picker-month__day" }, [_createTextVNode("\xA0")]), weeks.value.map(week => _createVNode("div", { "class": ['v-date-picker-month__day', 'v-date-picker-month__day--adjacent'] }, [week]))]), _createVNode("div", { "ref": daysRef, "class": "v-date-picker-month__days", "onMousedown": handleMousedown, "onTouchstart": handleMousedown }, [!props.hideWeekdays && adapter.getWeekdays().map(weekDay => _createVNode("div", { "class": ['v-date-picker-month__day', 'v-date-picker-month__weekday'] }, [weekDay.charAt(0)])), daysInMonth.value.map((item, index) => _createVNode("div", { "class": ['v-date-picker-month__day', { 'v-date-picker-month__day--selected': item.isSelected, 'v-date-picker-month__day--start': item.isStart, 'v-date-picker-month__day--end': item.isEnd, 'v-date-picker-month__day--adjacent': item.isAdjacent, 'v-date-picker-month__day--hide-adjacent': item.isHidden, 'v-date-picker-month__day--week-start': item.isWeekStart, 'v-date-picker-month__day--week-end': item.isWeekEnd, 'v-date-picker-month__day--hovered': item.isHovered }], "data-v-date": !item.isHidden ? item.isoDate : undefined }, [item.inRange && _createVNode("div", { "key": "in-range", "class": ['v-date-picker-month__day--range', backgroundColorClasses.value], "style": backgroundColorStyles.value }, null), item.inHover && !item.isStart && !item.isEnd && !item.isHovered && !item.inRange && _createVNode("div", { "key": "in-hover", "class": "v-date-picker-month__day--hover" }, null), (props.showAdjacentMonths || !item.isAdjacent) && _createVNode(VBtn, { "icon": true, "ripple": false, "variant": (item.isToday || item.isHovered) && !item.isSelected ? 'outlined' : 'flat', "active": item.isSelected, "color": item.isSelected || item.isToday ? props.color : item.isHovered ? undefined : 'transparent' }, { default: () => [item.localized] })]))])]); } }); //# sourceMappingURL=VDatePickerMonth.mjs.map