UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

445 lines (443 loc) 16.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _isFunction2 = _interopRequireDefault(require("lodash/isFunction")); var _stubFalse2 = _interopRequireDefault(require("lodash/stubFalse")); var _noop2 = _interopRequireDefault(require("lodash/noop")); var _react = _interopRequireDefault(require("react")); var _classnames = _interopRequireDefault(require("classnames")); var _propTypes = _interopRequireDefault(require("prop-types")); var _monthFoundation = _interopRequireDefault(require("@douyinfe/semi-foundation/lib/cjs/datePicker/monthFoundation")); var _constants = require("@douyinfe/semi-foundation/lib/cjs/datePicker/constants"); var _baseComponent = _interopRequireDefault(require("../_base/baseComponent")); var _index = require("@douyinfe/semi-foundation/lib/cjs/datePicker/_utils/index"); var _dateFns = require("date-fns"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /* eslint-disable jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions */ const prefixCls = _constants.cssClasses.PREFIX; class Month extends _baseComponent.default { constructor(props) { super(props); this.state = { weekdays: [], month: { weeks: [], monthText: '' }, todayText: '', weeksRowNum: props.weeksRowNum }; this.monthRef = /*#__PURE__*/_react.default.createRef(); } get adapter() { return Object.assign(Object.assign({}, super.adapter), { updateToday: todayText => this.setState({ todayText }), setWeekDays: weekdays => this.setState({ weekdays }), setWeeksRowNum: (weeksRowNum, callback) => this.setState({ weeksRowNum }, callback), updateMonthTable: month => this.setState({ month }), notifyDayClick: day => this.props.onDayClick(day), notifyDayHover: day => this.props.onDayHover(day), notifyWeeksRowNumChange: weeksRowNum => this.props.onWeeksRowNumChange(weeksRowNum) }); } componentDidMount() { this.foundation = new _monthFoundation.default(this.adapter); this.foundation.init(); } componentWillUnmount() { this.foundation.destroy(); } componentDidUpdate(prevProps, prevState) { if (prevProps.month !== this.props.month) { this.foundation.getMonthTable(); } } getSingleDayStatus(options) { const { rangeInputFocus } = this.props; const { fullDate, todayText, selected, disabledDate, rangeStart, rangeEnd } = options; const disabledOptions = { rangeStart, rangeEnd, rangeInputFocus }; const isToday = fullDate === todayText; const isSelected = selected.has(fullDate); let isDisabled = disabledDate && disabledDate((0, _dateFns.parseISO)(fullDate), disabledOptions); if (!isDisabled && this.props.rangeInputFocus === 'rangeStart' && rangeEnd && this.props.focusRecordsRef && this.props.focusRecordsRef.current.rangeEnd) { // The reason for splitting is that the dateRangeTime format: 'yyyy-MM-dd HH:MM:SS' isDisabled = (0, _index.isAfter)(fullDate, rangeEnd.trim().split(/\s+/)[0]); } if (!isDisabled && this.props.rangeInputFocus === 'rangeEnd' && rangeStart && this.props.focusRecordsRef && this.props.focusRecordsRef.current.rangeStart) { // The reason for splitting is that the dateRangeTime format: 'yyyy-MM-dd HH:MM:SS' isDisabled = (0, _index.isBefore)(fullDate, rangeStart.trim().split(/\s+/)[0]); } return { isToday, isSelected, isDisabled // Disabled }; } getDateRangeStatus(options) { const { rangeStart, rangeEnd, fullDate, hoverDay, offsetRangeStart, offsetRangeEnd, rangeInputFocus } = options; // If no item is selected, return the empty object directly const _isDateRangeAnySelected = Boolean(rangeStart || rangeEnd); const _isDateRangeSelected = Boolean(rangeStart && rangeEnd); const _isOffsetDateRangeAnyExist = offsetRangeStart || offsetRangeEnd; if (!_isDateRangeAnySelected) { return {}; } // The range selects the hover date, and the normal hover is .semi-datepicker-main: hover const _isHoverDay = (0, _index.isSameDay)(hoverDay, fullDate); // When one is selected let _isHoverAfterStart, _isHoverBeforeEnd, isSelectedStart, isSelectedEnd, isHoverDayAroundOneSelected; if (rangeStart) { isSelectedStart = (0, _index.isSameDay)(fullDate, rangeStart); if (rangeInputFocus === 'rangeEnd') { _isHoverAfterStart = (0, _index.isBetween)(fullDate, { start: rangeStart, end: hoverDay }); } } if (rangeEnd) { isSelectedEnd = (0, _index.isSameDay)(fullDate, rangeEnd); if (rangeInputFocus === 'rangeStart') { _isHoverBeforeEnd = (0, _index.isBetween)(fullDate, { start: hoverDay, end: rangeEnd }); } } if (!_isDateRangeSelected && _isDateRangeAnySelected) { isHoverDayAroundOneSelected = _isHoverDay; } let isHover; if (!_isOffsetDateRangeAnyExist) { isHover = _isHoverAfterStart || _isHoverBeforeEnd || _isHoverDay; } // Select all let isInRange, isSelectedStartAfterHover, isSelectedEndBeforeHover, isHoverDayInStartSelection, isHoverDayInEndSelection, isHoverDayInRange; if (_isDateRangeSelected) { isInRange = (0, _index.isBetween)(fullDate, { start: rangeStart, end: rangeEnd }); if (!_isOffsetDateRangeAnyExist) { isSelectedStartAfterHover = isSelectedStart && (0, _index.isAfter)(rangeStart, hoverDay); isSelectedEndBeforeHover = isSelectedEnd && (0, _index.isBefore)(rangeEnd, hoverDay); isHoverDayInStartSelection = _isHoverDay && rangeInputFocus === 'rangeStart'; isHoverDayInEndSelection = _isHoverDay && rangeInputFocus === 'rangeEnd'; isHoverDayInRange = _isHoverDay && (0, _index.isBetween)(hoverDay, { start: rangeStart, end: rangeEnd }); } } return { isHoverDay: _isHoverDay, isSelectedStart, isSelectedEnd, isInRange, isHover, isSelectedStartAfterHover, isSelectedEndBeforeHover, isHoverDayInRange, isHoverDayInStartSelection, isHoverDayInEndSelection, isHoverDayAroundOneSelected // Hover date and select a date }; } getOffsetDateStatus(options) { const { offsetRangeStart, offsetRangeEnd, rangeStart, rangeEnd, fullDate, hoverDay } = options; // When there is no offset, return the empty object directly const _isOffsetDateRangeNull = !(offsetRangeStart || offsetRangeEnd); if (_isOffsetDateRangeNull) { return {}; } // Range Select base date const _isInRange = (0, _index.isBetween)(fullDate, { start: rangeStart, end: rangeEnd }); const _isHoverDay = (0, _index.isSameDay)(hoverDay, fullDate); const _isSelectedStart = rangeStart && (0, _index.isSameDay)(fullDate, rangeStart); const _isSelectedEnd = rangeEnd && (0, _index.isSameDay)(fullDate, rangeEnd); const _isDateRangeSelected = Boolean(rangeStart && rangeEnd); // Determine whether it is offsetStart or offsetRangeEnd const isOffsetRangeStart = (0, _index.isSameDay)(fullDate, offsetRangeStart); const isOffsetRangeEnd = (0, _index.isSameDay)(fullDate, offsetRangeEnd); const isHoverDayOffset = _isHoverDay; // When selected let isHoverInOffsetRange, isInOffsetRange; if (_isDateRangeSelected) { isHoverInOffsetRange = _isInRange && _isHoverDay; } // When there is an offset area const _isOffsetDateRangeSelected = Boolean(offsetRangeStart && offsetRangeEnd); if (_isOffsetDateRangeSelected) { isInOffsetRange = _isSelectedStart || (0, _index.isBetween)(fullDate, { start: offsetRangeStart, end: offsetRangeEnd }) || _isSelectedEnd; } return { isOffsetRangeStart, isOffsetRangeEnd, isHoverInOffsetRange, isHoverDayOffset, isInOffsetRange // Include start and end within the week selection (start and end styles are the same as other dates, so start and end are included) }; } /** * get day current status * @param {Object} fullDate * @param {Object} options * @returns {Object} */ getDayStatus(currentDay, options) { const { fullDate } = currentDay; const { hoverDay, rangeStart, rangeEnd, todayText, offsetRangeStart, offsetRangeEnd, disabledDate, selected, rangeInputFocus } = options; const singleDayStatus = this.getSingleDayStatus({ fullDate, todayText, hoverDay, selected, disabledDate, rangeStart, rangeEnd }); const dateRangeStatus = this.getDateRangeStatus(Object.assign({ fullDate, rangeStart, rangeEnd, hoverDay, offsetRangeStart, offsetRangeEnd, rangeInputFocus }, singleDayStatus)); const offsetDataStatus = this.getOffsetDateStatus(Object.assign(Object.assign({ offsetRangeStart, offsetRangeEnd, rangeStart, rangeEnd, fullDate, hoverDay }, singleDayStatus), dateRangeStatus)); // this parameter will pass to the user when given renderFullDate function, do not delete or modify its key const dayStatus = Object.assign(Object.assign(Object.assign({}, singleDayStatus), dateRangeStatus), offsetDataStatus); return dayStatus; } renderDayOfWeek() { const { locale } = this.props; const weekdayCls = (0, _classnames.default)(_constants.cssClasses.WEEKDAY); const weekdayItemCls = (0, _classnames.default)(`${prefixCls}-weekday-item`); const { weekdays } = this.state; // i18n const weekdaysText = weekdays.map(key => locale.weeks[key]); return /*#__PURE__*/_react.default.createElement("div", { role: "row", className: weekdayCls }, weekdaysText.map((E, i) => (/*#__PURE__*/_react.default.createElement("div", { role: "columnheader", key: E + i, className: weekdayItemCls }, E)))); } renderWeeks() { const { month } = this.state; const { weeks } = month; const { weeksRowNum } = this.props; let style = {}; if (weeksRowNum) { const height = weeksRowNum * _constants.numbers.WEEK_HEIGHT; style = { height }; } const weeksCls = (0, _classnames.default)(_constants.cssClasses.WEEKS); return /*#__PURE__*/_react.default.createElement("div", { className: weeksCls, style: style }, weeks.map((week, weekIndex) => this.renderWeek(week, weekIndex))); } renderWeek(week, weekIndex) { const weekCls = _constants.cssClasses.WEEK; return /*#__PURE__*/_react.default.createElement("div", { role: "row", className: weekCls, key: weekIndex }, week.map((day, dayIndex) => this.renderDay(day, dayIndex))); } renderDay(day, dayIndex) { const { todayText } = this.state; const { renderFullDate, renderDate } = this.props; const { fullDate, dayNumber } = day; if (!fullDate) { return /*#__PURE__*/_react.default.createElement("div", { role: "gridcell", tabIndex: -1, key: dayNumber + dayIndex, className: _constants.cssClasses.DAY }, /*#__PURE__*/_react.default.createElement("span", null)); } const dayStatus = this.getDayStatus(day, Object.assign({ todayText }, this.props)); const dayCls = (0, _classnames.default)(_constants.cssClasses.DAY, { [_constants.cssClasses.DAY_TODAY]: dayStatus.isToday, [_constants.cssClasses.DAY_IN_RANGE]: dayStatus.isInRange, [_constants.cssClasses.DAY_HOVER]: dayStatus.isHover, [_constants.cssClasses.DAY_SELECTED]: dayStatus.isSelected, [_constants.cssClasses.DAY_SELECTED_START]: dayStatus.isSelectedStart, [_constants.cssClasses.DAY_SELECTED_END]: dayStatus.isSelectedEnd, [_constants.cssClasses.DAY_DISABLED]: dayStatus.isDisabled, // offsetDate class [_constants.cssClasses.DAY_HOVER_DAY]: dayStatus.isHoverDayOffset, [_constants.cssClasses.DAY_IN_OFFSET_RANGE]: dayStatus.isInOffsetRange, [_constants.cssClasses.DAY_SELECTED_RANGE_HOVER]: dayStatus.isHoverInOffsetRange, [_constants.cssClasses.DAY_OFFSET_RANGE_START]: dayStatus.isOffsetRangeStart, [_constants.cssClasses.DAY_OFFSET_RANGE_END]: dayStatus.isOffsetRangeEnd, // range input class [_constants.cssClasses.DAY_SELECTED_START_AFTER_HOVER]: dayStatus.isSelectedStartAfterHover, [_constants.cssClasses.DAY_SELECTED_END_BEFORE_HOVER]: dayStatus.isSelectedEndBeforeHover, [_constants.cssClasses.DAY_HOVER_DAY_BEFORE_RANGE]: dayStatus.isHoverDayInStartSelection, [_constants.cssClasses.DAY_HOVER_DAY_AFTER_RANGE]: dayStatus.isHoverDayInEndSelection, [_constants.cssClasses.DAY_HOVER_DAY_AROUND_SINGLE_SELECTED]: dayStatus.isHoverDayAroundOneSelected }); const dayMainCls = (0, _classnames.default)({ [`${_constants.cssClasses.DAY}-main`]: true }); const fullDateArgs = [dayNumber, fullDate, dayStatus]; const customRender = (0, _isFunction2.default)(renderFullDate); return /*#__PURE__*/_react.default.createElement("div", { role: "gridcell", tabIndex: dayStatus.isDisabled ? -1 : 0, "aria-disabled": dayStatus.isDisabled, "aria-selected": dayStatus.isSelected, "aria-label": fullDate, className: !customRender ? dayCls : _constants.cssClasses.DAY, title: fullDate, key: dayNumber + dayIndex, onClick: e => !dayStatus.isDisabled && this.foundation.handleClick(day), onMouseEnter: () => this.foundation.handleHover(day), onMouseLeave: () => this.foundation.handleHover() }, customRender ? renderFullDate(...fullDateArgs) : (/*#__PURE__*/_react.default.createElement("div", { className: dayMainCls }, (0, _isFunction2.default)(renderDate) ? renderDate(dayNumber, fullDate) : /*#__PURE__*/_react.default.createElement("span", null, dayNumber)))); } render() { const { forwardRef, multiple } = this.props; const weekday = this.renderDayOfWeek(); const weeks = this.renderWeeks(); const monthCls = (0, _classnames.default)(_constants.cssClasses.MONTH); const ref = forwardRef || this.monthRef; return /*#__PURE__*/_react.default.createElement("div", { role: "grid", "aria-multiselectable": multiple, ref: ref, className: monthCls }, weekday, weeks); } } exports.default = Month; Month.propTypes = { month: _propTypes.default.object, selected: _propTypes.default.object, rangeStart: _propTypes.default.string, rangeEnd: _propTypes.default.string, offsetRangeStart: _propTypes.default.string, offsetRangeEnd: _propTypes.default.string, onDayClick: _propTypes.default.func, onDayHover: _propTypes.default.func, weekStartsOn: _propTypes.default.number, disabledDate: _propTypes.default.func, weeksRowNum: _propTypes.default.number, onWeeksRowNumChange: _propTypes.default.func, renderDate: _propTypes.default.func, renderFullDate: _propTypes.default.func, hoverDay: _propTypes.default.string, startDateOffset: _propTypes.default.func, endDateOffset: _propTypes.default.func, rangeInputFocus: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]), focusRecordsRef: _propTypes.default.object, multiple: _propTypes.default.bool }; Month.defaultProps = { month: new Date(), selected: new Set(), rangeStart: '', rangeEnd: '', onDayClick: _noop2.default, onDayHover: _noop2.default, onWeeksRowNumChange: _noop2.default, weekStartsOn: _constants.numbers.WEEK_START_ON, disabledDate: _stubFalse2.default, weeksRowNum: 0 };