@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
JavaScript
"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
};