UNPKG

vuetify

Version:

Vue Material Component Framework

380 lines (375 loc) 14.9 kB
import { createElementVNode as _createElementVNode, createVNode as _createVNode, mergeProps as _mergeProps, Fragment as _Fragment } from "vue"; // Styles import "./VDatePicker.css"; // Components import { makeVDatePickerControlsProps, VDatePickerControls } from "./VDatePickerControls.js"; import { VDatePickerHeader } from "./VDatePickerHeader.js"; import { makeVDatePickerMonthProps, VDatePickerMonth } from "./VDatePickerMonth.js"; import { makeVDatePickerMonthsProps, VDatePickerMonths } from "./VDatePickerMonths.js"; import { makeVDatePickerYearsProps, VDatePickerYears } from "./VDatePickerYears.js"; import { VFadeTransition } from "../transitions/index.js"; import { VDefaultsProvider } from "../VDefaultsProvider/index.js"; import { makeVPickerProps, VPicker } from "../../labs/VPicker/VPicker.js"; // Composables import { useCalendarRange } from "../../composables/calendar.js"; import { useDate } from "../../composables/date/index.js"; import { daysDiff } from "../../composables/date/date.js"; import { useLocale, useRtl } from "../../composables/locale.js"; import { useProxiedModel } from "../../composables/proxiedModel.js"; // Utilities import { computed, shallowRef, toRef, watch } from 'vue'; import { convertToUnit, genericComponent, omit, propsFactory, useRender, wrapInArray } from "../../util/index.js"; // Types // Types export const makeVDatePickerProps = propsFactory({ // TODO: implement in v3.5 // calendarIcon: { // type: String, // default: '$calendar', // }, // keyboardIcon: { // type: String, // default: '$edit', // }, // inputMode: { // type: String as PropType<'calendar' | 'keyboard'>, // default: 'calendar', // }, // inputText: { // type: String, // default: '$vuetify.datePicker.input.placeholder', // }, // inputPlaceholder: { // type: String, // default: 'dd/mm/yyyy', // }, header: { type: String, default: '$vuetify.datePicker.header' }, headerColor: String, headerDateFormat: { type: String, default: 'normalDateWithWeekday' }, landscapeHeaderWidth: [Number, String], ...omit(makeVDatePickerControlsProps(), ['active', 'monthText', 'yearText']), ...makeVDatePickerMonthProps({ weeksInMonth: 'static' }), ...omit(makeVDatePickerMonthsProps(), ['modelValue']), ...omit(makeVDatePickerYearsProps(), ['modelValue']), ...makeVPickerProps({ title: '$vuetify.datePicker.title' }), modelValue: null }, 'VDatePicker'); export const VDatePicker = genericComponent()({ name: 'VDatePicker', props: makeVDatePickerProps(), emits: { 'update:modelValue': date => true, 'update:month': date => true, 'update:year': date => true, // 'update:inputMode': (date: any) => true, 'update:viewMode': date => true }, setup(props, _ref) { let { emit, slots } = _ref; const adapter = useDate(); const { t } = useLocale(); const { rtlClasses } = useRtl(); const model = useProxiedModel(props, 'modelValue', undefined, v => wrapInArray(v).map(i => adapter.date(i)), v => props.multiple ? v : v[0]); const viewMode = useProxiedModel(props, 'viewMode'); // const inputMode = useProxiedModel(props, 'inputMode') const { minDate, maxDate, clampDate } = useCalendarRange(props); const internal = computed(() => { const today = adapter.date(); const value = model.value?.[0] ? adapter.date(model.value[0]) : clampDate(today); return value && adapter.isValid(value) ? value : today; }); const headerColor = toRef(() => props.headerColor ?? props.color); const _month = useProxiedModel(props, 'month'); const month = computed({ get: () => Number(_month.value ?? adapter.getMonth(adapter.startOfMonth(internal.value))), set: v => _month.value = v }); const _year = useProxiedModel(props, 'year'); const year = computed({ get: () => Number(_year.value ?? adapter.getYear(adapter.startOfYear(adapter.setMonth(internal.value, month.value)))), set: v => _year.value = v }); const isReversing = shallowRef(false); const header = computed(() => { if (props.multiple && model.value.length > 1) { return t('$vuetify.datePicker.itemsSelected', model.value.length); } const formattedDate = model.value[0] && adapter.isValid(model.value[0]) ? adapter.format(adapter.date(model.value[0]), props.headerDateFormat) : t(props.header); return props.landscape && formattedDate.split(' ').length === 3 ? formattedDate.replace(' ', '\n') : formattedDate; }); const monthStart = toRef(() => { let date = adapter.date(); date = adapter.setDate(date, 1); date = adapter.setMonth(date, month.value); date = adapter.setYear(date, year.value); // year is not always ISO return date; }); const monthYearText = toRef(() => adapter.format(monthStart.value, 'monthAndYear')); const monthText = toRef(() => adapter.format(monthStart.value, 'monthShort')); const yearText = toRef(() => adapter.format(monthStart.value, 'year')); // const headerIcon = toRef(() => props.inputMode === 'calendar' ? props.keyboardIcon : props.calendarIcon) const headerTransition = toRef(() => `date-picker-header${isReversing.value ? '-reverse' : ''}-transition`); const disabled = computed(() => { if (props.disabled) return true; const targets = []; if (viewMode.value !== 'month') { targets.push(...['prev-month', 'next-month', 'prev-year', 'next-year']); } else { let _date = adapter.date(); _date = adapter.startOfMonth(_date); _date = adapter.setMonth(_date, month.value); _date = adapter.setYear(_date, year.value); if (minDate.value) { const prevMonthEnd = adapter.addDays(adapter.startOfMonth(_date), -1); const prevYearEnd = adapter.addDays(adapter.startOfYear(_date), -1); adapter.isAfter(minDate.value, prevMonthEnd) && targets.push('prev-month'); adapter.isAfter(minDate.value, prevYearEnd) && targets.push('prev-year'); } if (maxDate.value) { const nextMonthStart = adapter.addDays(adapter.endOfMonth(_date), 1); const nextYearStart = adapter.addDays(adapter.endOfYear(_date), 1); adapter.isAfter(nextMonthStart, maxDate.value) && targets.push('next-month'); adapter.isAfter(nextYearStart, maxDate.value) && targets.push('next-year'); } } return targets; }); const allowedYears = computed(() => { return props.allowedYears || isYearAllowed; }); const allowedMonths = computed(() => { return props.allowedMonths || isMonthAllowed; }); function isAllowedInRange(start, end) { const allowedDates = props.allowedDates; if (typeof allowedDates !== 'function') return true; const days = 1 + daysDiff(adapter, start, end); for (let i = 0; i < days; i++) { if (allowedDates(adapter.addDays(start, i))) return true; } return false; } function isYearAllowed(year) { if (typeof props.allowedDates === 'function') { const startOfYear = adapter.parseISO(`${year}-01-01`); return isAllowedInRange(startOfYear, adapter.endOfYear(startOfYear)); } if (Array.isArray(props.allowedDates) && props.allowedDates.length) { for (const date of props.allowedDates) { if (adapter.getYear(adapter.date(date)) === year) return true; } return false; } return true; } function isMonthAllowed(month) { if (typeof props.allowedDates === 'function') { const monthTwoDigits = String(month + 1).padStart(2, '0'); const startOfMonth = adapter.parseISO(`${year.value}-${monthTwoDigits}-01`); return isAllowedInRange(startOfMonth, adapter.endOfMonth(startOfMonth)); } if (Array.isArray(props.allowedDates) && props.allowedDates.length) { for (const date of props.allowedDates) { if (adapter.getYear(adapter.date(date)) === year.value && adapter.getMonth(adapter.date(date)) === month) return true; } return false; } return true; } // function onClickAppend () { // inputMode.value = inputMode.value === 'calendar' ? 'keyboard' : 'calendar' // } function onClickNextMonth() { if (month.value < 11) { month.value++; } else { year.value++; month.value = 0; onUpdateYear(); } onUpdateMonth(); } function onClickPrevMonth() { if (month.value > 0) { month.value--; } else { year.value--; month.value = 11; onUpdateYear(); } onUpdateMonth(); } function onClickNextYear() { year.value++; if (maxDate.value) { const monthTwoDigits = String(month.value + 1).padStart(2, '0'); const monthStart = adapter.parseISO(`${year.value}-${monthTwoDigits}-01`); if (adapter.isAfter(monthStart, maxDate.value)) { month.value = adapter.getMonth(maxDate.value); } } onUpdateYear(); } function onClickPrevYear() { year.value--; if (minDate.value) { const monthTwoDigits = String(month.value + 1).padStart(2, '0'); const monthStart = adapter.endOfMonth(adapter.parseISO(`${year.value}-${monthTwoDigits}-01`)); if (adapter.isAfter(minDate.value, monthStart)) { month.value = adapter.getMonth(minDate.value); } } onUpdateYear(); } function onClickDate() { viewMode.value = 'month'; } function onClickMonth() { viewMode.value = viewMode.value === 'months' ? 'month' : 'months'; } function onClickYear() { viewMode.value = viewMode.value === 'year' ? 'month' : 'year'; } function onUpdateMonth() { if (viewMode.value === 'months') onClickMonth(); } function onUpdateYear() { if (viewMode.value === 'year') onClickYear(); } watch(model, (val, oldVal) => { const arrBefore = wrapInArray(oldVal); const arrAfter = wrapInArray(val); if (!arrAfter.length) return; const before = adapter.date(arrBefore[arrBefore.length - 1]); const after = adapter.date(arrAfter[arrAfter.length - 1]); if (adapter.isSameDay(before, after)) return; const newMonth = adapter.getMonth(after); const newYear = adapter.getYear(after); if (newMonth !== month.value) { month.value = newMonth; onUpdateMonth(); } if (newYear !== year.value) { year.value = newYear; onUpdateYear(); } isReversing.value = adapter.isBefore(before, after); }); useRender(() => { const pickerProps = VPicker.filterProps(props); const datePickerControlsProps = omit(VDatePickerControls.filterProps(props), ['viewMode']); const datePickerHeaderProps = VDatePickerHeader.filterProps(props); const datePickerMonthProps = VDatePickerMonth.filterProps(props); const datePickerMonthsProps = omit(VDatePickerMonths.filterProps(props), ['modelValue']); const datePickerYearsProps = omit(VDatePickerYears.filterProps(props), ['modelValue']); const headerProps = { color: headerColor.value, header: header.value, transition: headerTransition.value }; return _createVNode(VPicker, _mergeProps(pickerProps, { "color": headerColor.value, "class": ['v-date-picker', `v-date-picker--${viewMode.value}`, { 'v-date-picker--show-week': props.showWeek }, rtlClasses.value, props.class], "style": [{ '--v-date-picker-landscape-header-width': convertToUnit(props.landscapeHeaderWidth) }, props.style] }), { title: () => slots.title?.() ?? _createElementVNode("div", { "class": "v-date-picker__title" }, [t(props.title)]), header: () => slots.header ? _createVNode(VDefaultsProvider, { "defaults": { VDatePickerHeader: { ...headerProps } } }, { default: () => [slots.header?.(headerProps)] }) : _createVNode(VDatePickerHeader, _mergeProps({ "key": "header" }, datePickerHeaderProps, headerProps, { "onClick": viewMode.value !== 'month' ? onClickDate : undefined }), { prepend: slots.prepend, append: slots.append }), default: () => _createElementVNode(_Fragment, null, [_createVNode(VDatePickerControls, _mergeProps(datePickerControlsProps, { "disabled": disabled.value, "viewMode": viewMode.value, "text": monthYearText.value, "monthText": monthText.value, "yearText": yearText.value, "onClick:next": onClickNextMonth, "onClick:prev": onClickPrevMonth, "onClick:nextYear": onClickNextYear, "onClick:prevYear": onClickPrevYear, "onClick:month": onClickMonth, "onClick:year": onClickYear }), { default: slots.controls }), _createVNode(VFadeTransition, { "hideOnLeave": true }, { default: () => [viewMode.value === 'months' ? _createVNode(VDatePickerMonths, _mergeProps({ "key": "date-picker-months" }, datePickerMonthsProps, { "modelValue": month.value, "onUpdate:modelValue": [$event => month.value = $event, onUpdateMonth], "min": minDate.value, "max": maxDate.value, "year": year.value, "allowedMonths": allowedMonths.value }), { month: slots.month }) : viewMode.value === 'year' ? _createVNode(VDatePickerYears, _mergeProps({ "key": "date-picker-years" }, datePickerYearsProps, { "modelValue": year.value, "onUpdate:modelValue": [$event => year.value = $event, onUpdateYear], "min": minDate.value, "max": maxDate.value, "allowedYears": allowedYears.value }), { year: slots.year }) : _createVNode(VDatePickerMonth, _mergeProps({ "key": "date-picker-month" }, datePickerMonthProps, { "modelValue": model.value, "onUpdate:modelValue": $event => model.value = $event, "month": month.value, "onUpdate:month": [$event => month.value = $event, onUpdateMonth], "year": year.value, "onUpdate:year": [$event => year.value = $event, onUpdateYear], "min": minDate.value, "max": maxDate.value }), { day: slots.day })] })]), actions: slots.actions }); }); return {}; } }); //# sourceMappingURL=VDatePicker.js.map