element-plus
Version:
A Component Library for Vue3.0
442 lines (430 loc) • 16 kB
JavaScript
import { t } from '../locale';
import ElButton from '../el-button';
import ElButtonGroup from '../el-button-group';
import { defineComponent, ref, computed, openBlock, createBlock, Fragment, renderList, toDisplayString, createCommentVNode, createVNode, renderSlot, resolveComponent, withCtx, createTextVNode, createSlots } from 'vue';
import dayjs from 'dayjs';
import localeData from 'dayjs/plugin/localeData';
import { rangeArr } from '../el-time-picker';
dayjs.extend(localeData);
const getPrevMonthLastDays = (date, amount) => {
const lastDay = date.subtract(1, 'month').endOf('month').date();
return rangeArr(amount).map((_, index) => lastDay - (amount - index - 1));
};
const getMonthDays = (date) => {
const days = date.daysInMonth();
return rangeArr(days).map((_, index) => index + 1);
};
var script = defineComponent({
props: {
selectedDay: {
type: Object,
},
range: {
type: Array,
},
date: {
type: Object,
},
hideHeader: {
type: Boolean,
},
},
emits: ['pick'],
setup(props, ctx) {
const WEEK_DAYS = ref(dayjs().localeData().weekdaysShort());
const now = dayjs();
const firstDayOfWeek = now.$locale().weekStart || 0;
const toNestedArr = days => {
return rangeArr(days.length / 7).map((_, index) => {
const start = index * 7;
return days.slice(start, start + 7);
});
};
const getFormattedDate = (day, type) => {
let result;
if (type === 'prev') {
result = props.date.startOf('month').subtract(1, 'month').date(day);
}
else if (type === 'next') {
result = props.date.startOf('month').add(1, 'month').date(day);
}
else {
result = props.date.date(day);
}
return result;
};
const getCellClass = ({ text, type }) => {
const classes = [type];
if (type === 'current') {
const date_ = getFormattedDate(text, type);
if (date_.isSame(props.selectedDay, 'day')) {
classes.push('is-selected');
}
if (date_.isSame(now, 'day')) {
classes.push('is-today');
}
}
return classes;
};
const pickDay = ({ text, type }) => {
const date = getFormattedDate(text, type);
ctx.emit('pick', date);
};
const getSlotData = ({ text, type }) => {
const day = getFormattedDate(text, type);
return {
isSelected: day.isSame(props.selectedDay),
type: `${type}-month`,
day: day.format('YYYY-MM-DD'),
date: day.toDate(),
};
};
const isInRange = computed(() => {
return props.range && props.range.length;
});
const rows = computed(() => {
let days = [];
if (isInRange.value) {
const [start, end] = props.range;
const currentMonthRange = rangeArr(end.date() - start.date() + 1).map((_, index) => ({
text: start.date() + index,
type: 'current',
}));
let remaining = currentMonthRange.length % 7;
remaining = remaining === 0 ? 0 : 7 - remaining;
const nextMonthRange = rangeArr(remaining).map((_, index) => ({
text: index + 1,
type: 'next',
}));
days = currentMonthRange.concat(nextMonthRange);
}
else {
const firstDay = props.date.startOf('month').day() || 7;
const prevMonthDays = getPrevMonthLastDays(props.date, firstDay - firstDayOfWeek).map(day => ({
text: day,
type: 'prev',
}));
const currentMonthDays = getMonthDays(props.date).map(day => ({
text: day,
type: 'current',
}));
days = [...prevMonthDays, ...currentMonthDays];
const nextMonthDays = rangeArr(42 - days.length).map((_, index) => ({
text: index + 1,
type: 'next',
}));
days = days.concat(nextMonthDays);
}
return toNestedArr(days);
});
const weekDays = computed(() => {
const start = firstDayOfWeek;
if (start === 0) {
return WEEK_DAYS.value;
}
else {
return WEEK_DAYS.value
.slice(start)
.concat(WEEK_DAYS.value.slice(0, start));
}
});
return {
isInRange,
weekDays,
rows,
getCellClass,
pickDay,
getSlotData,
};
},
});
const _hoisted_1 = { key: 0 };
const _hoisted_2 = { class: "el-calendar-day" };
function render(_ctx, _cache, $props, $setup, $data, $options) {
return (openBlock(), createBlock("table", {
class: {
'el-calendar-table': true,
'is-range': _ctx.isInRange
},
cellspacing: "0",
cellpadding: "0"
}, [
(!_ctx.hideHeader)
? (openBlock(), createBlock("thead", _hoisted_1, [
(openBlock(true), createBlock(Fragment, null, renderList(_ctx.weekDays, (day) => {
return (openBlock(), createBlock("th", { key: day }, toDisplayString(day), 1 /* TEXT */))
}), 128 /* KEYED_FRAGMENT */))
]))
: createCommentVNode("v-if", true),
createVNode("tbody", null, [
(openBlock(true), createBlock(Fragment, null, renderList(_ctx.rows, (row, index) => {
return (openBlock(), createBlock("tr", {
key: index,
class: {
'el-calendar-table__row': true,
'el-calendar-table__row--hide-border': index === 0 && _ctx.hideHeader
}
}, [
(openBlock(true), createBlock(Fragment, null, renderList(row, (cell, key) => {
return (openBlock(), createBlock("td", {
key: key,
class: _ctx.getCellClass(cell),
onClick: $event => (_ctx.pickDay(cell))
}, [
createVNode("div", _hoisted_2, [
renderSlot(_ctx.$slots, "dateCell", {
data: _ctx.getSlotData(cell)
}, () => [
createVNode("span", null, toDisplayString(cell.text), 1 /* TEXT */)
])
])
], 10 /* CLASS, PROPS */, ["onClick"]))
}), 128 /* KEYED_FRAGMENT */))
], 2 /* CLASS */))
}), 128 /* KEYED_FRAGMENT */))
])
], 2 /* CLASS */))
}
script.render = render;
script.__file = "packages/calendar/src/date-table.vue";
var script$1 = defineComponent({
name: 'ElCalendar',
components: {
DateTable: script,
ElButton,
ElButtonGroup,
},
props: {
modelValue: {
type: Date,
},
range: {
type: Array,
validator: (range) => {
if (Array.isArray(range)) {
return (range.length === 2 &&
range.every(item => item instanceof Date));
}
return false;
},
},
},
emits: ['input', 'update:modelValue'],
setup(props, ctx) {
const selectedDay = ref(null);
const now = dayjs();
const prevMonthDayjs = computed(() => {
return date.value.subtract(1, 'month');
});
const curMonthDatePrefix = computed(() => {
return dayjs(date.value).format('YYYY-MM');
});
const nextMonthDayjs = computed(() => {
return date.value.add(1, 'month');
});
const i18nDate = computed(() => {
const pickedMonth = `el.datepicker.month${date.value.format('M')}`;
return `${date.value.year()} ${t('el.datepicker.year')} ${t(pickedMonth)}`;
});
const realSelectedDay = computed({
get() {
if (!props.modelValue)
return selectedDay.value;
return date.value;
},
set(val) {
selectedDay.value = val;
const result = val.toDate();
ctx.emit('input', result);
ctx.emit('update:modelValue', result);
},
});
const date = computed(() => {
if (!props.modelValue) {
if (realSelectedDay.value) {
return realSelectedDay.value;
}
else if (validatedRange.value.length) {
return validatedRange.value[0][0];
}
return now;
}
else {
return dayjs(props.modelValue);
}
});
const validatedRange = computed(() => {
if (!props.range)
return [];
const rangeArrDayjs = props.range.map(_ => dayjs(_));
const [startDayjs, endDayjs] = rangeArrDayjs;
if (startDayjs.isAfter(endDayjs)) {
console.warn('[ElementCalendar]end time should be greater than start time');
return [];
}
if (startDayjs.isSame(endDayjs, 'month')) {
return [[
startDayjs.startOf('week'),
endDayjs.endOf('week'),
]];
}
else {
if (startDayjs.add(1, 'month').month() !== endDayjs.month()) {
console.warn('[ElementCalendar]start time and end time interval must not exceed two months');
return [];
}
const endMonthFirstDay = endDayjs.startOf('month');
const endMonthFirstWeekDay = endMonthFirstDay.startOf('week');
let endMonthStart = endMonthFirstDay;
if (!endMonthFirstDay.isSame(endMonthFirstWeekDay, 'month')) {
endMonthStart = endMonthFirstDay.endOf('week').add(1, 'day');
}
return [
[
startDayjs.startOf('week'),
startDayjs.endOf('month'),
],
[
endMonthStart,
endDayjs.endOf('week'),
],
];
}
});
const pickDay = (day) => {
realSelectedDay.value = day;
};
const selectDate = type => {
let day;
if (type === 'prev-month') {
day = prevMonthDayjs.value;
}
else if (type === 'next-month') {
day = nextMonthDayjs.value;
}
else {
day = now;
}
if (day.isSame(date.value, 'day'))
return;
pickDay(day);
};
return {
selectedDay,
curMonthDatePrefix,
i18nDate,
realSelectedDay,
date,
validatedRange,
pickDay,
selectDate,
t,
};
},
});
const _hoisted_1$1 = { class: "el-calendar" };
const _hoisted_2$1 = { class: "el-calendar__header" };
const _hoisted_3 = { class: "el-calendar__title" };
const _hoisted_4 = {
key: 0,
class: "el-calendar__button-group"
};
const _hoisted_5 = {
key: 0,
class: "el-calendar__body"
};
const _hoisted_6 = {
key: 1,
class: "el-calendar__body"
};
function render$1(_ctx, _cache, $props, $setup, $data, $options) {
const _component_el_button = resolveComponent("el-button");
const _component_el_button_group = resolveComponent("el-button-group");
const _component_date_table = resolveComponent("date-table");
return (openBlock(), createBlock("div", _hoisted_1$1, [
createVNode("div", _hoisted_2$1, [
createVNode("div", _hoisted_3, toDisplayString(_ctx.i18nDate), 1 /* TEXT */),
(_ctx.validatedRange.length === 0)
? (openBlock(), createBlock("div", _hoisted_4, [
createVNode(_component_el_button_group, null, {
default: withCtx(() => [
createVNode(_component_el_button, {
size: "mini",
onClick: _cache[1] || (_cache[1] = $event => (_ctx.selectDate('prev-month')))
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.t('el.datepicker.prevMonth')), 1 /* TEXT */)
]),
_: 1 /* STABLE */
}),
createVNode(_component_el_button, {
size: "mini",
onClick: _cache[2] || (_cache[2] = $event => (_ctx.selectDate('today')))
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.t('el.datepicker.today')), 1 /* TEXT */)
]),
_: 1 /* STABLE */
}),
createVNode(_component_el_button, {
size: "mini",
onClick: _cache[3] || (_cache[3] = $event => (_ctx.selectDate('next-month')))
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.t('el.datepicker.nextMonth')), 1 /* TEXT */)
]),
_: 1 /* STABLE */
})
]),
_: 1 /* STABLE */
})
]))
: createCommentVNode("v-if", true)
]),
(_ctx.validatedRange.length === 0)
? (openBlock(), createBlock("div", _hoisted_5, [
createVNode(_component_date_table, {
date: _ctx.date,
"selected-day": _ctx.realSelectedDay,
onPick: _ctx.pickDay
}, createSlots({ _: 2 /* DYNAMIC */ }, [
(_ctx.$slots.dateCell)
? {
name: "dateCell",
fn: withCtx((data) => [
renderSlot(_ctx.$slots, "dateCell", data)
])
}
: undefined
]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["date", "selected-day", "onPick"])
]))
: (openBlock(), createBlock("div", _hoisted_6, [
(openBlock(true), createBlock(Fragment, null, renderList(_ctx.validatedRange, (range_, index) => {
return (openBlock(), createBlock(_component_date_table, {
key: index,
date: range_[0],
"selected-day": _ctx.realSelectedDay,
range: range_,
"hide-header": index !== 0,
onPick: _ctx.pickDay
}, createSlots({ _: 2 /* DYNAMIC */ }, [
(_ctx.$slots.dateCell)
? {
name: "dateCell",
fn: withCtx((data) => [
renderSlot(_ctx.$slots, "dateCell", data)
])
}
: undefined
]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["date", "selected-day", "range", "hide-header", "onPick"]))
}), 128 /* KEYED_FRAGMENT */))
]))
]))
}
script$1.render = render$1;
script$1.__file = "packages/calendar/src/index.vue";
script$1.install = (app) => {
app.component(script$1.name, script$1);
};
const _Calendar = script$1;
export default _Calendar;