dayCalendar.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import React from 'react';
  2. import { isEqual } from 'lodash';
  3. import cls from 'classnames';
  4. import PropTypes from 'prop-types';
  5. import CalendarFoundation, { CalendarAdapter, ParsedEventsType, ParsedEventsWithArray } from '@douyinfe/semi-foundation/calendar/foundation';
  6. import { cssClasses } from '@douyinfe/semi-foundation/calendar/constants';
  7. import DayCol from './dayCol';
  8. import TimeCol from './timeCol';
  9. import BaseComponent from '../_base/baseComponent';
  10. import LocaleConsumer from '../locale/localeConsumer';
  11. import localeContext from '../locale/context';
  12. import { Locale } from '../locale/interface';
  13. import { DayCalendarProps } from './interface';
  14. import '@douyinfe/semi-foundation/calendar/calendar.scss';
  15. const prefixCls = `${cssClasses.PREFIX}-day`;
  16. export interface DayCalendarState {
  17. scrollHeight: number;
  18. parsedEvents: ParsedEventsWithArray;
  19. cachedKeys: Array<string>;
  20. }
  21. export default class DayCalendar extends BaseComponent<DayCalendarProps, DayCalendarState> {
  22. static propTypes = {
  23. displayValue: PropTypes.instanceOf(Date),
  24. events: PropTypes.array,
  25. header: PropTypes.node,
  26. showCurrTime: PropTypes.bool,
  27. onClick: PropTypes.func,
  28. mode: PropTypes.string,
  29. renderTimeDisplay: PropTypes.func,
  30. markWeekend: PropTypes.bool,
  31. scrollTop: PropTypes.number,
  32. width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  33. height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  34. style: PropTypes.object,
  35. className: PropTypes.string,
  36. dateGridRender: PropTypes.func,
  37. };
  38. static defaultProps = {
  39. events: [] as DayCalendarProps['events'],
  40. displayValue: new Date(),
  41. mode: 'day',
  42. };
  43. static contextType = localeContext;
  44. dom: React.RefObject<HTMLDivElement>;
  45. scrollDom: React.RefObject<HTMLDivElement>;
  46. isWeekend: boolean;
  47. foundation: CalendarFoundation;
  48. constructor(props: DayCalendarProps) {
  49. super(props);
  50. this.foundation = new CalendarFoundation(this.adapter);
  51. this.state = {
  52. scrollHeight: 0,
  53. parsedEvents: {
  54. day: [],
  55. allDay: []
  56. },
  57. cachedKeys: [],
  58. };
  59. this.dom = React.createRef();
  60. this.scrollDom = React.createRef();
  61. this.isWeekend = false;
  62. }
  63. get adapter(): CalendarAdapter<DayCalendarProps, DayCalendarState> {
  64. return {
  65. ...super.adapter,
  66. updateScrollHeight: scrollHeight => {
  67. this.setState({ scrollHeight });
  68. },
  69. setParsedEvents: (parsedEvents: ParsedEventsType) => {
  70. this.setState({ parsedEvents: parsedEvents as ParsedEventsWithArray });
  71. },
  72. cacheEventKeys: cachedKeys => {
  73. this.setState({ cachedKeys });
  74. },
  75. };
  76. }
  77. componentDidMount() {
  78. this.foundation.init();
  79. const { scrollHeight } = this.scrollDom.current;
  80. this.dom.current.scrollTop = this.props.scrollTop;
  81. this.foundation.notifyScrollHeight(scrollHeight);
  82. this.foundation.parseDailyEvents();
  83. }
  84. componentDidUpdate(prevProps: DayCalendarProps, prevState: DayCalendarState) {
  85. const prevEventKeys = prevState.cachedKeys;
  86. const nowEventKeys = this.props.events.map(event => event.key);
  87. if (!isEqual(prevEventKeys, nowEventKeys)) {
  88. this.foundation.parseDailyEvents();
  89. }
  90. }
  91. componentWillUnmount() {
  92. this.foundation.destroy();
  93. }
  94. checkWeekend = (val: Date) => this.foundation.checkWeekend(val);
  95. renderAllDayEvents = (events: ParsedEventsWithArray['allDay']) => {
  96. const list = events.map((event, ind) => {
  97. const { children, key } = event;
  98. return (
  99. // eslint-disable-next-line max-len
  100. <li className={`${cssClasses.PREFIX}-event-item ${cssClasses.PREFIX}-event-allday`} key={key || `allDay-${ind}`}>
  101. {children}
  102. </li>
  103. );
  104. });
  105. return list;
  106. };
  107. handleClick = (e: React.MouseEvent, val: [Date, number, number, number]) => {
  108. const { onClick } = this.props;
  109. const value = this.foundation.formatCbValue(val);
  110. onClick && onClick(e, value);
  111. };
  112. renderAllDay = (events: ParsedEventsWithArray['allDay']) => {
  113. const allDayCls = `${cssClasses.PREFIX}-all-day`;
  114. const contentCls = cls(`${allDayCls}-content`, {
  115. [`${cssClasses.PREFIX}-weekend`]: this.isWeekend,
  116. });
  117. return (
  118. <LocaleConsumer componentName="Calendar">
  119. {(locale: Locale['Calendar']) => (
  120. <div className={`${allDayCls}`}>
  121. <ul className={`${cssClasses.PREFIX}-tag ${allDayCls}-tag ${prefixCls}-sticky-left`}>
  122. <span>{locale.allDay}</span>
  123. </ul>
  124. <div role="gridcell" className={contentCls}>
  125. <ul className={`${cssClasses.PREFIX}-event-items`}>
  126. {this.renderAllDayEvents(events)}
  127. </ul>
  128. </div>
  129. </div>
  130. )}
  131. </LocaleConsumer>
  132. );
  133. };
  134. render() {
  135. // eslint-disable-next-line max-len
  136. const { dateGridRender, displayValue, showCurrTime, renderTimeDisplay, markWeekend, className, height, width, style, header } = this.props;
  137. const dayCls = cls(prefixCls, className);
  138. const dayStyle = {
  139. height,
  140. width,
  141. ...style,
  142. };
  143. const { parsedEvents, scrollHeight } = this.state;
  144. this.isWeekend = markWeekend && this.checkWeekend(displayValue);
  145. return (
  146. <div className={dayCls} style={dayStyle} ref={this.dom}>
  147. <div className={`${prefixCls}-sticky-top`}>
  148. {header}
  149. {this.renderAllDay(parsedEvents.allDay)}
  150. </div>
  151. <div className={`${prefixCls}-scroll-wrapper`}>
  152. <div className={`${prefixCls}-scroll`} ref={this.scrollDom}>
  153. <TimeCol
  154. className={`${prefixCls}-sticky-left`}
  155. renderTimeDisplay={renderTimeDisplay}
  156. />
  157. <DayCol
  158. events={parsedEvents.day}
  159. displayValue={displayValue}
  160. scrollHeight={scrollHeight}
  161. handleClick={this.handleClick}
  162. showCurrTime={showCurrTime}
  163. isWeekend={this.isWeekend}
  164. dateGridRender={dateGridRender}
  165. />
  166. </div>
  167. </div>
  168. </div>
  169. );
  170. }
  171. }