@opentiny/vue-renderless
Version:
An enterprise-class UI component library, support both Vue.js 2 and Vue.js 3, as well as PC and mobile.
510 lines (509 loc) • 19.4 kB
JavaScript
import "../chunk-G2ADBYYC.js";
import { lastMonth, nextMonth } from "@opentiny/utils";
import { getDirection } from "@opentiny/utils";
const normalConfig = (config, state) => {
let { disabled, holiday, workday, mark } = config || {};
const weekFirst = getWeekFirst(state, { config });
disabled = typeof disabled === "function" ? disabled : () => false;
holiday = typeof holiday === "function" ? holiday : () => true;
workday = typeof workday === "function" ? workday : () => true;
mark = typeof mark === "function" ? mark : () => "";
return { weekFirst, disabled, holiday, workday, mark };
};
const normalDate = (date) => {
date = !date ? /* @__PURE__ */ new Date() : !(date instanceof Date) ? new Date(date) : date;
date = date.toString() === "Invalid Date" ? /* @__PURE__ */ new Date() : date;
return date;
};
const splitDate = (date) => {
const today = /* @__PURE__ */ new Date();
const todayFullYear = today.getFullYear();
const todayMonth = today.getMonth() + 1;
const todayDate = today.getDate();
const currentFullYear = date.getFullYear();
const currentMonth = date.getMonth() + 1;
const currentDate = date.getDate();
return { todayFullYear, todayMonth, todayDate, currentFullYear, currentMonth, currentDate };
};
const getBuildDay = (args) => (year, month, date) => {
const { pad0: pad02, isCurrent, holiday, workday, mark, type } = args;
const { currentDate, isToday, disabled, dayOfWeek } = args;
const dateStr = `${year}-${pad02(month)}-${pad02(date)}`;
const d = new Date(dateStr);
const isCurMon = isCurrent(year, month);
const isSat = d.getDay() === dayOfWeek - 1;
const isSun = d.getDay() === 0;
let isWorkday, isHoliday;
if (isSat || isSun) {
isHoliday = holiday(d);
isWorkday = !isHoliday;
} else {
isWorkday = workday(d);
isHoliday = !isWorkday;
}
const markMsg = mark(d);
const marked = !!markMsg;
const day = { dateStr, marked, markMsg, isWorkday, isHoliday, isSat, isSun, isCurMon };
day.isCur = isCurMon && date === currentDate && type === "cur";
day.isToday = isToday(year, month, date);
day.disabled = disabled(d);
day.dateArr = [year, month, date];
day.type = type;
return day;
};
const getPadCalendarDays = ({ calendarDays, buildDay }) => (flag, count, cur) => {
const sign = flag === "s" ? -1 : 1;
Array.from({ length: count }).forEach((v, i) => {
const d = new Date(cur.getTime() + (i + 1) * sign * 864e5);
const year = d.getFullYear();
const month = d.getMonth() + 1;
const date = d.getDate();
calendarDays[flag === "s" ? "unshift" : "push"](buildDay(year, month, date));
});
};
const equalArr = (arr1, arr2) => Array.isArray(arr1) && Array.isArray(arr2) && arr1.join(",") === arr2.join(",");
const setDayRow = ({ calendarDays, state }) => calendarDays.forEach((day, i) => {
day.row = Math.floor(i / state.dayOfWeek);
if (day.isCur) {
state.activeRow = day.row;
state.activeDate = day.dateStr;
}
});
const pad0 = (str, n = 2) => String(str).padStart(n, "0");
const getDate = (state, type, date) => {
let resDate = /* @__PURE__ */ new Date();
if (type === "last") {
const { year, month } = lastMonth(state.currentYear, state.currentMonth);
resDate = /* @__PURE__ */ new Date(`${year}-${month}-01`);
} else if (type === "next") {
const { year, month } = nextMonth(state.currentYear, state.currentMonth);
resDate = /* @__PURE__ */ new Date(`${year}-${month}-01`);
} else {
resDate = normalDate(date);
}
return resDate;
};
const getCalendarDays = (state) => (date, config, type = "cur") => {
date = getDate(state, type, date);
let { weekFirst, disabled, holiday, workday, mark } = normalConfig(config, state);
const { todayFullYear, todayMonth, todayDate, currentFullYear, currentMonth, currentDate } = splitDate(date);
const isToday = (year, month, date2) => year === todayFullYear && month === todayMonth && date2 === todayDate;
const isCurrent = (year, month) => year === currentFullYear && month === currentMonth;
const february = currentFullYear % 4 === 0 && currentFullYear % 100 !== 0 || currentFullYear % 400 === 0 ? 29 : 28;
const monthDays = [-1, 31, february, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const f = (arr) => arr[0];
const l = (arr) => arr[arr.length - 1];
const { dayOfWeek } = state;
const args = { pad0, isCurrent, currentFullYear, currentMonth, holiday, workday, mark, type };
Object.assign(args, { currentDate, isToday, disabled, dayOfWeek });
const buildDay = getBuildDay(args);
const calendarDays = Array.from({ length: monthDays[currentMonth] }).map(
(v, i) => buildDay(currentFullYear, currentMonth, i + 1)
);
const weekDays = Array.from({ length: dayOfWeek }).map((v, i) => (weekFirst + i) % dayOfWeek);
const monthDaysFirst = new Date(f(calendarDays).dateStr).getDay();
const monthDaysLast = new Date(l(calendarDays).dateStr).getDay();
const padCalendarDays = getPadCalendarDays({ calendarDays, buildDay });
let count = monthDaysFirst !== f(weekDays) ? weekDays.indexOf(monthDaysFirst) : dayOfWeek;
padCalendarDays("s", count, new Date(f(calendarDays).dateStr));
count = monthDaysLast !== l(weekDays) ? dayOfWeek - 1 - weekDays.indexOf(monthDaysLast) : dayOfWeek;
padCalendarDays("e", count, new Date(l(calendarDays).dateStr));
setCalendarDays(state, type, calendarDays);
if (type !== "cur")
return;
setDayRow({ calendarDays, state });
if (!equalArr(state.weekDays, weekDays)) {
state.weekDays = weekDays;
}
state.currentYear = currentFullYear;
state.currentMonth = currentMonth;
state.currentDate = currentDate;
state.cascaderCurrent = [currentFullYear, currentMonth];
};
const setCalendarDays = (state, type, calendarDays) => {
if (type === "last") {
state.lastCalendarDays = calendarDays;
} else if (type === "next") {
state.nextCalendarDays = calendarDays;
} else {
state.calendarDays = calendarDays;
}
};
const getPrevWeek = ({ props, emit, state, api }) => () => {
let newPrevDate = new Date(state.weekDates[0].dateStr);
newPrevDate.setDate(newPrevDate.getDate() - 7);
state.weekDates = api.getAllDatesOfCurrWeek(new Date(newPrevDate));
setActiveDate(state, props, emit);
};
const getNextWeek = ({ props, emit, state, api }) => () => {
let newNextDate = new Date(state.weekDates[6].dateStr);
newNextDate.setDate(newNextDate.getDate() + 7);
state.weekDates = api.getAllDatesOfCurrWeek(new Date(newNextDate));
setActiveDate(state, props, emit);
};
const setActiveDate = (state, props, emit) => {
state.weekDates.forEach((day2) => day2.isCur = false);
const day = new Date(props.modelValue).getDay();
const dayIdx = state.weekDays.indexOf(day);
const curDate = state.weekDates[dayIdx];
curDate.isCur = true;
emit("update:modelValue", curDate.dateStr);
state.activeDate = curDate.dateStr;
state.currentDate = curDate.dateArr[2];
state.activeRow = curDate.row;
};
const getAllDatesOfCurrWeek = ({ state, props }) => (date) => {
const weekFirst = getWeekFirst(state, props);
const weekDates = [];
let weekDate = new Date(date);
const calDate = weekDate.getDate() - weekDate.getDay() + weekFirst;
const weekFirstDate = calDate > weekDate.getDate() ? calDate - 7 : calDate;
weekDate.setDate(weekFirstDate);
const threeMonthDays = [...state.calendarDays, ...state.lastCalendarDays, ...state.nextCalendarDays];
const len = threeMonthDays.length;
for (let i = 0; i < 7; i++) {
const date2 = formatDate(new Date(weekDate));
let findDate = false;
for (let j = 0; j < len; j++) {
if (threeMonthDays[j].dateStr === date2) {
threeMonthDays[j].type = "cur";
weekDates.push(threeMonthDays[j]);
findDate = true;
break;
}
}
if (!findDate) {
const newDate = new Date(weekDate);
weekDates.push({ dateStr: date2, dateArr: [newDate.getFullYear(), newDate.getMonth() + 1, newDate.getDate()] });
}
weekDate.setDate(weekDate.getDate() + 1);
}
return weekDates;
};
const getWeekOfDate = ({ api }) => (type, date) => {
const aWeekTimestamp = 7 * 24 * 60 * 60 * 1e3;
let nextDate = +new Date(date);
if (type === "prev") {
nextDate = +new Date(date) - aWeekTimestamp;
} else {
nextDate = +new Date(date) + aWeekTimestamp;
}
return api.getAllDatesOfCurrWeek(new Date(nextDate));
};
const showWeekChange = ({ state }) => (value) => {
if (value) {
getWeekDatesByActiveRow(state);
} else {
state.calendarDays.forEach((date) => {
if (state.activeDate === date.dateStr) {
date.isCur = true;
} else {
date.isCur = false;
}
});
}
};
const formatDate = (date) => {
const newDate = new Date(date);
return newDate.getFullYear() + "-" + pad0(newDate.getMonth() + 1) + "-" + pad0(newDate.getDate());
};
const getWeekDatesByActiveRow = (state) => {
state.weekDates = state.calendarDays.filter((day) => day.row === state.activeRow);
if (!state.weekDates.length) {
state.activeRow = 0;
state.weekDates = state.calendarDays.filter((day) => day.row === state.activeRow);
}
};
const computedCurrentRow = (state) => () => {
const { calendarDays } = state;
if (Array.isArray(calendarDays) && calendarDays.length) {
const currentDay = calendarDays.find((day) => day.isCur);
if (currentDay) {
return currentDay.row;
}
}
return null;
};
const computedData = (state) => () => {
if (state.showWeek) {
return [state.prevWeekDates, state.weekDates, state.nextWeekDates];
} else {
return [state.lastCalendarDays, state.calendarDays, state.nextCalendarDays];
}
};
const computedFilteredCalendarDays = (state) => () => {
const { calendarDays, currentRow, visibleRows } = state;
if (Array.isArray(calendarDays) && calendarDays.length && currentRow !== null) {
const rows = [...visibleRows, currentRow];
return calendarDays.filter((day) => ~rows.indexOf(day.row));
}
return [];
};
const handleDraggerClick = (state, emit) => () => {
if (state.dragging)
return;
state.showWeek = !state.showWeek;
emit("expand", !state.showWeek);
};
const handleClickDay = ({ api, emit, props, state }) => (day) => {
if (day.isCur || day.disabled)
return;
if (typeof day.dateStr === "string") {
const isCurrent = day.dateArr[0] === +state.currentYear && day.dateArr[1] === +state.currentMonth;
if (!isCurrent) {
api.getCalendarDays(day.dateStr, props.config, "cur");
api.getCalendarDays(day.dateStr, props.config, "last");
api.getCalendarDays(day.dateStr, props.config, "next");
}
const showCalendarDays = [...state.calendarDays, ...state.weekDates];
state.activeRow = day.row;
showCalendarDays.forEach((date) => {
if (day.dateStr === date.dateStr) {
date.isCur = true;
state.activeRow = date.row;
} else {
date.isCur = false;
}
});
state.activeDate = day.dateStr;
state.currentDate = day.dateArr[2];
emit("update:modelValue", day.dateStr);
}
};
const calcCalendarItemHeight = ({ state, vm }) => () => {
const calendarPanel = vm.$refs.calendarPanel;
if (calendarPanel && calendarPanel.childNodes instanceof NodeList && calendarPanel.childNodes.length > 1) {
setTimeout(() => {
state.itemHeight = calendarPanel.childNodes[1].offsetHeight;
});
}
};
const computedTotalRows = (state) => () => {
const len = state.dragging ? state.calendarDaysCopy.length : calendarDays.length;
const { calendarDays, dayOfWeek } = state;
const total = Math.floor(len / dayOfWeek);
return total;
};
const dragStart = ({ state, clientX, clientY, vm }) => {
state.showRows = 0;
state.calendarDaysCopy = state.calendarDays.slice(0);
state.calendarPanelHeight = vm.$refs.calendarPanel.offsetHeight;
state.dragPosStart = state.dragPos = { clientX, clientY };
};
const dragEnd = ({ state, vm, clientY, emit }) => {
const dy = clientY - state.dragPosStart.clientY;
if (dy === 0)
return;
state.dragPosStart = state.dragPos = {};
if (state.showWeek) {
if (state.showRows >= 2) {
state.showWeek = false;
}
} else {
if (state.showRows <= 5) {
state.showWeek = true;
}
}
emit("expand", !state.showWeek);
state.weekDates = state.copyWeekDates;
state.calendarDays = state.calendarDaysCopy;
vm.$refs.calendarPanel.style.height = "auto";
state.showRows = 0;
};
const dragMove = ({ state, vm, clientX, clientY }) => {
const { dragPos: lastPos, itemHeight } = state;
const totalRows = 6;
if (lastPos.clientY === void 0 || lastPos.clientX === void 0) {
state.dragging = false;
return;
}
const minH = itemHeight;
const maxH = itemHeight * totalRows;
state.dragPos = { clientX, clientY };
state.calendarPanelHeight += clientY - lastPos.clientY;
let h = state.calendarPanelHeight;
h = h < minH ? minH : h > maxH ? maxH : h;
state.showRows = Math.floor(h / itemHeight);
vm.$refs.calendarPanel.style.height = `${h}px`;
if (state.showWeek) {
if (state.showRows === 1) {
state.weekDates = [...state.copyWeekDates];
}
if (state.showRows === 2) {
state.weekDates = [...state.prevWeekDates, ...state.copyWeekDates];
}
if (state.showRows === 3) {
state.weekDates = [...state.prevWeekDates, ...state.copyWeekDates, ...state.nextWeekDates];
}
} else {
getShowedCalendarDays(state);
}
};
const getShowedCalendarDays = (state) => {
if (state.showRows === 0)
return;
state.calendarDays = state.calendarDaysCopy.slice(0, state.showRows * 7);
};
const handleDraggerMousedown = ({ api, state, vm }) => (e) => {
const { clientX, clientY } = e;
dragStart({ state, vm, clientX, clientY });
document.addEventListener("mouseup", api.handleMouseup);
document.addEventListener("mousemove", api.throttledHandleMousemove);
};
const handleMouseup = ({ api, state, vm, emit }) => (e) => {
setTimeout(() => state.dragging = false);
document.removeEventListener("mouseup", api.handleMouseup);
document.removeEventListener("mousemove", api.throttledHandleMousemove);
dragEnd({ state, vm, clientY: e.clientY, emit });
};
const handleMousemove = ({ state, vm }) => (e) => {
state.dragging = true;
const { clientX, clientY } = e;
dragMove({ state, vm, clientX, clientY });
};
const handleDraggerTouchstart = ({ state, vm }) => (e) => {
const { clientX, clientY } = e.changedTouches[0];
state.touching = true;
dragStart({ state, vm, clientX, clientY });
};
const handleDraggerTouchend = ({ state, vm, emit }) => (e) => {
const { clientY } = e.changedTouches[0];
state.touching = false;
dragEnd({ state, vm, clientY, emit });
};
const handleDraggerTouchmove = ({ state, vm }) => (e) => {
const { clientX, clientY } = e.changedTouches[0];
dragMove({ state, vm, clientX, clientY });
};
const setCascaderVisible = (state) => (value) => state.cascaderVisible = !!value;
const handleCascaderChange = ({ api, emit, props, state }) => (val) => {
const dateStr = getDateStr(state, val[0], val[1]);
api.getCalendarDays(dateStr, props.config, "cur");
api.getCalendarDays(dateStr, props.config, "last");
api.getCalendarDays(dateStr, props.config, "next");
emit("update:modelValue", dateStr);
getWeekDatesByActiveRow(state);
};
const computeCascaderOptions = (t) => () => [
{
range: [2e3, 2050],
optionMethod: (i) => ({ id: i, label: t("ui.calendarBar.year").replace("%s", String(i)) })
},
{ range: [1, 12], optionMethod: (i) => ({ id: i, label: t(`ui.calendarBar.month.${i}`) }) }
];
const i18nYearMonth = ({ state, t }) => () => {
const { currentYear, currentMonth } = state;
let template = t("ui.calendarBar.yearMonth");
const monthAbbr = t(`ui.calendarBar.monthAbbr.${currentMonth}`);
template = template.replace("%y", currentYear);
template = template.replace("%m", monthAbbr);
return template;
};
const touchmove = ({ state }) => (event) => {
const touch = event.touches[0];
state.deltaPos.Y = touch.clientY - state.startPos.Y;
state.deltaPos.X = touch.clientX - state.startPos.X;
state.offsetPos.Y = Math.abs(state.deltaPos.Y);
state.offsetPos.X = Math.abs(state.deltaPos.X);
state.direction = getDirection(state.offsetPos.X, state.offsetPos.Y);
if (state.direction === "vertical")
return;
state.delta = state.deltaPos.X;
};
const touchstart = ({ state }) => (event) => {
event.stopPropagation();
resetTouchStatus(state);
state.duration = 300;
state.moving = true;
state.touchTime = Date.now();
state.startPos.X = event.touches[0].clientX;
state.startPos.Y = event.touches[0].clientY;
};
const touchend = ({ state, api, vm }) => () => {
const weekPanel = vm.$refs.weekPanel;
const width = weekPanel && weekPanel.offsetWidth;
const speed = state.delta / (Date.now() - state.touchTime);
const isShouldMove = Math.abs(speed) > 0.3 || Math.abs(state.delta) > +(width / 3).toFixed(2);
if (isShouldMove) {
const delta = state.delta;
state.duration = 300;
state.delta = delta > 0 ? width : -width;
setTimeout(() => {
if (state.showWeek) {
delta > 0 ? api.getPrevWeek() : api.getNextWeek();
if (state.weekDates[3].dateArr[0] !== +state.currentYear || state.weekDates[3].dateArr[1] !== +state.currentMonth) {
api.updateCalendarDays(delta);
}
} else {
api.updateCalendarDays(delta);
}
state.duration = 0;
state.delta = 0;
}, 300);
} else {
state.delta = 0;
}
state.moving = false;
};
const updateCalendarDays = ({ props, state, api, emit }) => (delta) => {
let { year, month } = delta > 0 ? lastMonth(state.currentYear, state.currentMonth) : nextMonth(state.currentYear, state.currentMonth);
const dateStr = getDateStr(state, year, month);
api.getCalendarDays(dateStr, props.config, "cur");
api.getCalendarDays(dateStr, props.config, "last");
api.getCalendarDays(dateStr, props.config, "next");
!state.showWeek && emit("update:modelValue", dateStr);
};
function getDateStr(state, year, month) {
const { currentDate } = state;
let dateStr = `${year}-${pad0(month)}-${pad0(currentDate)}`;
const numberCurrentDate = Number(currentDate);
const { currentFullYear: curYear, currentMonth: curMonth, currentDate: curDate } = splitDate(new Date(dateStr));
if (curYear !== year || curMonth !== month || curDate !== numberCurrentDate) {
dateStr = `${year}-${pad0(month)}-01`;
}
return dateStr;
}
function getWeekFirst(state, props) {
let weekFirst = props.config.weekFirst || 0;
const minWeekFirst = 0;
const maxWeekFirst = state.dayOfWeek - 1;
weekFirst = typeof weekFirst === "number" && weekFirst >= minWeekFirst && weekFirst <= maxWeekFirst ? Math.round(weekFirst) : minWeekFirst;
return weekFirst;
}
function resetTouchStatus(state) {
state.direction = "";
state.delta = 0;
state.deltaPos.X = 0;
state.deltaPos.Y = 0;
state.offsetPos.X = 0;
state.offsetPos.Y = 0;
}
export {
calcCalendarItemHeight,
computeCascaderOptions,
computedCurrentRow,
computedData,
computedFilteredCalendarDays,
computedTotalRows,
getAllDatesOfCurrWeek,
getCalendarDays,
getNextWeek,
getPrevWeek,
getWeekOfDate,
handleCascaderChange,
handleClickDay,
handleDraggerClick,
handleDraggerMousedown,
handleDraggerTouchend,
handleDraggerTouchmove,
handleDraggerTouchstart,
handleMousemove,
handleMouseup,
i18nYearMonth,
setCascaderVisible,
showWeekChange,
touchend,
touchmove,
touchstart,
updateCalendarDays
};