UNPKG

naive-ui

Version:

A Vue 3 Component Library. Fairly Complete, Theme Customizable, Uses TypeScript, Fast

701 lines 26 kB
import { addMonths, format, getDate, getMonth, getTime, getYear, isValid, set, startOfDay, startOfMonth, startOfQuarter, startOfSecond } from 'date-fns'; import { computed, inject, ref, watch } from 'vue'; import { MONTH_ITEM_HEIGHT } from "../config.mjs"; import { datePickerInjectionKey } from "../interface.mjs"; import { dateArray, getDefaultTime, monthArray, pluckValueFromRange, quarterArray, strictParse, yearArray } from "../utils.mjs"; import { usePanelCommon, usePanelCommonProps } from "./use-panel-common.mjs"; const useDualCalendarProps = Object.assign(Object.assign({}, usePanelCommonProps), { defaultCalendarStartTime: Number, defaultCalendarEndTime: Number, bindCalendarMonths: Boolean, actions: { type: Array, default: () => ['clear', 'confirm'] } }); function useDualCalendar(props, type) { var _a, _b; const { isDateDisabledRef, isStartHourDisabledRef, isEndHourDisabledRef, isStartMinuteDisabledRef, isEndMinuteDisabledRef, isStartSecondDisabledRef, isEndSecondDisabledRef, isStartDateInvalidRef, isEndDateInvalidRef, isStartTimeInvalidRef, isEndTimeInvalidRef, isStartValueInvalidRef, isEndValueInvalidRef, isRangeInvalidRef, localeRef, rangesRef, closeOnSelectRef, updateValueOnCloseRef, firstDayOfWeekRef, datePickerSlots, monthFormatRef, yearFormatRef, quarterFormatRef, yearRangeRef } = inject(datePickerInjectionKey); const validation = { isDateDisabled: isDateDisabledRef, isStartHourDisabled: isStartHourDisabledRef, isEndHourDisabled: isEndHourDisabledRef, isStartMinuteDisabled: isStartMinuteDisabledRef, isEndMinuteDisabled: isEndMinuteDisabledRef, isStartSecondDisabled: isStartSecondDisabledRef, isEndSecondDisabled: isEndSecondDisabledRef, isStartDateInvalid: isStartDateInvalidRef, isEndDateInvalid: isEndDateInvalidRef, isStartTimeInvalid: isStartTimeInvalidRef, isEndTimeInvalid: isEndTimeInvalidRef, isStartValueInvalid: isStartValueInvalidRef, isEndValueInvalid: isEndValueInvalidRef, isRangeInvalid: isRangeInvalidRef }; const panelCommon = usePanelCommon(props); const startDatesElRef = ref(null); const endDatesElRef = ref(null); const startYearScrollbarRef = ref(null); const endYearScrollbarRef = ref(null); const startYearVlRef = ref(null); const endYearVlRef = ref(null); const startMonthScrollbarRef = ref(null); const endMonthScrollbarRef = ref(null); const { value } = props; const defaultCalendarStartTime = (_a = props.defaultCalendarStartTime) !== null && _a !== void 0 ? _a : Array.isArray(value) && typeof value[0] === 'number' ? value[0] : Date.now(); const startCalendarDateTimeRef = ref(defaultCalendarStartTime); const endCalendarDateTimeRef = ref((_b = props.defaultCalendarEndTime) !== null && _b !== void 0 ? _b : Array.isArray(value) && typeof value[1] === 'number' ? value[1] : getTime(addMonths(defaultCalendarStartTime, 1))); adjustCalendarTimes(true); const nowRef = ref(Date.now()); const isSelectingRef = ref(false); const memorizedStartDateTimeRef = ref(0); const mergedDateFormatRef = computed(() => props.dateFormat || localeRef.value.dateFormat); const mergedDayFormatRef = computed(() => props.calendarDayFormat || localeRef.value.dayFormat); const startDateInput = ref(Array.isArray(value) ? format(value[0], mergedDateFormatRef.value, panelCommon.dateFnsOptions.value) : ''); const endDateInputRef = ref(Array.isArray(value) ? format(value[1], mergedDateFormatRef.value, panelCommon.dateFnsOptions.value) : ''); // derived computed const selectingPhaseRef = computed(() => { if (isSelectingRef.value) return 'end';else return 'start'; }); const startDateArrayRef = computed(() => { var _a; return dateArray(startCalendarDateTimeRef.value, props.value, nowRef.value, (_a = firstDayOfWeekRef.value) !== null && _a !== void 0 ? _a : localeRef.value.firstDayOfWeek); }); const endDateArrayRef = computed(() => { var _a; return dateArray(endCalendarDateTimeRef.value, props.value, nowRef.value, (_a = firstDayOfWeekRef.value) !== null && _a !== void 0 ? _a : localeRef.value.firstDayOfWeek); }); const weekdaysRef = computed(() => { return startDateArrayRef.value.slice(0, 7).map(dateItem => { const { ts } = dateItem; return format(ts, mergedDayFormatRef.value, panelCommon.dateFnsOptions.value); }); }); const startCalendarMonthRef = computed(() => { return format(startCalendarDateTimeRef.value, props.calendarHeaderMonthFormat || localeRef.value.monthFormat, panelCommon.dateFnsOptions.value); }); const endCalendarMonthRef = computed(() => { return format(endCalendarDateTimeRef.value, props.calendarHeaderMonthFormat || localeRef.value.monthFormat, panelCommon.dateFnsOptions.value); }); const startCalendarYearRef = computed(() => { return format(startCalendarDateTimeRef.value, props.calendarHeaderYearFormat || localeRef.value.yearFormat, panelCommon.dateFnsOptions.value); }); const endCalendarYearRef = computed(() => { return format(endCalendarDateTimeRef.value, props.calendarHeaderYearFormat || localeRef.value.yearFormat, panelCommon.dateFnsOptions.value); }); const startTimeValueRef = computed(() => { const { value } = props; if (Array.isArray(value)) return value[0]; return null; }); const endTimeValueRef = computed(() => { const { value } = props; if (Array.isArray(value)) return value[1]; return null; }); const shortcutsRef = computed(() => { const { shortcuts } = props; return shortcuts || rangesRef.value; }); const startYearArrayRef = computed(() => { return yearArray(pluckValueFromRange(props.value, 'start'), nowRef.value, { yearFormat: yearFormatRef.value }, yearRangeRef); }); const endYearArrayRef = computed(() => { return yearArray(pluckValueFromRange(props.value, 'end'), nowRef.value, { yearFormat: yearFormatRef.value }, yearRangeRef); }); const startQuarterArrayRef = computed(() => { const startValue = pluckValueFromRange(props.value, 'start'); return quarterArray(startValue !== null && startValue !== void 0 ? startValue : Date.now(), startValue, nowRef.value, { quarterFormat: quarterFormatRef.value }); }); const endQuarterArrayRef = computed(() => { const endValue = pluckValueFromRange(props.value, 'end'); return quarterArray(endValue !== null && endValue !== void 0 ? endValue : Date.now(), endValue, nowRef.value, { quarterFormat: quarterFormatRef.value }); }); const startMonthArrayRef = computed(() => { const startValue = pluckValueFromRange(props.value, 'start'); return monthArray(startValue !== null && startValue !== void 0 ? startValue : Date.now(), startValue, nowRef.value, { monthFormat: monthFormatRef.value }); }); const endMonthArrayRef = computed(() => { const endValue = pluckValueFromRange(props.value, 'end'); return monthArray(endValue !== null && endValue !== void 0 ? endValue : Date.now(), endValue, nowRef.value, { monthFormat: monthFormatRef.value }); }); const calendarMonthBeforeYearRef = computed(() => { var _a; return (_a = props.calendarHeaderMonthBeforeYear) !== null && _a !== void 0 ? _a : localeRef.value.monthBeforeYear; }); watch(computed(() => props.value), value => { if (value !== null && Array.isArray(value)) { const [startMoment, endMoment] = value; startDateInput.value = format(startMoment, mergedDateFormatRef.value, panelCommon.dateFnsOptions.value); endDateInputRef.value = format(endMoment, mergedDateFormatRef.value, panelCommon.dateFnsOptions.value); if (!isSelectingRef.value) { syncCalendarTimeWithValue(value); } } else { startDateInput.value = ''; endDateInputRef.value = ''; } }); function handleCalendarChange(value, oldValue) { if (type === 'daterange' || type === 'datetimerange') { if (getYear(value) !== getYear(oldValue) || getMonth(value) !== getMonth(oldValue)) { panelCommon.disableTransitionOneTick(); } } } watch(startCalendarDateTimeRef, handleCalendarChange); watch(endCalendarDateTimeRef, handleCalendarChange); // change calendar function adjustCalendarTimes(byStartCalendarTime) { const startTime = startOfMonth(startCalendarDateTimeRef.value); const endTime = startOfMonth(endCalendarDateTimeRef.value); if (props.bindCalendarMonths || startTime >= endTime) { if (byStartCalendarTime) { endCalendarDateTimeRef.value = getTime(addMonths(startTime, 1)); } else { startCalendarDateTimeRef.value = getTime(addMonths(endTime, -1)); } } } function startCalendarNextYear() { startCalendarDateTimeRef.value = getTime(addMonths(startCalendarDateTimeRef.value, 12)); adjustCalendarTimes(true); } function startCalendarPrevYear() { startCalendarDateTimeRef.value = getTime(addMonths(startCalendarDateTimeRef.value, -12)); adjustCalendarTimes(true); } function startCalendarNextMonth() { startCalendarDateTimeRef.value = getTime(addMonths(startCalendarDateTimeRef.value, 1)); adjustCalendarTimes(true); } function startCalendarPrevMonth() { startCalendarDateTimeRef.value = getTime(addMonths(startCalendarDateTimeRef.value, -1)); adjustCalendarTimes(true); } function endCalendarNextYear() { endCalendarDateTimeRef.value = getTime(addMonths(endCalendarDateTimeRef.value, 12)); adjustCalendarTimes(false); } function endCalendarPrevYear() { endCalendarDateTimeRef.value = getTime(addMonths(endCalendarDateTimeRef.value, -12)); adjustCalendarTimes(false); } function endCalendarNextMonth() { endCalendarDateTimeRef.value = getTime(addMonths(endCalendarDateTimeRef.value, 1)); adjustCalendarTimes(false); } function endCalendarPrevMonth() { endCalendarDateTimeRef.value = getTime(addMonths(endCalendarDateTimeRef.value, -1)); adjustCalendarTimes(false); } function onUpdateStartCalendarValue(value) { startCalendarDateTimeRef.value = value; adjustCalendarTimes(true); } function onUpdateEndCalendarValue(value) { endCalendarDateTimeRef.value = value; adjustCalendarTimes(false); } // The function is used on date panel, not the date-picker value validation function mergedIsDateDisabled(ts) { const isDateDisabled = isDateDisabledRef.value; if (!isDateDisabled) return false; if (!Array.isArray(props.value)) { return isDateDisabled(ts, 'start', null); } if (selectingPhaseRef.value === 'start') { // before you really start to select return isDateDisabled(ts, 'start', null); } else { const { value: memorizedStartDateTime } = memorizedStartDateTimeRef; // after you starting to select if (ts < memorizedStartDateTimeRef.value) { return isDateDisabled(ts, 'start', [memorizedStartDateTime, memorizedStartDateTime]); } else { return isDateDisabled(ts, 'end', [memorizedStartDateTime, memorizedStartDateTime]); } } } function syncCalendarTimeWithValue(value) { if (value === null) return; const [startMoment, endMoment] = value; startCalendarDateTimeRef.value = startMoment; if (startOfMonth(endMoment) <= startOfMonth(startMoment)) { endCalendarDateTimeRef.value = getTime(startOfMonth(addMonths(startMoment, 1))); } else { endCalendarDateTimeRef.value = getTime(startOfMonth(endMoment)); } } // for daterange & datetimerange function handleDateClick(dateItem) { if (!isSelectingRef.value) { isSelectingRef.value = true; memorizedStartDateTimeRef.value = dateItem.ts; changeStartEndTime(dateItem.ts, dateItem.ts, 'done'); } else { isSelectingRef.value = false; const { value } = props; if (props.panel && Array.isArray(value)) { changeStartEndTime(value[0], value[1], 'done'); } else { if (closeOnSelectRef.value && type === 'daterange') { if (updateValueOnCloseRef.value) { closeCalendar(); } else { handleConfirmClick(); } } } } } function handleDateMouseEnter(dateItem) { if (isSelectingRef.value) { if (mergedIsDateDisabled(dateItem.ts)) return; if (dateItem.ts >= memorizedStartDateTimeRef.value) { changeStartEndTime(memorizedStartDateTimeRef.value, dateItem.ts, 'wipPreview'); } else { changeStartEndTime(dateItem.ts, memorizedStartDateTimeRef.value, 'wipPreview'); } } } function handleConfirmClick() { if (isRangeInvalidRef.value) { return; } panelCommon.doConfirm(); closeCalendar(); } function closeCalendar() { isSelectingRef.value = false; if (props.active) { panelCommon.doClose(); } } function changeStartDateTime(time) { if (typeof time !== 'number') { time = getTime(time); } if (props.value === null) { panelCommon.doUpdateValue([time, time], props.panel); } else if (Array.isArray(props.value)) { panelCommon.doUpdateValue([time, Math.max(props.value[1], time)], props.panel); } } function changeEndDateTime(time) { if (typeof time !== 'number') { time = getTime(time); } if (props.value === null) { panelCommon.doUpdateValue([time, time], props.panel); } else if (Array.isArray(props.value)) { panelCommon.doUpdateValue([Math.min(props.value[0], time), time], props.panel); } } function changeStartEndTime(startTime, endTime, source) { if (typeof startTime !== 'number') { startTime = getTime(startTime); } if (source !== 'shortcutPreview' && source !== 'shortcutDone') { let startDefaultTime; let endDefaultTime; if (type === 'datetimerange') { const { defaultTime } = props; if (Array.isArray(defaultTime)) { startDefaultTime = getDefaultTime(defaultTime[0]); endDefaultTime = getDefaultTime(defaultTime[1]); } else { startDefaultTime = getDefaultTime(defaultTime); endDefaultTime = startDefaultTime; } } if (startDefaultTime) { startTime = getTime(set(startTime, startDefaultTime)); } if (endDefaultTime) { endTime = getTime(set(endTime, endDefaultTime)); } } panelCommon.doUpdateValue([startTime, endTime], props.panel && (source === 'done' || source === 'shortcutDone')); } function sanitizeValue(datetime) { if (type === 'datetimerange') { return getTime(startOfSecond(datetime)); } else if (type === 'monthrange') { return getTime(startOfMonth(datetime)); } else { // daterange return getTime(startOfDay(datetime)); } } function handleStartDateInput(value) { const date = strictParse(value, mergedDateFormatRef.value, new Date(), panelCommon.dateFnsOptions.value); if (isValid(date)) { if (!props.value) { const newValue = set(new Date(), { year: getYear(date), month: getMonth(date), date: getDate(date) }); changeStartDateTime(sanitizeValue(getTime(newValue))); } else if (Array.isArray(props.value)) { const newValue = set(props.value[0], { year: getYear(date), month: getMonth(date), date: getDate(date) }); changeStartDateTime(sanitizeValue(getTime(newValue))); } } else { startDateInput.value = value; } } function handleEndDateInput(value) { /** strict check when input */ const date = strictParse(value, mergedDateFormatRef.value, new Date(), panelCommon.dateFnsOptions.value); if (isValid(date)) { if (props.value === null) { const newValue = set(new Date(), { year: getYear(date), month: getMonth(date), date: getDate(date) }); changeEndDateTime(sanitizeValue(getTime(newValue))); } else if (Array.isArray(props.value)) { const newValue = set(props.value[1], { year: getYear(date), month: getMonth(date), date: getDate(date) }); changeEndDateTime(sanitizeValue(getTime(newValue))); } } else { endDateInputRef.value = value; } } function handleStartDateInputBlur() { const date = strictParse(startDateInput.value, mergedDateFormatRef.value, new Date(), panelCommon.dateFnsOptions.value); const { value } = props; if (isValid(date)) { if (value === null) { const newValue = set(new Date(), { year: getYear(date), month: getMonth(date), date: getDate(date) }); changeStartDateTime(sanitizeValue(getTime(newValue))); } else if (Array.isArray(value)) { const newValue = set(value[0], { year: getYear(date), month: getMonth(date), date: getDate(date) }); changeStartDateTime(sanitizeValue(getTime(newValue))); } } else { refreshDisplayDateString(); } } function handleEndDateInputBlur() { const date = strictParse(endDateInputRef.value, mergedDateFormatRef.value, new Date(), panelCommon.dateFnsOptions.value); const { value } = props; if (isValid(date)) { if (value === null) { const newValue = set(new Date(), { year: getYear(date), month: getMonth(date), date: getDate(date) }); changeEndDateTime(sanitizeValue(getTime(newValue))); } else if (Array.isArray(value)) { const newValue = set(value[1], { year: getYear(date), month: getMonth(date), date: getDate(date) }); changeEndDateTime(sanitizeValue(getTime(newValue))); } } else { refreshDisplayDateString(); } } function refreshDisplayDateString(times) { // If not selected, display nothing, // else update datetime related string const { value } = props; if (value === null || !Array.isArray(value)) { startDateInput.value = ''; endDateInputRef.value = ''; return; } if (times === undefined) { times = value; } startDateInput.value = format(times[0], mergedDateFormatRef.value, panelCommon.dateFnsOptions.value); endDateInputRef.value = format(times[1], mergedDateFormatRef.value, panelCommon.dateFnsOptions.value); } function handleStartTimePickerChange(value) { if (value === null) return; changeStartDateTime(value); } function handleEndTimePickerChange(value) { if (value === null) return; changeEndDateTime(value); } function handleRangeShortcutMouseenter(shortcut) { panelCommon.cachePendingValue(); const shortcutValue = panelCommon.getShortcutValue(shortcut); if (!Array.isArray(shortcutValue)) return; changeStartEndTime(shortcutValue[0], shortcutValue[1], 'shortcutPreview'); } function handleRangeShortcutClick(shortcut) { const shortcutValue = panelCommon.getShortcutValue(shortcut); if (!Array.isArray(shortcutValue)) return; changeStartEndTime(shortcutValue[0], shortcutValue[1], 'shortcutDone'); panelCommon.clearPendingValue(); handleConfirmClick(); } function justifyColumnsScrollState(value, type) { const mergedValue = value === undefined ? props.value : value; if (value === undefined || type === 'start') { if (startMonthScrollbarRef.value) { const monthIndex = !Array.isArray(mergedValue) ? getMonth(Date.now()) : getMonth(mergedValue[0]); startMonthScrollbarRef.value.scrollTo({ debounce: false, index: monthIndex, elSize: MONTH_ITEM_HEIGHT }); } if (startYearVlRef.value) { const yearIndex = (!Array.isArray(mergedValue) ? getYear(Date.now()) : getYear(mergedValue[0])) - yearRangeRef.value[0]; startYearVlRef.value.scrollTo({ index: yearIndex, debounce: false }); } } if (value === undefined || type === 'end') { if (endMonthScrollbarRef.value) { const monthIndex = !Array.isArray(mergedValue) ? getMonth(Date.now()) : getMonth(mergedValue[1]); endMonthScrollbarRef.value.scrollTo({ debounce: false, index: monthIndex, elSize: MONTH_ITEM_HEIGHT }); } if (endYearVlRef.value) { const yearIndex = (!Array.isArray(mergedValue) ? getYear(Date.now()) : getYear(mergedValue[1])) - yearRangeRef.value[0]; endYearVlRef.value.scrollTo({ index: yearIndex, debounce: false }); } } } // only for monthrange function handleColItemClick(dateItem, clickType) { const { value } = props; const noCurrentValue = !Array.isArray(value); const itemTs = dateItem.type === 'year' && type !== 'yearrange' ? noCurrentValue ? set(dateItem.ts, { month: getMonth(type === 'quarterrange' ? startOfQuarter(new Date()) : new Date()) }).valueOf() : set(dateItem.ts, { month: getMonth(type === 'quarterrange' ? startOfQuarter(value[clickType === 'start' ? 0 : 1]) : value[clickType === 'start' ? 0 : 1]) }).valueOf() : dateItem.ts; if (noCurrentValue) { const partialValue = sanitizeValue(itemTs); const nextValue = [partialValue, partialValue]; panelCommon.doUpdateValue(nextValue, props.panel); justifyColumnsScrollState(nextValue, 'start'); justifyColumnsScrollState(nextValue, 'end'); panelCommon.disableTransitionOneTick(); return; } const nextValue = [value[0], value[1]]; let otherPartsChanged = false; if (clickType === 'start') { nextValue[0] = sanitizeValue(itemTs); if (nextValue[0] > nextValue[1]) { nextValue[1] = nextValue[0]; otherPartsChanged = true; } } else { nextValue[1] = sanitizeValue(itemTs); if (nextValue[0] > nextValue[1]) { nextValue[0] = nextValue[1]; otherPartsChanged = true; } } panelCommon.doUpdateValue(nextValue, props.panel); switch (type) { case 'monthrange': case 'quarterrange': panelCommon.disableTransitionOneTick(); if (otherPartsChanged) { justifyColumnsScrollState(nextValue, 'start'); justifyColumnsScrollState(nextValue, 'end'); } else { justifyColumnsScrollState(nextValue, clickType); } break; case 'yearrange': panelCommon.disableTransitionOneTick(); justifyColumnsScrollState(nextValue, 'start'); justifyColumnsScrollState(nextValue, 'end'); } } function handleStartYearVlScroll() { var _a; (_a = startYearScrollbarRef.value) === null || _a === void 0 ? void 0 : _a.sync(); } function handleEndYearVlScroll() { var _a; (_a = endYearScrollbarRef.value) === null || _a === void 0 ? void 0 : _a.sync(); } function virtualListContainer(type) { var _a, _b; if (type === 'start') { return ((_a = startYearVlRef.value) === null || _a === void 0 ? void 0 : _a.listElRef) || null; } else { return ((_b = endYearVlRef.value) === null || _b === void 0 ? void 0 : _b.listElRef) || null; } } function virtualListContent(type) { var _a, _b; if (type === 'start') { return ((_a = startYearVlRef.value) === null || _a === void 0 ? void 0 : _a.itemsElRef) || null; } else { return ((_b = endYearVlRef.value) === null || _b === void 0 ? void 0 : _b.itemsElRef) || null; } } const childComponentRefs = { startYearVlRef, endYearVlRef, startMonthScrollbarRef, endMonthScrollbarRef, startYearScrollbarRef, endYearScrollbarRef }; return Object.assign(Object.assign(Object.assign(Object.assign({ startDatesElRef, endDatesElRef, handleDateClick, handleColItemClick, handleDateMouseEnter, handleConfirmClick, startCalendarPrevYear, startCalendarPrevMonth, startCalendarNextYear, startCalendarNextMonth, endCalendarPrevYear, endCalendarPrevMonth, endCalendarNextMonth, endCalendarNextYear, mergedIsDateDisabled, changeStartEndTime, ranges: rangesRef, calendarMonthBeforeYear: calendarMonthBeforeYearRef, startCalendarMonth: startCalendarMonthRef, startCalendarYear: startCalendarYearRef, endCalendarMonth: endCalendarMonthRef, endCalendarYear: endCalendarYearRef, weekdays: weekdaysRef, startDateArray: startDateArrayRef, endDateArray: endDateArrayRef, startYearArray: startYearArrayRef, startMonthArray: startMonthArrayRef, startQuarterArray: startQuarterArrayRef, endYearArray: endYearArrayRef, endMonthArray: endMonthArrayRef, endQuarterArray: endQuarterArrayRef, isSelecting: isSelectingRef, handleRangeShortcutMouseenter, handleRangeShortcutClick }, panelCommon), validation), childComponentRefs), { // datetimerangeonly startDateDisplayString: startDateInput, endDateInput: endDateInputRef, timePickerSize: panelCommon.timePickerSize, startTimeValue: startTimeValueRef, endTimeValue: endTimeValueRef, datePickerSlots, shortcuts: shortcutsRef, startCalendarDateTime: startCalendarDateTimeRef, endCalendarDateTime: endCalendarDateTimeRef, justifyColumnsScrollState, handleFocusDetectorFocus: panelCommon.handleFocusDetectorFocus, handleStartTimePickerChange, handleEndTimePickerChange, handleStartDateInput, handleStartDateInputBlur, handleEndDateInput, handleEndDateInputBlur, handleStartYearVlScroll, handleEndYearVlScroll, virtualListContainer, virtualListContent, onUpdateStartCalendarValue, onUpdateEndCalendarValue }); } export { useDualCalendar, useDualCalendarProps };