UNPKG

@nutui/nutui-react

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

638 lines (637 loc) 30.3 kB
import { _ as _define_property } from "@swc/helpers/_/_define_property"; import { _ as _object_spread } from "@swc/helpers/_/_object_spread"; import { _ as _object_spread_props } from "@swc/helpers/_/_object_spread_props"; import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array"; import { _ as _to_consumable_array } from "@swc/helpers/_/_to_consumable_array"; import React, { useState, useEffect, useRef } from "react"; import classNames from "classnames"; import { ComponentDefaults } from "../../utils/typings"; import { Utils, getCurrMonthData, getDaysStatus, getPreMonthDates } from "../../utils/date"; import requestAniFrame from "../../utils/raf"; import { useConfig } from "../configprovider"; import { usePropsValue } from "../../hooks/use-props-value"; import { splitDate, isMultiple, isCurrDay, getCurrDate, isStart, isEnd, isStartAndEnd } from "../calendar/utils"; var defaultProps = _object_spread_props(_object_spread({}, ComponentDefaults), { type: 'single', autoBackfill: false, popup: true, title: '', startDate: Utils.getDay(0), endDate: Utils.getDay(365), showToday: true, startText: '', endText: '', confirmText: '', showTitle: true, showSubTitle: true, scrollAnimation: true, firstDayOfWeek: 0, disableDate: function(date) { return false; }, renderHeaderButtons: undefined, renderDay: undefined, renderDayTop: undefined, renderDayBottom: undefined, onConfirm: function(data) {}, onUpdate: function() {}, onDayClick: function(data) {}, onPageChange: function(data) {} }); export var CalendarItem = /*#__PURE__*/ React.forwardRef(function(props, ref) { var locale = useConfig().locale; var _$_object_spread = _object_spread({}, defaultProps, props), style = _$_object_spread.style, className = _$_object_spread.className, children = _$_object_spread.children, popup = _$_object_spread.popup, type = _$_object_spread.type, autoBackfill = _$_object_spread.autoBackfill, title = _$_object_spread.title, defaultValue = _$_object_spread.defaultValue, startDate = _$_object_spread.startDate, endDate = _$_object_spread.endDate, showToday = _$_object_spread.showToday, startText = _$_object_spread.startText, endText = _$_object_spread.endText, confirmText = _$_object_spread.confirmText, showTitle = _$_object_spread.showTitle, showSubTitle = _$_object_spread.showSubTitle, scrollAnimation = _$_object_spread.scrollAnimation, firstDayOfWeek = _$_object_spread.firstDayOfWeek, disableDate = _$_object_spread.disableDate, renderHeaderButtons = _$_object_spread.renderHeaderButtons, renderBottomButton = _$_object_spread.renderBottomButton, renderDay = _$_object_spread.renderDay, renderDayTop = _$_object_spread.renderDayTop, renderDayBottom = _$_object_spread.renderDayBottom, value = _$_object_spread.value, onConfirm = _$_object_spread.onConfirm, onUpdate = _$_object_spread.onUpdate, onDayClick = _$_object_spread.onDayClick, onPageChange = _$_object_spread.onPageChange; var weekdays = locale.calendaritem.weekdays; var weeks = _to_consumable_array(weekdays.slice(firstDayOfWeek, 7)).concat(_to_consumable_array(weekdays.slice(0, firstDayOfWeek))); var monthTitle = locale.calendaritem.monthTitle; var _useState = _sliced_to_array(useState(''), 2), yearMonthTitle = _useState[0], setYearMonthTitle = _useState[1]; var _useState1 = _sliced_to_array(useState([]), 2), monthsData = _useState1[0], setMonthsData = _useState1[1]; var _useState2 = _sliced_to_array(useState(0), 2), monthsNum = _useState2[0], setMonthsNum = _useState2[1]; var _useState3 = _sliced_to_array(useState(0), 2), translateY = _useState3[0], setTranslateY = _useState3[1]; var _useState4 = _sliced_to_array(useState([]), 2), monthDefaultRange = _useState4[0], setMonthDefaultRange = _useState4[1]; // 初始化开始结束数据 var propStartDate = startDate || Utils.getDay(0); var propEndDate = endDate || Utils.getDay(365); var startDates = splitDate(propStartDate); var endDates = splitDate(propEndDate); var _useState5 = _sliced_to_array(useState({ currDateArray: [] }), 1), state = _useState5[0]; var getMonthsPanel = function() { return monthsPanel.current; }; var getMonthsRef = function() { return monthsRef.current; }; var resetDefaultValue = function() { if (defaultValue || Array.isArray(defaultValue) && defaultValue.length > 0) { return type !== 'single' ? _to_consumable_array(defaultValue) : defaultValue; } return undefined; }; var _usePropsValue = _sliced_to_array(usePropsValue({ value: value, defaultValue: resetDefaultValue(), finalValue: [], onChange: function(val) {} }), 2), currentDate = _usePropsValue[0], setCurrentDate = _usePropsValue[1]; var weeksPanel = useRef(null); var monthsRef = useRef(null); var monthsPanel = useRef(null); var viewAreaRef = useRef(null); var _useState6 = _sliced_to_array(useState(0), 2), avgHeight = _useState6[0], setAvgHeight = _useState6[1]; var viewHeight = 0; var classPrefix = 'nut-calendar'; var dayPrefix = 'nut-calendar-day'; // 获取月数据 var getMonthData = function(curData, monthNum, type) { var i = 0; var date = curData; var monthData = monthsData; do { var y = parseInt(date[0], 10); var m = parseInt(date[1], 10); var days = _to_consumable_array(getPreMonthDates('prev', y, m, firstDayOfWeek)).concat(_to_consumable_array(getDaysStatus('active', y, m))); var cssHeight = 39 + (days.length > 35 ? 384 : 320); var scrollTop = 0; if (monthData.length > 0) { var monthEle = monthData[monthData.length - 1]; scrollTop = monthEle.scrollTop + monthEle.cssHeight; } var monthInfo = { curData: date, title: monthTitle(y, m), monthData: days, cssHeight: cssHeight, scrollTop: scrollTop }; if (type === 'next') { if (!endDates || !Utils.compareDate("".concat(endDates[0], "/").concat(endDates[1], "/").concat(Utils.getMonthDays(endDates[0], endDates[1])), "".concat(curData[0], "/").concat(curData[1], "/").concat(curData[2]))) { monthData.push(monthInfo); } } else if (!startDates || !Utils.compareDate("".concat(curData[0], "/").concat(curData[1], "/").concat(curData[2]), "".concat(startDates[0], "/").concat(startDates[1], "/01"))) { monthData.unshift(monthInfo); } date = getCurrMonthData('next', y, m); }while (i++ < monthNum); setMonthsData(monthData); }; var setReachedYearMonthInfo = function(current) { var currentMonthsData = monthsData[current]; var _currentMonthsData_curData = _sliced_to_array(currentMonthsData.curData, 2), year = _currentMonthsData_curData[0], month = _currentMonthsData_curData[1]; if (currentMonthsData.title === yearMonthTitle) return; onPageChange && onPageChange([ year, month, "".concat(year, "-").concat(month) ]); setYearMonthTitle(currentMonthsData.title); }; // 设置默认的范围 var setDefaultRange = function(monthNum, current) { var start = 0; var end = 0; if (monthNum >= 3) { if (current > 0 && current < monthNum) { start = current - 1; end = current + 3; } else if (current === 0) { start = current; end = current + 4; } else if (current === monthNum) { start = current - 2; end = current + 2; } } else { start = 0; end = monthNum + 2; } setMonthDefaultRange([ start, end ]); setTranslateY(monthsData[start].scrollTop); setReachedYearMonthInfo(current); }; var getMonthNum = function() { var monthNum = Number(endDates[1]) - Number(startDates[1]); var yearNum = Number(endDates[0]) - Number(startDates[0]); if (yearNum > 0) { monthNum += 12 * yearNum; } if (monthNum <= 0) { monthNum = 1; } setMonthsNum(monthNum); return monthNum; }; var setDefaultDate = function() { var defaultData = []; // 日期转化为数组,限制初始日期。判断时间范围 if (type === 'range' && Array.isArray(currentDate)) { if (currentDate.length > 0) { if (propStartDate && Utils.compareDate(currentDate[0], propStartDate)) { currentDate.splice(0, 1, propStartDate); } if (propEndDate && Utils.compareDate(propEndDate, currentDate[1])) { currentDate.splice(1, 1, propEndDate); } defaultData = _to_consumable_array(splitDate(currentDate[0])).concat(_to_consumable_array(splitDate(currentDate[1]))); } } else if (type === 'multiple' && Array.isArray(currentDate)) { if (currentDate.length > 0) { var _currentDate; var defaultArr = []; var obj = {}; currentDate.forEach(function(item) { if (propStartDate && !Utils.compareDate(item, propStartDate) && propEndDate && !Utils.compareDate(propEndDate, item)) { if (!Object.hasOwnProperty.call(obj, item)) { defaultArr.push(item); obj[item] = item; } } }); currentDate.splice(0) && (_currentDate = currentDate).push.apply(_currentDate, _to_consumable_array(defaultArr)); defaultData = _to_consumable_array(splitDate(defaultArr[0])); } } else if (type === 'week' && Array.isArray(currentDate)) { if (currentDate.length > 0) { var _currentDate1; var _splitDate = _sliced_to_array(splitDate(currentDate[0]), 3), y = _splitDate[0], m = _splitDate[1], d = _splitDate[2]; var weekArr = Utils.getWeekDate(y, m, d, firstDayOfWeek); currentDate.splice(0) && (_currentDate1 = currentDate).push.apply(_currentDate1, _to_consumable_array(weekArr)); if (propStartDate && Utils.compareDate(currentDate[0], propStartDate)) { currentDate.splice(0, 1, propStartDate); } if (propEndDate && Utils.compareDate(propEndDate, currentDate[1])) { currentDate.splice(1, 1, propEndDate); } defaultData = _to_consumable_array(splitDate(currentDate[0])).concat(_to_consumable_array(splitDate(currentDate[1]))); } } else if (currentDate) { if (currentDate.length > 0) { if (propStartDate && Utils.compareDate(currentDate, propStartDate)) { defaultData = _to_consumable_array(splitDate(propStartDate)); } else if (propEndDate && !Utils.compareDate(currentDate, propEndDate)) { defaultData = _to_consumable_array(splitDate(propEndDate)); } else { defaultData = _to_consumable_array(splitDate(currentDate)); } } else { defaultData = []; } } return defaultData; }; var getCurrentIndex = function(defaultData) { // 设置默认可见区域 var current = 0; var lastCurrent = 0; if (defaultData.length > 0) { monthsData.forEach(function(item, index) { if (item.title === monthTitle(defaultData[0], defaultData[1])) { current = index; } if (type === 'range' || type === 'week') { if (item.title === monthTitle(defaultData[3], defaultData[4])) { lastCurrent = index; } } }); } else { // 当 defaultValue 为空时,如果月份列表包含当月,则默认定位到当月 var date = new Date(); var year = date.getFullYear(); var month = date.getMonth() + 1; var index = monthsData.findIndex(function(item) { return +item.curData[0] === year && +item.curData[1] === month; }); if (index > -1) { current = index; } } return { current: current, lastCurrent: lastCurrent }; }; var renderCurrentDate = function() { var defaultData = setDefaultDate(); var current = getCurrentIndex(defaultData); if (defaultData.length > 0) { // 设置当前选中日期 if (type === 'range') { chooseDay({ day: defaultData[2], type: 'active' }, monthsData[current.current], true); chooseDay({ day: defaultData[5], type: 'active' }, monthsData[current.lastCurrent], true); } else if (type === 'week') { chooseDay({ day: defaultData[2], type: 'curr' }, monthsData[current.current], true); } else if (type === 'multiple') { ; _to_consumable_array(currentDate).forEach(function(item) { var dateArr = splitDate(item); var currentIndex = current.current; monthsData.forEach(function(item, index) { if (item.title === monthTitle(dateArr[0], dateArr[1])) { currentIndex = index; } }); chooseDay({ day: dateArr[2], type: 'active' }, monthsData[currentIndex], true); }); } else { chooseDay({ day: defaultData[2], type: 'active' }, monthsData[current.current], true); } } return current.current; }; var requestAniFrameFunc = function(current, monthNum) { var lastItem = monthsData[monthsData.length - 1]; var containerHeight = lastItem.cssHeight + lastItem.scrollTop; requestAniFrame(function() { // 初始化 日历位置 if (monthsRef && monthsPanel && viewAreaRef) { viewHeight = getMonthsRef().clientHeight; getMonthsPanel().style.height = "".concat(containerHeight, "px"); getMonthsRef().scrollTop = monthsData[current].scrollTop; } }); setAvgHeight(Math.floor(containerHeight / (monthNum + 1))); }; var initData = function() { // 判断时间范围内存在多少个月 var monthNum = getMonthNum(); // 设置月份数据,获取包含月份的所有数据,只需要 set 一次即可。 getMonthData(startDates, monthNum, 'next'); var current = renderCurrentDate(); setDefaultRange(monthNum, current); requestAniFrameFunc(current, monthNum); }; useEffect(function() { initData(); }, []); var resetRender = function() { state.currDateArray.splice(0); monthsData.splice(0); initData(); }; useEffect(function() { setCurrentDate(resetDefaultValue() || []); }, [ defaultValue ]); useEffect(function() { popup && resetRender(); }, [ currentDate ]); // 暴露出的API var scrollToDate = function(date) { if (Utils.compareDate(date, propStartDate)) { date = propStartDate; } else if (!Utils.compareDate(date, propEndDate)) { date = propEndDate; } var dateArr = splitDate(date); monthsData.forEach(function(item, index) { if (item.title === monthTitle(dateArr[0], dateArr[1])) { var currTop = monthsData[index].scrollTop; if (monthsRef.current) { var distance = currTop - monthsRef.current.scrollTop; if (scrollAnimation) { var flag = 0; var interval = setInterval(function() { flag++; if (monthsRef.current) { var offset = distance / 10; monthsRef.current.scrollTop += offset; } if (flag >= 10) { clearInterval(interval); if (monthsRef.current) { monthsRef.current.scrollTop = currTop; } } }, 40); } else { monthsRef.current.scrollTop = currTop; } } } }); }; var monthsViewScroll = function(e) { if (monthsData.length <= 1) { return; } var scrollTop = e.target.scrollTop; var current = Math.floor(scrollTop / avgHeight); if (current < 0) return; if (!monthsData[current + 1]) return; var nextTop = monthsData[current + 1].scrollTop; var nextHeight = monthsData[current + 1].cssHeight; if (current === 0) { if (scrollTop >= nextTop) { current += 1; } } else if (current > 0 && current < monthsNum - 1) { if (scrollTop >= nextTop) { current += 1; } if (scrollTop < monthsData[current].scrollTop) { current -= 1; } } else { var viewPosition = Math.round(scrollTop + viewHeight); if (current + 1 <= monthsNum && viewPosition >= nextTop + nextHeight) { current += 1; } if (current >= 1 && scrollTop < monthsData[current - 1].scrollTop) { current -= 1; } } setDefaultRange(monthsNum, current); }; React.useImperativeHandle(ref, function() { return { scrollToDate: scrollToDate }; }); var getClasses = function(day, month) { var dateStr = getCurrDate(day, month); if (day.type === 'active') { if (propStartDate && Utils.compareDate(dateStr, propStartDate) || propEndDate && Utils.compareDate(propEndDate, dateStr)) { return "".concat(dayPrefix, "-disabled"); } if (type === 'range' || type === 'week') { if (isStart(dateStr, currentDate) || isEnd(dateStr, currentDate)) { return "".concat(dayPrefix, "-active ").concat(isStart(dateStr, currentDate) ? 'active-start' : '', " ").concat(isEnd(dateStr, currentDate) ? 'active-end' : ''); } if (Array.isArray(currentDate) && Object.values(currentDate).length === 2 && Utils.compareDate(currentDate[0], dateStr) && Utils.compareDate(dateStr, currentDate[1])) { if (disableDate(day)) { return "".concat(dayPrefix, "-choose-disabled"); } return "".concat(dayPrefix, "-choose"); } } else if (type === 'multiple' && isMultiple(dateStr, currentDate) || !Array.isArray(currentDate) && Utils.isEqual(currentDate, dateStr)) { return "".concat(dayPrefix, "-active"); } if (disableDate(day)) { return "".concat(dayPrefix, "-disabled"); } return null; } return "".concat(dayPrefix, "-disabled"); }; var chooseDay = function(day, month, isFirst) { if (getClasses(day, month) === "".concat(dayPrefix, "-disabled")) { return; } var days = _to_consumable_array(month.curData); var _month_curData = _sliced_to_array(month.curData, 2), y = _month_curData[0], m = _month_curData[1]; days[2] = typeof day.day === 'number' ? Utils.getNumTwoBit(day.day) : day.day; days[3] = "".concat(days[0], "/").concat(days[1], "/").concat(days[2]); days[4] = Utils.getWhatDay(+days[0], +days[1], +days[2]); if (type === 'multiple') { if (currentDate.length > 0) { var hasIndex = ''; currentDate.forEach(function(item, index) { if (item === days[3]) { hasIndex = index; } }); if (isFirst) { state.currDateArray.push(_to_consumable_array(days)); } else if (hasIndex !== '') { ; currentDate.splice(hasIndex, 1); state.currDateArray.splice(hasIndex, 1); } else { ; currentDate.push(days[3]); state.currDateArray.push(_to_consumable_array(days)); } } else { ; currentDate.push(days[3]); state.currDateArray = [ _to_consumable_array(days) ]; } } else if (type === 'range') { var curDataLength = Object.values(currentDate).length; if (curDataLength === 2 || curDataLength === 0) { Array.isArray(currentDate) && currentDate.splice(0) && currentDate.push(days[3]); state.currDateArray = [ _to_consumable_array(days) ]; } else if (Utils.compareDate(currentDate[0], days[3])) { Array.isArray(currentDate) && currentDate.push(days[3]); state.currDateArray = _to_consumable_array(state.currDateArray).concat([ _to_consumable_array(days) ]); } else { Array.isArray(currentDate) && currentDate.unshift(days[3]); state.currDateArray = [ _to_consumable_array(days) ].concat(_to_consumable_array(state.currDateArray)); } } else if (type === 'week') { var _currentDate; var weekArr = Utils.getWeekDate(y, m, "".concat(day.day), firstDayOfWeek); if (propStartDate && Utils.compareDate(weekArr[0], propStartDate)) { weekArr.splice(0, 1, propStartDate); } if (propEndDate && Utils.compareDate(propEndDate, weekArr[1])) { weekArr.splice(1, 1, propEndDate); } Array.isArray(currentDate) && currentDate.splice(0) && (_currentDate = currentDate).push.apply(_currentDate, _to_consumable_array(weekArr)); state.currDateArray = [ Utils.formatResultDate(weekArr[0]), Utils.formatResultDate(weekArr[1]) ]; } else { setCurrentDate(days[3]); state.currDateArray = _to_consumable_array(days); } if (!isFirst) { onDayClick && onDayClick(state.currDateArray); if (autoBackfill || !popup) { confirm(); } } setMonthsData(monthsData.slice()); }; var resetSelectedValue = function() { var itemData = function(dateArr) { days = dateArr.split('/'); days[3] = "".concat(days[0], "/").concat(days[1], "/").concat(days[2]); days[4] = Utils.getWhatDay(+days[0], +days[1], +days[2]); return days; }; var days = []; if (Array.isArray(currentDate) && currentDate) { days = currentDate.map(function(item) { return itemData(item); }); } else { days = itemData(currentDate); } return days; }; var confirm = function() { if (type === 'range' && state.currDateArray.length === 2 || type !== 'range') { var chooseData = state.currDateArray.slice(0); onConfirm && onConfirm(chooseData); if (popup) { onUpdate && onUpdate(); } } }; var _obj; var classes = classNames((_obj = {}, _define_property(_obj, "".concat(classPrefix, "-title"), !popup), _define_property(_obj, "".concat(classPrefix, "-nofooter"), !!autoBackfill), _obj), classPrefix, className); var _obj1; var headerClasses = classNames((_obj1 = {}, _define_property(_obj1, "".concat(classPrefix, "-header"), true), _define_property(_obj1, "".concat(classPrefix, "-header-title"), !popup), _obj1)); // 是否有开始提示 var isStartTip = function(day, month) { return (type === 'range' || type === 'week') && day.type === 'active' && isStart(getCurrDate(day, month), currentDate); }; // 是否有结束提示 var isEndTip = function(day, month) { return currentDate.length >= 2 && (type === 'range' || type === 'week') && day.type === 'active' && isEnd(getCurrDate(day, month), currentDate); }; var renderHeader = function() { return /*#__PURE__*/ React.createElement("div", { className: headerClasses }, showTitle && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-title") }, title || locale.calendaritem.title), renderHeaderButtons && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-header-buttons") }, renderHeaderButtons()), showSubTitle && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-sub-title") }, yearMonthTitle), /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-weeks"), ref: weeksPanel }, weeks.map(function(item) { return /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-week-item"), key: item }, item); }))); }; var renderContent = function() { return /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-content"), onScroll: monthsViewScroll, ref: monthsRef }, /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-pannel"), ref: monthsPanel }, /*#__PURE__*/ React.createElement("div", { className: "viewArea", ref: viewAreaRef, style: { transform: "translateY(".concat(translateY, "px)") } }, monthsData.slice(monthDefaultRange[0], monthDefaultRange[1]).map(function(month, key) { return /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-month"), key: key }, /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-month-title") }, month.title), /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-days") }, month.monthData.map(function(day, i) { return /*#__PURE__*/ React.createElement("div", { className: [ "".concat(classPrefix, "-day"), getClasses(day, month) ].join(' '), onClick: function() { chooseDay(day, month); }, key: i }, /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-day-day") }, renderDay ? renderDay(day) : day.day), !isStartTip(day, month) && renderDayTop && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-day-info-top") }, renderDayTop(day)), !isStartTip(day, month) && !isEndTip(day, month) && renderDayBottom && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-day-info-bottom") }, renderDayBottom(day)), !isStartTip(day, month) && !isEndTip(day, month) && !renderDayBottom && showToday && isCurrDay(month, day.day) && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-day-info-curr") }, locale.calendaritem.today), isStartTip(day, month) && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-day-info ").concat(isStartAndEnd(currentDate) ? "".concat(classPrefix, "-day-info-top") : '') }, startText || locale.calendaritem.start), isEndTip(day, month) && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-day-info") }, endText || locale.calendaritem.end)); }))); })))); }; var renderFooter = function() { return /*#__PURE__*/ React.createElement("div", { className: "nut-calendar-footer" }, children, /*#__PURE__*/ React.createElement("div", { onClick: confirm }, renderBottomButton ? renderBottomButton() : /*#__PURE__*/ React.createElement("div", { className: "calendar-confirm-btn" }, confirmText || locale.confirm))); }; return /*#__PURE__*/ React.createElement("div", { className: classes, style: style }, renderHeader(), renderContent(), popup && !autoBackfill ? renderFooter() : ''); }); CalendarItem.displayName = 'NutCalendarItem';