vuetify
Version:
Vue Material Component Framework
329 lines (325 loc) • 12.6 kB
JavaScript
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 { useDate } from "../../composables/date/index.js";
import { useLocale, useRtl } from "../../composables/locale.js";
import { useProxiedModel } from "../../composables/proxiedModel.js"; // Utilities
import { computed, shallowRef, toRef, watch } from 'vue';
import { 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,
...makeVDatePickerControlsProps(),
...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 = computed(() => {
const date = adapter.date(props.min);
return props.min && adapter.isValid(date) ? date : null;
});
const maxDate = computed(() => {
const date = adapter.date(props.max);
return props.max && adapter.isValid(date) ? date : null;
});
const internal = computed(() => {
const today = adapter.date();
let value = today;
if (model.value?.[0]) {
value = adapter.date(model.value[0]);
} else if (minDate.value && adapter.isBefore(today, minDate.value)) {
value = minDate.value;
} else if (maxDate.value && adapter.isAfter(today, maxDate.value)) {
value = maxDate.value;
}
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);
}
return model.value[0] && adapter.isValid(model.value[0]) ? adapter.format(adapter.date(model.value[0]), 'normalDateWithWeekday') : t(props.header);
});
const text = computed(() => {
let date = adapter.date();
date = adapter.setDate(date, 1);
date = adapter.setMonth(date, month.value);
date = adapter.setYear(date, year.value);
return adapter.format(date, 'monthAndYear');
});
// 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', 'next']);
} 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 date = adapter.addDays(adapter.startOfMonth(_date), -1);
adapter.isAfter(minDate.value, date) && targets.push('prev');
}
if (maxDate.value) {
const date = adapter.addDays(adapter.endOfMonth(_date), 1);
adapter.isAfter(date, maxDate.value) && targets.push('next');
}
}
return targets;
});
function isAllowedInRange(start, end) {
const allowedDates = props.allowedDates;
if (typeof allowedDates !== 'function') return true;
const days = adapter.getDiff(end, start, 'days');
for (let i = 0; i < days; i++) {
if (allowedDates(adapter.addDays(start, i))) return true;
}
return false;
}
function allowedYears(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 allowedMonths(month) {
if (typeof props.allowedDates === 'function') {
const startOfMonth = adapter.parseISO(`${year.value}-${month + 1}-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 onClickNext() {
if (month.value < 11) {
month.value++;
} else {
year.value++;
month.value = 0;
onUpdateYear();
}
onUpdateMonth();
}
function onClickPrev() {
if (month.value > 0) {
month.value--;
} else {
year.value--;
month.value = 11;
onUpdateYear();
}
onUpdateMonth();
}
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]);
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 = VDatePickerControls.filterProps(props);
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": 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
}), {
...slots,
default: undefined
}),
default: () => _createElementVNode(_Fragment, null, [_createVNode(VDatePickerControls, _mergeProps(datePickerControlsProps, {
"disabled": disabled.value,
"text": text.value,
"onClick:next": onClickNext,
"onClick:prev": onClickPrev,
"onClick:month": onClickMonth,
"onClick:year": onClickYear
}), null), _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
}), null) : 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
}), null) : _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
}), null)]
})]),
actions: slots.actions
});
});
return {};
}
});
//# sourceMappingURL=VDatePicker.js.map