import { ref, computed, defineComponent, createVNode as _createVNode } from "vue"; import { pick, addUnit, numericProp, setScrollTop, createNamespace, makeRequiredProp } from "../utils/index.mjs"; import { getMonthEndDay } from "../date-picker/utils.mjs"; import { t, bem, compareDay, getPrevDay, getNextDay, formatMonthTitle } from "./utils.mjs"; import { useRect, useToggle } from "@vant/use"; import { useExpose } from "../composables/use-expose.mjs"; import { useHeight } from "../composables/use-height.mjs"; import CalendarDay from "./CalendarDay.mjs"; const [name] = createNamespace("calendar-month"); const calendarMonthProps = { date: makeRequiredProp(Date), type: String, color: String, minDate: Date, maxDate: Date, showMark: Boolean, rowHeight: numericProp, formatter: Function, lazyRender: Boolean, currentDate: [Date, Array], allowSameDay: Boolean, showSubtitle: Boolean, showMonthTitle: Boolean, firstDayOfWeek: Number }; var stdin_default = defineComponent({ name, props: calendarMonthProps, emits: ["click", "clickDisabledDate"], setup(props, { emit, slots }) { const [visible, setVisible] = useToggle(); const daysRef = ref(); const monthRef = ref(); const height = useHeight(monthRef); const title = computed(() => formatMonthTitle(props.date)); const rowHeight = computed(() => addUnit(props.rowHeight)); const offset = computed(() => { const date = props.date.getDate(); const day = props.date.getDay(); const realDay = (day - date % 7 + 8) % 7; if (props.firstDayOfWeek) { return (realDay + 7 - props.firstDayOfWeek) % 7; } return realDay; }); const totalDay = computed(() => getMonthEndDay(props.date.getFullYear(), props.date.getMonth() + 1)); const shouldRender = computed(() => visible.value || !props.lazyRender); const getTitle = () => title.value; const getMultipleDayType = (day) => { const isSelected = (date) => props.currentDate.some((item) => compareDay(item, date) === 0); if (isSelected(day)) { const prevDay = getPrevDay(day); const nextDay = getNextDay(day); const prevSelected = isSelected(prevDay); const nextSelected = isSelected(nextDay); if (prevSelected && nextSelected) { return "multiple-middle"; } if (prevSelected) { return "end"; } if (nextSelected) { return "start"; } return "multiple-selected"; } return ""; }; const getRangeDayType = (day) => { const [startDay, endDay] = props.currentDate; if (!startDay) { return ""; } const compareToStart = compareDay(day, startDay); if (!endDay) { return compareToStart === 0 ? "start" : ""; } const compareToEnd = compareDay(day, endDay); if (props.allowSameDay && compareToStart === 0 && compareToEnd === 0) { return "start-end"; } if (compareToStart === 0) { return "start"; } if (compareToEnd === 0) { return "end"; } if (compareToStart > 0 && compareToEnd < 0) { return "middle"; } return ""; }; const getDayType = (day) => { const { type, minDate, maxDate, currentDate } = props; if (minDate && compareDay(day, minDate) < 0 || maxDate && compareDay(day, maxDate) > 0) { return "disabled"; } if (currentDate === null) { return ""; } if (Array.isArray(currentDate)) { if (type === "multiple") { return getMultipleDayType(day); } if (type === "range") { return getRangeDayType(day); } } else if (type === "single") { return compareDay(day, currentDate) === 0 ? "selected" : ""; } return ""; }; const getBottomInfo = (dayType) => { if (props.type === "range") { if (dayType === "start" || dayType === "end") { return t(dayType); } if (dayType === "start-end") { return `${t("start")}/${t("end")}`; } } }; const renderTitle = () => { if (props.showMonthTitle) { return _createVNode("div", { "class": bem("month-title") }, [slots["month-title"] ? slots["month-title"]({ date: props.date, text: title.value }) : title.value]); } }; const renderMark = () => { if (props.showMark && shouldRender.value) { return _createVNode("div", { "class": bem("month-mark") }, [props.date.getMonth() + 1]); } }; const placeholders = computed(() => { const count = Math.ceil((totalDay.value + offset.value) / 7); return Array(count).fill({ type: "placeholder" }); }); const days = computed(() => { const days2 = []; const year = props.date.getFullYear(); const month = props.date.getMonth(); for (let day = 1; day <= totalDay.value; day++) { const date = new Date(year, month, day); const type = getDayType(date); let config = { date, type, text: day, bottomInfo: getBottomInfo(type) }; if (props.formatter) { config = props.formatter(config); } days2.push(config); } return days2; }); const disabledDays = computed(() => days.value.filter((day) => day.type === "disabled")); const scrollToDate = (body, targetDate) => { if (daysRef.value) { const daysRect = useRect(daysRef.value); const totalRows = placeholders.value.length; const currentRow = Math.ceil((targetDate.getDate() + offset.value) / 7); const rowOffset = (currentRow - 1) * daysRect.height / totalRows; setScrollTop(body, daysRect.top + rowOffset + body.scrollTop - useRect(body).top); } }; const renderDay = (item, index) => _createVNode(CalendarDay, { "item": item, "index": index, "color": props.color, "offset": offset.value, "rowHeight": rowHeight.value, "onClick": (item2) => emit("click", item2), "onClickDisabledDate": (item2) => emit("clickDisabledDate", item2) }, pick(slots, ["top-info", "bottom-info", "text"])); const renderDays = () => _createVNode("div", { "ref": daysRef, "role": "grid", "class": bem("days") }, [renderMark(), (shouldRender.value ? days : placeholders).value.map(renderDay)]); useExpose({ getTitle, getHeight: () => height.value, setVisible, scrollToDate, disabledDays }); return () => _createVNode("div", { "class": bem("month"), "ref": monthRef }, [renderTitle(), renderDays()]); } }); export { stdin_default as default };