@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.
277 lines • 9.42 kB
JavaScript
import _isEqual from "lodash/isEqual";
import React, { Fragment } from 'react';
import cls from 'classnames';
import PropTypes from 'prop-types';
import CalendarFoundation from '@douyinfe/semi-foundation/lib/es/calendar/foundation';
import LocaleConsumer from '../locale/localeConsumer';
import localeContext from '../locale/context';
import { cssClasses } from '@douyinfe/semi-foundation/lib/es/calendar/constants';
import BaseComponent from '../_base/baseComponent';
import DayCol from './dayCol';
import TimeCol from './timeCol';
import { calcRowHeight } from '@douyinfe/semi-foundation/lib/es/calendar/eventUtil';
import '@douyinfe/semi-foundation/lib/es/calendar/calendar.css';
const toPercent = num => {
const res = num < 1 ? num * 100 : 100;
return `${res}%`;
};
const prefixCls = `${cssClasses.PREFIX}-week`;
const allDayCls = `${cssClasses.PREFIX}-all-day`;
export default class WeekCalendar extends BaseComponent {
constructor(props) {
super(props);
this.checkWeekend = val => this.foundation.checkWeekend(val);
this.handleClick = (e, val) => {
const {
onClick
} = this.props;
const value = this.foundation.formatCbValue(val);
onClick && onClick(e, value);
};
this.renderDayGrid = () => {
const {
parsedEvents
} = this.state;
const events = parsedEvents.day;
const {
week
} = this.weeklyData;
const {
markWeekend,
dateGridRender,
minEventHeight
} = this.props;
const inner = week.map(day => {
const dateString = day.date.toString();
const dayEvents = events.has(dateString) ? events.get(dateString) : [];
const parsed = this.foundation.getParseDailyEvents(dayEvents, day.date);
return /*#__PURE__*/React.createElement(DayCol, {
key: `${dateString}-weekday`,
displayValue: day.date,
scrollHeight: this.state.scrollHeight,
handleClick: this.handleClick,
events: parsed.day,
showCurrTime: this.props.showCurrTime,
isWeekend: markWeekend && day.isWeekend,
dateGridRender: dateGridRender,
minEventHeight: minEventHeight
});
});
return inner;
};
this.renderHeader = dateFnsLocale => {
const {
markWeekend,
displayValue,
renderDateDisplay
} = this.props;
const {
month,
week
} = this.foundation.getWeeklyData(displayValue, dateFnsLocale);
return /*#__PURE__*/React.createElement("div", {
className: `${prefixCls}-header`
}, /*#__PURE__*/React.createElement("ul", {
className: `${cssClasses.PREFIX}-tag ${prefixCls}-tag ${prefixCls}-sticky-left`
}, /*#__PURE__*/React.createElement("span", null, month)), /*#__PURE__*/React.createElement("div", {
role: "gridcell",
className: `${prefixCls}-grid`
}, /*#__PURE__*/React.createElement("ul", {
className: `${prefixCls}-grid-row`
}, week.map(day => {
const {
date,
dayString,
weekday,
isToday
} = day;
const listCls = cls({
[`${cssClasses.PREFIX}-today`]: isToday,
[`${cssClasses.PREFIX}-weekend`]: markWeekend && day.isWeekend
});
const dateContent = renderDateDisplay ? renderDateDisplay(date) : (/*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("span", {
className: `${cssClasses.PREFIX}-today-date`
}, dayString), /*#__PURE__*/React.createElement("span", null, weekday)));
return /*#__PURE__*/React.createElement("li", {
key: `${date.toString()}-weekheader`,
className: listCls
}, dateContent);
}))));
};
this.renderAllDayEvents = events => {
if (this.props.allDayEventsRender) {
return this.props.allDayEventsRender(this.props.events);
}
const list = events.map((event, ind) => {
const {
leftPos,
width,
topInd,
children,
key
} = event;
const top = `${topInd}em`;
const style = {
left: toPercent(leftPos),
width: toPercent(width),
top
};
return /*#__PURE__*/React.createElement("li", {
className: `${cssClasses.PREFIX}-event-item ${cssClasses.PREFIX}-event-allday`,
key: `allDay-${ind}`,
style: style
}, children);
});
return list;
};
this.renderAllDay = locale => {
const {
allDayEventsRender
} = this.props;
const {
allDay
} = this.state.parsedEvents;
const parsed = this.foundation.parseWeeklyAllDayEvents(allDay);
const style = allDayEventsRender ? null : {
height: `${calcRowHeight(parsed)}em`
};
const {
markWeekend
} = this.props;
const {
week
} = this.weeklyData;
return /*#__PURE__*/React.createElement("div", {
className: `${allDayCls}`,
style: style
}, /*#__PURE__*/React.createElement("ul", {
className: `${cssClasses.PREFIX}-tag ${allDayCls}-tag ${prefixCls}-sticky-left`
}, /*#__PURE__*/React.createElement("span", null, locale.allDay)), /*#__PURE__*/React.createElement("div", {
role: "gridcell",
className: `${cssClasses.PREFIX}-content ${allDayCls}-content`
}, /*#__PURE__*/React.createElement("ul", {
className: `${allDayCls}-skeleton`
}, Object.keys(week).map((date, ind) => {
const listCls = cls({
[`${cssClasses.PREFIX}-weekend`]: markWeekend && week[date].isWeekend
});
return /*#__PURE__*/React.createElement("li", {
key: `${date}-weekgrid`,
className: listCls
});
})), /*#__PURE__*/React.createElement("ul", {
className: `${cssClasses.PREFIX}-event-items`
}, this.renderAllDayEvents(parsed))));
};
this.state = {
scrollHeight: 0,
parsedEvents: {
day: new Map(),
allDay: new Map()
},
cachedKeys: []
};
this.foundation = new CalendarFoundation(this.adapter);
this.dom = /*#__PURE__*/React.createRef();
this.scrollDom = /*#__PURE__*/React.createRef();
this.handleClick = this.handleClick.bind(this);
this.allDayRowHeight = 1;
}
get adapter() {
return Object.assign(Object.assign({}, super.adapter), {
setWeeklyData: data => {
this.weeklyData = data;
},
getWeeklyData: () => this.weeklyData,
updateScrollHeight: scrollHeight => {
this.setState({
scrollHeight
});
},
setParsedEvents: parsedEvents => {
this.setState({
parsedEvents: parsedEvents
});
},
cacheEventKeys: cachedKeys => {
this.setState({
cachedKeys
});
}
});
}
componentDidMount() {
this.foundation.init();
const {
scrollHeight
} = this.scrollDom.current;
this.dom.current.scrollTop = this.props.scrollTop;
this.foundation.notifyScrollHeight(scrollHeight);
this.foundation.parseWeeklyEvents();
}
componentDidUpdate(prevProps, prevState) {
const prevEventKeys = prevState.cachedKeys;
const nowEventKeys = this.props.events.map(event => event.key);
if (!_isEqual(prevEventKeys, nowEventKeys) || !_isEqual(prevProps.displayValue, this.props.displayValue)) {
this.foundation.parseWeeklyEvents();
}
}
componentWillUnmount() {
this.foundation.destroy();
}
render() {
const {
renderTimeDisplay,
className,
height,
width,
style,
header
} = this.props;
const weekCls = cls(prefixCls, className);
const weekStyle = Object.assign({
height,
width
}, style);
return /*#__PURE__*/React.createElement(LocaleConsumer, {
componentName: "Calendar"
}, (locale, localeCode, dateFnsLocale) => (/*#__PURE__*/React.createElement("div", Object.assign({
className: weekCls,
style: weekStyle,
ref: this.dom
}, this.getDataAttr(this.props)), /*#__PURE__*/React.createElement("div", {
className: `${prefixCls}-sticky-top`
}, header, this.renderHeader(dateFnsLocale), this.renderAllDay(locale)), /*#__PURE__*/React.createElement("div", {
className: `${prefixCls}-scroll-wrapper`
}, /*#__PURE__*/React.createElement("div", {
className: `${prefixCls}-scroll`,
ref: this.scrollDom
}, /*#__PURE__*/React.createElement(TimeCol, {
className: `${prefixCls}-sticky-left`,
renderTimeDisplay: renderTimeDisplay
}), this.renderDayGrid())))));
}
}
WeekCalendar.propTypes = {
displayValue: PropTypes.instanceOf(Date),
header: PropTypes.node,
events: PropTypes.array,
mode: PropTypes.string,
showCurrTime: PropTypes.bool,
markWeekend: PropTypes.bool,
scrollTop: PropTypes.number,
renderTimeDisplay: PropTypes.func,
renderDateDisplay: PropTypes.func,
dateGridRender: PropTypes.func,
allDayEventsRender: PropTypes.func,
width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
style: PropTypes.object,
className: PropTypes.string
};
WeekCalendar.defaultProps = {
displayValue: new Date(),
events: [],
mode: 'week'
};
WeekCalendar.contextType = localeContext;