UNPKG

@nutui/nutui-react

Version:

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

418 lines (417 loc) 14.2 kB
import React__default, { useState, useEffect } from "react"; import classNames from "classnames"; import { C as ComponentDefaults } from "./typings.js"; import { U as Utils } from "./date.js"; import { u as useConfig } from "./configprovider2.js"; import { u as usePropsValue } from "./use-props-value.js"; const ArrowLeft = () => { return React__default.createElement( "svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 18 18" }, React__default.createElement("path", { d: "M6.605 9.49a.771.771 0 0 1 0-.98l3.6-4.372a.771.771 0 0 1 1.19.981L8.2 9l3.197 3.881a.771.771 0 1 1-1.191.98l-3.6-4.37Z" }) ); }; const ArrowRight = () => { return React__default.createElement( "svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 18 18" }, React__default.createElement("path", { d: "M11.396 9.49a.771.771 0 0 0 0-.98l-3.6-4.372a.771.771 0 0 0-1.191.981L9.8 9l-3.196 3.881a.771.771 0 0 0 1.19.98l3.6-4.37Z" }) ); }; const DoubleLeft = () => { return React__default.createElement( "svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 18 18" }, React__default.createElement("path", { d: "M13.853 4.026a.771.771 0 0 1 .12 1.085L10.864 9l3.11 3.889a.771.771 0 1 1-1.204.963L9.272 9.482a.771.771 0 0 1 0-.964l3.497-4.371a.771.771 0 0 1 1.084-.12Zm-5.245 0a.771.771 0 0 1 .12 1.085L5.617 9l3.111 3.889a.771.771 0 0 1-1.205.963L4.026 9.482a.771.771 0 0 1 0-.964l3.497-4.371a.771.771 0 0 1 1.085-.12Z" }) ); }; const DoubleRight = () => { return React__default.createElement( "svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 18 18" }, React__default.createElement("path", { d: "M4.147 13.974a.771.771 0 0 1-.12-1.085L7.136 9 4.028 5.11a.771.771 0 1 1 1.204-.963l3.497 4.371a.771.771 0 0 1 0 .964l-3.497 4.371a.771.771 0 0 1-1.084.12Zm5.245 0a.771.771 0 0 1-.12-1.085L12.383 9 9.272 5.11a.771.771 0 1 1 1.205-.963l3.497 4.371a.771.771 0 0 1 0 .964l-3.497 4.371a.771.771 0 0 1-1.085.12Z" }) ); }; const convertDateToDay = (date) => { return date ? { year: date.getFullYear(), month: date.getMonth() + 1, date: date.getDate() } : null; }; const convertDayToDate = (day) => { return day ? new Date(day.year, day.month - 1, day.date) : null; }; const getPrevMonthDays = (year, month, firstDayOfWeek) => { let prevMonth = month - 1; let prevYear = year; if (prevMonth <= 0) { prevMonth = 12; prevYear -= 1; } let days = Utils.getMonthPreDay(year, month); days -= firstDayOfWeek; if (days >= 7) { days -= 7; } const preDates = Utils.getMonthDays(`${prevYear}`, `${prevMonth}`); const months = Array.from(Array(preDates), (_, k) => { return { type: "prev", year: prevYear, month: prevMonth, date: k + 1 }; }); return months.slice(preDates - days); }; const getCurrentMonthDays = (year, month) => { const days = Utils.getMonthDays(`${year}`, `${month}`); return Array.from(Array(days), (_, k) => { return { type: "current", year, month, date: k + 1 }; }); }; const getCurrentWeekDays = (day, firstDayOfWeek) => { const current = new Date(day.year, day.month - 1, day.date); const count = (current.getDay() + 7 - firstDayOfWeek) % 7; return [ convertDateToDay(new Date(current.getTime() - 24 * 60 * 60 * 1e3 * count)), convertDateToDay(new Date(current.getTime() + 24 * 60 * 60 * 1e3 * (6 - count))) ]; }; const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { type: "single", firstDayOfWeek: 0 }); const prefixCls = "nut-calendarcard"; const CalendarCard = React__default.forwardRef((props, ref) => { const { locale } = useConfig(); const { style, className, type, value, defaultValue, firstDayOfWeek, startDate, endDate, disableDay, renderDay, renderDayTop, renderDayBottom, onDayClick, onPageChange, onChange } = Object.assign(Object.assign({}, defaultProps), props); const [month, setMonth] = useState(() => { let date = new Date(Date.now()); const val = value || defaultValue; if (Array.isArray(val)) { if (val.length) { date = val[0]; } } else if (val) { date = val; } return { year: date.getFullYear(), month: date.getMonth() + 1 }; }); const [days, setDays] = useState([]); const valueToRange = (val) => { if (Array.isArray(val)) { return val.map((date) => { return convertDateToDay(date); }); } return val ? [convertDateToDay(val)] : []; }; const rangeTovalue = (range) => { if (Array.isArray(range)) { return range.map((day) => { return convertDayToDate(day); }); } return range ? [convertDayToDate(range)] : []; }; const [innerValue, setInnerValue] = usePropsValue({ value: value ? valueToRange(value) : void 0, defaultValue: defaultValue ? valueToRange(defaultValue) : void 0, finalValue: [] }); const change = (v) => { setInnerValue(v); if (type === "single") { const date = convertDayToDate(v[0]); onChange === null || onChange === void 0 ? void 0 : onChange(date); } else if (type === "multiple" || type === "range" || type === "week") { const val = rangeTovalue(v); onChange === null || onChange === void 0 ? void 0 : onChange(val); } }; const getDays = (month2) => { const y = month2.year; const m = month2.month; const days2 = [ ...getPrevMonthDays(y, m, firstDayOfWeek), ...getCurrentMonthDays(y, m) ]; const size = days2.length; const yearOfNextMonth = month2.month === 12 ? month2.year + 1 : month2.year; const monthOfNextMonth = month2.month === 12 ? 1 : month2.month + 1; for (let i = 1; i <= 42 - size; i++) { days2.push({ type: "next", year: yearOfNextMonth, month: monthOfNextMonth, date: i }); } return days2; }; useEffect(() => { const newDays = getDays(month); setDays(newDays); onPageChange === null || onPageChange === void 0 ? void 0 : onPageChange(month); }, [month]); const isSameDay = (day1, day2) => { return (day1 === null || day1 === void 0 ? void 0 : day1.year) === (day2 === null || day2 === void 0 ? void 0 : day2.year) && (day1 === null || day1 === void 0 ? void 0 : day1.month) === (day2 === null || day2 === void 0 ? void 0 : day2.month) && (day1 === null || day1 === void 0 ? void 0 : day1.date) === (day2 === null || day2 === void 0 ? void 0 : day2.date); }; const compareDay = (day1, day2) => { if (day1 && day2) { if (day1.year === day2.year) { if (day1.month === day2.month) { return day1.date - day2.date; } return day1.month - day2.month; } return day1.year - day2.year; } }; const isDisable = (day) => { if (disableDay && disableDay(day)) { return true; } if (startDate && Number(compareDay(day, convertDateToDay(startDate))) < 0) { return true; } if (endDate && Number(compareDay(day, convertDateToDay(endDate))) > 0) { return true; } return false; }; const isActive = (day) => { if (type === "single" || type === "multiple") { for (const val of innerValue) { if (isSameDay(day, val)) { return true; } } } else if (type === "range" && innerValue.length === 1 && isSameDay(innerValue[0], day)) { return true; } return false; }; const isStart = (day) => { return (type === "range" || type === "week") && innerValue.length === 2 && isSameDay(day, innerValue[0]); }; const isEnd = (day) => { return (type === "range" || type === "week") && innerValue.length === 2 && isSameDay(day, innerValue[1]); }; const isMid = (day) => { if (type === "range" || type === "week") { if (innerValue.length === 2) { const c1 = compareDay(innerValue[0], day); const c2 = compareDay(day, innerValue[1]); if (c1 && c1 < 0 && c2 && c2 < 0) { return true; } } } return false; }; const isWeekend = (day) => { const d = new Date(day.year, day.month - 1, day.date).getDay(); return d === 0 || d === 6; }; const getClasses = (day) => { if (isDisable(day)) { return ["disabled"]; } const res = []; if (day.type === "current") { if (isActive(day)) { res.push("active"); } if (isStart(day)) { res.push("start"); } if (isEnd(day)) { res.push("end"); } if (isMid(day)) { res.push("mid"); } if (isWeekend(day)) { res.push("weekend"); } } return res; }; const jumpTo = (year, month2) => { if (startDate) { const c = compareDay({ year, month: month2, date: 31 }, convertDateToDay(startDate)); if (c && c < 0) { return; } } if (endDate) { const c = compareDay({ year, month: month2, date: 1 }, convertDateToDay(endDate)); if (c && c > 0) { return; } } setMonth({ year, month: month2 }); }; const jump = (step = 1) => { const current = month.year * 12 + month.month; let newMonth = (current + step) % 12; if (newMonth === 0) { newMonth = 12; } const newYear = Math.floor((current + step - newMonth) / 12); jumpTo(newYear, newMonth); }; React__default.useImperativeHandle(ref, () => { return { jump, jumpTo }; }); const handleDayClick = (day) => { onDayClick === null || onDayClick === void 0 ? void 0 : onDayClick(day); if (day.type === "prev" || day.type === "next" || isDisable(day)) { return; } switch (type) { case "single": { if (innerValue[0] && isSameDay(innerValue[0], day)) { change([]); } else { change([day]); } break; } case "multiple": { const t = innerValue.find((i) => isSameDay(i, day)); if (t) { change(innerValue.filter((i) => i !== t)); } else { change([...innerValue, day]); } break; } case "range": { const len = innerValue.length; if (len === 0 || len === 2) { change([day]); } else if (len === 1) { const t = compareDay(innerValue[0], day); if (t === null || t === void 0) { change([]); } else if (t < 0) { change([innerValue[0], day]); } else { change([day, innerValue[0]]); } } else { console.warn("[NutUI] Calendar range error"); } break; } case "week": { if (innerValue.length === 2 || innerValue.length === 0) { const [left, right] = getCurrentWeekDays(day, firstDayOfWeek); change([left, right]); } else { console.warn("[NutUI] Calendar week error"); } break; } default: { console.warn("[NutUI] Calendar type error"); } } }; const monthTitle = locale.calendaritem.monthTitle; const renderHeader = () => { return React__default.createElement( "div", { className: `${prefixCls}-header` }, React__default.createElement( "div", { className: `${prefixCls}-header-left` }, React__default.createElement( "div", { className: "double-left", onClick: () => jump(-12) }, React__default.createElement(DoubleLeft, null) ), React__default.createElement( "div", { className: "left", onClick: () => jump(-1) }, React__default.createElement(ArrowLeft, null) ) ), React__default.createElement("div", { className: `${prefixCls}-header-title` }, monthTitle(month.year, month.month)), React__default.createElement( "div", { className: `${prefixCls}-header-right` }, React__default.createElement( "div", { className: "right", onClick: () => jump(1) }, React__default.createElement(ArrowRight, null) ), React__default.createElement( "div", { className: "double-right", onClick: () => jump(12) }, React__default.createElement(DoubleRight, null) ) ) ); }; const [weekHeader] = useState(() => { const weekdays = locale.calendaritem.weekdays.map((day, index) => { return { name: day, key: index }; }); return [ ...weekdays.slice(firstDayOfWeek, 7), ...weekdays.slice(0, firstDayOfWeek) ]; }); const renderContent = () => { return React__default.createElement( "div", { className: `${prefixCls}-content` }, React__default.createElement("div", { className: `${prefixCls}-days` }, weekHeader.map((day) => { return React__default.createElement("div", { className: classNames(`${prefixCls}-day`, "header", { weekend: day.key === 0 || day.key === 6 }), key: day.key }, day.name); })), React__default.createElement("div", { className: `${prefixCls}-days` }, days.map((day) => React__default.createElement( "div", { className: classNames(`${prefixCls}-day`, day.type, getClasses(day)), key: `${day.year}-${day.month}-${day.date}`, onClick: () => handleDayClick(day) }, React__default.createElement("div", { className: `${prefixCls}-day-top` }, renderDayTop ? renderDayTop(day) : ""), React__default.createElement("div", { className: `${prefixCls}-day-inner` }, renderDay ? renderDay(day) : day.date), React__default.createElement("div", { className: `${prefixCls}-day-bottom` }, renderDayBottom ? renderDayBottom(day) : "") ))) ); }; return days.length > 0 ? React__default.createElement( "div", { className: classNames(prefixCls, className), style }, renderHeader(), renderContent() ) : null; }); CalendarCard.displayName = "NutCalendarCard"; export { CalendarCard as default };