UNPKG

@vuetify/nightly

Version:

Vue Material Component Framework

334 lines (333 loc) • 10.5 kB
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