@vuetify/nightly
Version:
Vue Material Component Framework
334 lines (333 loc) • 10.5 kB
JavaScript
import { mergeProps as _mergeProps, createVNode as _createVNode, withDirectives as _withDirectives } from "vue";
// Styles
import "./VCalendarCategory.css";
import "./VCalendarDaily.css";
import "./VCalendarWeekly.css";
// Components
import { VCalendarCategory } from "./VCalendarCategory.js";
import { VCalendarDaily } from "./VCalendarDaily.js";
import { VCalendarWeekly } from "./VCalendarWeekly.js"; // Composables
import { makeCalendarBaseProps } from "./composables/calendarBase.js";
import { makeCalendarWithEventsProps, useCalendarWithEvents } from "./composables/calendarWithEvents.js";
import { forwardRefs } from "../../composables/forwardRefs.js"; // Directives
import vResize from "../../directives/resize/index.js"; // Utilities
import { computed, onMounted, onUpdated, ref, watch } from 'vue';
import { getParsedCategories } from "./util/parser.js";
import { copyTimestamp, DAY_MIN, DAYS_IN_MONTH_MAX, DAYS_IN_WEEK, getEndOfMonth, getStartOfMonth, nextDay, prevDay, relativeDays, timestampToDate, updateFormatted, updateRelative, updateWeekday, validateTimestamp } from "./util/timestamp.js";
import { genericComponent, useRender } from "../../util/index.js"; // Types
// Types
export const VCalendar = genericComponent()({
name: 'VCalendar',
directives: {
vResize
},
props: {
modelValue: {
type: [String, Number, Date],
validate: validateTimestamp
},
categoryDays: {
type: [Number, String],
default: 1,
validate: x => isFinite(parseInt(x)) && parseInt(x) > 0
},
categories: {
type: [Array, String],
default: ''
},
categoryText: {
type: [String, Function]
},
maxDays: {
type: Number,
default: 7
},
categoryHideDynamic: {
type: Boolean
},
categoryShowAll: {
type: Boolean
},
categoryForInvalid: {
type: String,
default: ''
},
...makeCalendarBaseProps(),
...makeCalendarWithEventsProps()
},
setup(props, _ref) {
let {
slots,
attrs,
emit
} = _ref;
const root = ref();
const base = useCalendarWithEvents(props, slots, attrs);
const lastStart = ref(null);
const lastEnd = ref(null);
const parsedCategoryDays = computed(() => {
return parseInt(String(props.categoryDays)) || 1;
});
const parsedCategories = computed(() => {
return getParsedCategories(props.categories, props.categoryText);
});
const renderProps = computed(() => {
const around = base.parsedValue.value;
let component = null;
let maxDays = props.maxDays;
let categories = parsedCategories.value;
let start = around;
let end = around;
switch (props.type) {
case 'month':
component = VCalendarWeekly;
start = getStartOfMonth(around);
end = getEndOfMonth(around);
break;
case 'week':
component = VCalendarDaily;
start = base.getStartOfWeek(around);
end = base.getEndOfWeek(around);
maxDays = 7;
break;
case 'day':
component = VCalendarDaily;
maxDays = 1;
break;
case '4day':
component = VCalendarDaily;
end = relativeDays(copyTimestamp(end), nextDay, 3);
updateFormatted(end);
maxDays = 4;
break;
case 'custom-weekly':
component = VCalendarWeekly;
start = base.parsedStart.value || around;
end = base.parsedEnd.value;
break;
case 'custom-daily':
component = VCalendarDaily;
start = base.parsedStart.value || around;
end = base.parsedEnd.value;
break;
case 'category':
const days = parsedCategoryDays.value;
component = VCalendarCategory;
end = relativeDays(copyTimestamp(end), nextDay, days);
updateFormatted(end);
maxDays = days;
categories = getCategoryList(categories);
break;
default:
const type = props.type;
throw new Error(`${type} is not a valid Calendar type`);
}
return {
component,
start,
end,
maxDays,
categories
};
});
const eventWeekdays = computed(() => {
return base.effectiveWeekdays.value;
});
const categoryMode = computed(() => {
return props.type === 'category';
});
const monthLongFormatter = computed(() => {
return base.getFormatter({
timeZone: 'UTC',
month: 'long'
});
});
const monthShortFormatter = computed(() => {
return base.getFormatter({
timeZone: 'UTC',
month: 'short'
});
});
const title = computed(() => {
const {
start,
end
} = renderProps.value;
const spanYears = start.year !== end.year;
const spanMonths = spanYears || start.month !== end.month;
if (spanYears) {
return monthShortFormatter.value(start, true) + ' ' + start.year + ' - ' + monthShortFormatter.value(end, true) + ' ' + end.year;
}
if (spanMonths) {
return monthShortFormatter.value(start, true) + ' - ' + monthShortFormatter.value(end, true) + ' ' + end.year;
} else {
return monthLongFormatter.value(start, false) + ' ' + start.year;
}
});
function checkChange() {
const {
start,
end
} = renderProps.value;
if (!lastStart.value || !lastEnd.value || start.date !== lastStart.value.date || end.date !== lastEnd.value.date) {
lastStart.value = start;
lastEnd.value = end;
emit('change', {
start,
end
});
}
}
function move() {
let amount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
const moved = copyTimestamp(base.parsedValue.value);
const forward = amount > 0;
const mover = forward ? nextDay : prevDay;
const limit = forward ? DAYS_IN_MONTH_MAX : DAY_MIN;
let times = forward ? amount : -amount;
while (--times >= 0) {
switch (props.type) {
case 'month':
moved.day = limit;
mover(moved);
break;
case 'week':
relativeDays(moved, mover, DAYS_IN_WEEK);
break;
case 'day':
relativeDays(moved, mover, 1);
break;
case '4day':
relativeDays(moved, mover, 4);
break;
case 'category':
relativeDays(moved, mover, parsedCategoryDays.value);
break;
}
}
updateWeekday(moved);
updateFormatted(moved);
updateRelative(moved, base.times.now);
if (props.modelValue instanceof Date) {
emit('update:modelValue', timestampToDate(moved));
} else if (typeof props.modelValue === 'number') {
emit('update:modelValue', timestampToDate(moved).getTime());
} else {
emit('update:modelValue', moved.date);
}
emit('moved', moved);
}
function next() {
let amount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
move(amount);
}
function prev() {
let amount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
move(-amount);
}
function getCategoryList(categories) {
if (!base.noEvents.value) {
const categoryMap = categories.reduce((map, category, index) => {
if (typeof category === 'object' && category.categoryName) map[category.categoryName] = {
index,
count: 0
};else if (typeof category === 'string') map[category] = {
index,
count: 0
};
return map;
}, {});
if (!props.categoryHideDynamic || !props.categoryShowAll) {
let categoryLength = categories.length;
base.parsedEvents.value.forEach(ev => {
let category = ev.category;
if (typeof category !== 'string') {
category = props.categoryForInvalid;
}
if (!category) {
return;
}
if (category in categoryMap) {
categoryMap[category].count++;
} else if (!props.categoryHideDynamic) {
categoryMap[category] = {
index: categoryLength++,
count: 1
};
}
});
}
if (!props.categoryShowAll) {
for (const category in categoryMap) {
if (categoryMap[category].count === 0) {
delete categoryMap[category];
}
}
}
categories = categories.filter(category => {
if (typeof category === 'object' && category.categoryName) {
return categoryMap.hasOwnProperty(category.categoryName);
} else if (typeof category === 'string') {
return categoryMap.hasOwnProperty(category);
}
return false;
});
}
return categories;
}
watch(renderProps, checkChange);
onMounted(() => {
base.updateEventVisibility();
checkChange();
});
onUpdated(() => {
window.requestAnimationFrame(base.updateEventVisibility);
});
useRender(() => {
const {
start,
end,
maxDays,
component: Component,
categories
} = renderProps.value;
return _withDirectives(_createVNode(Component, _mergeProps({
"ref": root,
"class": ['v-calendar', {
'v-calendar-events': !base.noEvents.value
}],
"role": "grid"
}, Component.filterProps(props), {
"start": start.date,
"end": end.date,
"maxDays": maxDays,
"weekdays": base.effectiveWeekdays.value,
"categories": categories,
"onClick:date": (e, day) => {
if (attrs['onUpdate:modelValue']) emit('update:modelValue', day.date);
}
}), base.getScopedSlots()), [[vResize, base.updateEventVisibility, void 0, {
quiet: true
}]]);
});
return forwardRefs({
...base,
lastStart,
lastEnd,
parsedCategoryDays,
renderProps,
eventWeekdays,
categoryMode,
title,
monthLongFormatter,
monthShortFormatter,
parsedCategories,
checkChange,
move,
next,
prev,
getCategoryList
}, root);
}
});
//# sourceMappingURL=VCalendar.js.map