UNPKG

react-big-calendar

Version:
1,411 lines (1,373 loc) 235 kB
import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2'; import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties'; import _typeof from '@babel/runtime/helpers/esm/typeof'; import _classCallCheck from '@babel/runtime/helpers/esm/classCallCheck'; import _createClass from '@babel/runtime/helpers/esm/createClass'; import _callSuper from '@babel/runtime/helpers/esm/callSuper'; import _inherits from '@babel/runtime/helpers/esm/inherits'; import _slicedToArray from '@babel/runtime/helpers/esm/slicedToArray'; import clsx from 'clsx'; import React, { useEffect, useLayoutEffect, useRef, createRef, Component, useMemo, useState, useCallback } from 'react'; import { uncontrollable } from 'uncontrollable'; import PropTypes from 'prop-types'; import invariant from 'invariant'; import * as dates from 'date-arithmetic'; import { inRange as inRange$1, lt, lte, gt, gte, eq, neq, startOf, endOf, add, min, max, minutes } from 'date-arithmetic'; import _defineProperty from '@babel/runtime/helpers/esm/defineProperty'; import _toConsumableArray from '@babel/runtime/helpers/esm/toConsumableArray'; import chunk from 'lodash/chunk'; import getPosition$1 from 'dom-helpers/position'; import * as animationFrame from 'dom-helpers/animationFrame'; import { Overlay } from 'react-overlays'; import getOffset from 'dom-helpers/offset'; import isEqual$1 from 'lodash/isEqual'; import getHeight from 'dom-helpers/height'; import qsa from 'dom-helpers/querySelectorAll'; import contains from 'dom-helpers/contains'; import closest from 'dom-helpers/closest'; import listen from 'dom-helpers/listen'; import findIndex from 'lodash/findIndex'; import range$1 from 'lodash/range'; import memoize from 'memoize-one'; import getWidth from 'dom-helpers/width'; import sortBy from 'lodash/sortBy'; import scrollbarSize from 'dom-helpers/scrollbarSize'; import _toArray from '@babel/runtime/helpers/esm/toArray'; import addClass from 'dom-helpers/addClass'; import removeClass from 'dom-helpers/removeClass'; import defaults from 'lodash/defaults'; import mapValues from 'lodash/mapValues'; import omit from 'lodash/omit'; import transform from 'lodash/transform'; import isBetween from 'dayjs/plugin/isBetween'; import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'; import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; import localeData from 'dayjs/plugin/localeData'; import localizedFormat from 'dayjs/plugin/localizedFormat'; import minMax from 'dayjs/plugin/minMax'; import utc from 'dayjs/plugin/utc'; import isLeapYear from 'dayjs/plugin/isLeapYear'; function NoopWrapper(props) { return props.children; } var navigate = { PREVIOUS: 'PREV', NEXT: 'NEXT', TODAY: 'TODAY', DATE: 'DATE' }; var views = { MONTH: 'month', WEEK: 'week', WORK_WEEK: 'work_week', DAY: 'day', AGENDA: 'agenda' }; var viewNames$1 = Object.keys(views).map(function (k) { return views[k]; }); PropTypes.oneOfType([PropTypes.string, PropTypes.func]); PropTypes.any; PropTypes.func; /** * accepts either an array of builtin view names: * * ``` * views={['month', 'day', 'agenda']} * ``` * * or an object hash of the view name and the component (or boolean for builtin) * * ``` * views={{ * month: true, * week: false, * workweek: WorkWeekViewComponent, * }} * ``` */ PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOf(viewNames$1)), PropTypes.objectOf(function (prop, key) { var isBuiltinView = viewNames$1.indexOf(key) !== -1 && typeof prop[key] === 'boolean'; if (isBuiltinView) { return null; } else { for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } return PropTypes.elementType.apply(PropTypes, [prop, key].concat(args)); } })]); PropTypes.oneOfType([PropTypes.oneOf(['overlap', 'no-overlap']), PropTypes.func]); /* eslint no-fallthrough: off */ var MILLI = { seconds: 1000, minutes: 1000 * 60, hours: 1000 * 60 * 60, day: 1000 * 60 * 60 * 24 }; function firstVisibleDay(date, localizer) { var firstOfMonth = dates.startOf(date, 'month'); return dates.startOf(firstOfMonth, 'week', localizer.startOfWeek()); } function lastVisibleDay(date, localizer) { var endOfMonth = dates.endOf(date, 'month'); return dates.endOf(endOfMonth, 'week', localizer.startOfWeek()); } function visibleDays(date, localizer) { var current = firstVisibleDay(date, localizer), last = lastVisibleDay(date, localizer), days = []; while (dates.lte(current, last, 'day')) { days.push(current); current = dates.add(current, 1, 'day'); } return days; } function ceil(date, unit) { var floor = dates.startOf(date, unit); return dates.eq(floor, date) ? floor : dates.add(floor, 1, unit); } function range(start, end) { var unit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'day'; var current = start, days = []; while (dates.lte(current, end, unit)) { days.push(current); current = dates.add(current, 1, unit); } return days; } function merge(date, time) { if (time == null && date == null) return null; if (time == null) time = new Date(); if (date == null) date = new Date(); date = dates.startOf(date, 'day'); date = dates.hours(date, dates.hours(time)); date = dates.minutes(date, dates.minutes(time)); date = dates.seconds(date, dates.seconds(time)); return dates.milliseconds(date, dates.milliseconds(time)); } function isJustDate(date) { return dates.hours(date) === 0 && dates.minutes(date) === 0 && dates.seconds(date) === 0 && dates.milliseconds(date) === 0; } function duration(start, end, unit, firstOfWeek) { if (unit === 'day') unit = 'date'; return Math.abs( // eslint-disable-next-line import/namespace dates[unit](start, undefined, firstOfWeek) - // eslint-disable-next-line import/namespace dates[unit](end, undefined, firstOfWeek)); } function diff(dateA, dateB, unit) { if (!unit || unit === 'milliseconds') return Math.abs(+dateA - +dateB); // the .round() handles an edge case // with DST where the total won't be exact // since one day in the range may be shorter/longer by an hour return Math.round(Math.abs(+dates.startOf(dateA, unit) / MILLI[unit] - +dates.startOf(dateB, unit) / MILLI[unit])); } var localePropType = PropTypes.oneOfType([PropTypes.string, PropTypes.func]); function _format(localizer, formatter, value, format, culture) { var result = typeof format === 'function' ? format(value, culture, localizer) : formatter.call(localizer, value, format, culture); invariant(result == null || typeof result === 'string', '`localizer format(..)` must return a string, null, or undefined'); return result; } /** * This date conversion was moved out of TimeSlots.js, to * allow for localizer override * @param {Date} dt - The date to start from * @param {Number} minutesFromMidnight * @param {Number} offset * @returns {Date} */ function getSlotDate(dt, minutesFromMidnight, offset) { return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(), 0, minutesFromMidnight + offset, 0, 0); } function getDstOffset(start, end) { return start.getTimezoneOffset() - end.getTimezoneOffset(); } // if the start is on a DST-changing day but *after* the moment of DST // transition we need to add those extra minutes to our minutesFromMidnight function getTotalMin(start, end) { return diff(start, end, 'minutes') + getDstOffset(start, end); } function getMinutesFromMidnight(start) { var daystart = startOf(start, 'day'); return diff(daystart, start, 'minutes') + getDstOffset(daystart, start); } // These two are used by DateSlotMetrics function continuesPrior(start, first) { return lt(start, first, 'day'); } function continuesAfter(start, end, last) { var singleDayDuration = eq(start, end, 'minutes'); return singleDayDuration ? gte(end, last, 'minutes') : gt(end, last, 'minutes'); } function daySpan(start, end) { return duration(start, end, 'day'); } // These two are used by eventLevels function sortEvents$1(_ref) { var _ref$evtA = _ref.evtA, aStart = _ref$evtA.start, aEnd = _ref$evtA.end, aAllDay = _ref$evtA.allDay, _ref$evtB = _ref.evtB, bStart = _ref$evtB.start, bEnd = _ref$evtB.end, bAllDay = _ref$evtB.allDay; var startSort = +startOf(aStart, 'day') - +startOf(bStart, 'day'); var durA = daySpan(aStart, aEnd); var durB = daySpan(bStart, bEnd); return startSort || // sort by start Day first durB - durA || // events spanning multiple days go first !!bAllDay - !!aAllDay || // then allDay single day events +aStart - +bStart || // then sort by start time +aEnd - +bEnd // then sort by end time ; } function inEventRange(_ref2) { var _ref2$event = _ref2.event, start = _ref2$event.start, end = _ref2$event.end, _ref2$range = _ref2.range, rangeStart = _ref2$range.start, rangeEnd = _ref2$range.end; var eStart = startOf(start, 'day'); var startsBeforeEnd = lte(eStart, rangeEnd, 'day'); // when the event is zero duration we need to handle a bit differently var sameMin = neq(eStart, end, 'minutes'); var endsAfterStart = sameMin ? gt(end, rangeStart, 'minutes') : gte(end, rangeStart, 'minutes'); return startsBeforeEnd && endsAfterStart; } // other localizers treats 'day' and 'date' equality very differently, so we // abstract the change the 'localizer.eq(date1, date2, 'day') into this // new method, where they can be treated correctly by the localizer overrides function isSameDate(date1, date2) { return eq(date1, date2, 'day'); } function startAndEndAreDateOnly(start, end) { return isJustDate(start) && isJustDate(end); } var DateLocalizer = /*#__PURE__*/_createClass(function DateLocalizer(spec) { var _this = this; _classCallCheck(this, DateLocalizer); invariant(typeof spec.format === 'function', 'date localizer `format(..)` must be a function'); invariant(typeof spec.firstOfWeek === 'function', 'date localizer `firstOfWeek(..)` must be a function'); this.propType = spec.propType || localePropType; this.formats = spec.formats; this.format = function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _format.apply(void 0, [_this, spec.format].concat(args)); }; // These date arithmetic methods can be overriden by the localizer this.startOfWeek = spec.firstOfWeek; this.merge = spec.merge || merge; this.inRange = spec.inRange || inRange$1; this.lt = spec.lt || lt; this.lte = spec.lte || lte; this.gt = spec.gt || gt; this.gte = spec.gte || gte; this.eq = spec.eq || eq; this.neq = spec.neq || neq; this.startOf = spec.startOf || startOf; this.endOf = spec.endOf || endOf; this.add = spec.add || add; this.range = spec.range || range; this.diff = spec.diff || diff; this.ceil = spec.ceil || ceil; this.min = spec.min || min; this.max = spec.max || max; this.minutes = spec.minutes || minutes; this.daySpan = spec.daySpan || daySpan; this.firstVisibleDay = spec.firstVisibleDay || firstVisibleDay; this.lastVisibleDay = spec.lastVisibleDay || lastVisibleDay; this.visibleDays = spec.visibleDays || visibleDays; this.getSlotDate = spec.getSlotDate || getSlotDate; this.getTimezoneOffset = spec.getTimezoneOffset || function (value) { return value.getTimezoneOffset(); }; this.getDstOffset = spec.getDstOffset || getDstOffset; this.getTotalMin = spec.getTotalMin || getTotalMin; this.getMinutesFromMidnight = spec.getMinutesFromMidnight || getMinutesFromMidnight; this.continuesPrior = spec.continuesPrior || continuesPrior; this.continuesAfter = spec.continuesAfter || continuesAfter; this.sortEvents = spec.sortEvents || sortEvents$1; this.inEventRange = spec.inEventRange || inEventRange; this.isSameDate = spec.isSameDate || isSameDate; this.startAndEndAreDateOnly = spec.startAndEndAreDateOnly || startAndEndAreDateOnly; this.segmentOffset = spec.browserTZOffset ? spec.browserTZOffset() : 0; }); function mergeWithDefaults(localizer, culture, formatOverrides, messages) { var formats = _objectSpread(_objectSpread({}, localizer.formats), formatOverrides); return _objectSpread(_objectSpread({}, localizer), {}, { messages: messages, startOfWeek: function startOfWeek() { return localizer.startOfWeek(culture); }, format: function format(value, _format2) { return localizer.format(value, formats[_format2] || _format2, culture); } }); } var Toolbar = /*#__PURE__*/function (_React$Component) { function Toolbar() { var _this; _classCallCheck(this, Toolbar); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, Toolbar, [].concat(args)); _this.navigate = function (action) { _this.props.onNavigate(action); }; _this.view = function (view) { _this.props.onView(view); }; return _this; } _inherits(Toolbar, _React$Component); return _createClass(Toolbar, [{ key: "render", value: function render() { var _this$props = this.props, messages = _this$props.localizer.messages, label = _this$props.label; return /*#__PURE__*/React.createElement("div", { className: "rbc-toolbar" }, /*#__PURE__*/React.createElement("span", { className: "rbc-btn-group" }, /*#__PURE__*/React.createElement("button", { type: "button", onClick: this.navigate.bind(null, navigate.TODAY) }, messages.today), /*#__PURE__*/React.createElement("button", { type: "button", onClick: this.navigate.bind(null, navigate.PREVIOUS) }, messages.previous), /*#__PURE__*/React.createElement("button", { type: "button", onClick: this.navigate.bind(null, navigate.NEXT) }, messages.next)), /*#__PURE__*/React.createElement("span", { className: "rbc-toolbar-label" }, label), /*#__PURE__*/React.createElement("span", { className: "rbc-btn-group" }, this.viewNamesGroup(messages))); } }, { key: "viewNamesGroup", value: function viewNamesGroup(messages) { var _this2 = this; var viewNames = this.props.views; var view = this.props.view; if (viewNames.length > 1) { return viewNames.map(function (name) { return /*#__PURE__*/React.createElement("button", { type: "button", key: name, className: clsx({ 'rbc-active': view === name }), onClick: _this2.view.bind(null, name) }, messages[name]); }); } } }]); }(React.Component); function notify(handler, args) { handler && handler.apply(null, [].concat(args)); } var defaultMessages = { date: 'Date', time: 'Time', event: 'Event', allDay: 'All Day', week: 'Week', work_week: 'Work Week', day: 'Day', month: 'Month', previous: 'Back', next: 'Next', yesterday: 'Yesterday', tomorrow: 'Tomorrow', today: 'Today', agenda: 'Agenda', noEventsInRange: 'There are no events in this range.', showMore: function showMore(total) { return "+".concat(total, " more"); } }; function messages(msgs) { return _objectSpread(_objectSpread({}, defaultMessages), msgs); } function useClickOutside(_ref) { var ref = _ref.ref, callback = _ref.callback; useEffect(function () { var handleClickOutside = function handleClickOutside(e) { if (ref.current && !ref.current.contains(e.target)) { callback(); } }; document.addEventListener('mousedown', handleClickOutside); return function () { document.removeEventListener('mousedown', handleClickOutside); }; }, [ref, callback]); } var _excluded$7 = ["style", "className", "event", "selected", "isAllDay", "onSelect", "onDoubleClick", "onKeyPress", "localizer", "continuesPrior", "continuesAfter", "accessors", "getters", "children", "components", "slotStart", "slotEnd"]; var EventCell = /*#__PURE__*/function (_React$Component) { function EventCell() { _classCallCheck(this, EventCell); return _callSuper(this, EventCell, arguments); } _inherits(EventCell, _React$Component); return _createClass(EventCell, [{ key: "render", value: function render() { var _this$props = this.props, style = _this$props.style, className = _this$props.className, event = _this$props.event, selected = _this$props.selected, isAllDay = _this$props.isAllDay, onSelect = _this$props.onSelect, _onDoubleClick = _this$props.onDoubleClick, onKeyPress = _this$props.onKeyPress, localizer = _this$props.localizer, continuesPrior = _this$props.continuesPrior, continuesAfter = _this$props.continuesAfter, accessors = _this$props.accessors, getters = _this$props.getters, children = _this$props.children, _this$props$component = _this$props.components, Event = _this$props$component.event, EventWrapper = _this$props$component.eventWrapper, slotStart = _this$props.slotStart, slotEnd = _this$props.slotEnd, props = _objectWithoutProperties(_this$props, _excluded$7); delete props.resizable; var title = accessors.title(event); var tooltip = accessors.tooltip(event); var end = accessors.end(event); var start = accessors.start(event); var allDay = accessors.allDay(event); var showAsAllDay = isAllDay || allDay || localizer.diff(start, localizer.ceil(end, 'day'), 'day') > 1; var userProps = getters.eventProp(event, start, end, selected); var content = /*#__PURE__*/React.createElement("div", { className: "rbc-event-content", title: tooltip || undefined }, Event ? /*#__PURE__*/React.createElement(Event, { event: event, continuesPrior: continuesPrior, continuesAfter: continuesAfter, title: title, isAllDay: allDay, localizer: localizer, slotStart: slotStart, slotEnd: slotEnd }) : title); return /*#__PURE__*/React.createElement(EventWrapper, Object.assign({}, this.props, { type: "date" }), /*#__PURE__*/React.createElement("div", Object.assign({}, props, { style: _objectSpread(_objectSpread({}, userProps.style), style), className: clsx('rbc-event', className, userProps.className, { 'rbc-selected': selected, 'rbc-event-allday': showAsAllDay, 'rbc-event-continues-prior': continuesPrior, 'rbc-event-continues-after': continuesAfter }), onClick: function onClick(e) { return onSelect && onSelect(event, e); }, onDoubleClick: function onDoubleClick(e) { return _onDoubleClick && _onDoubleClick(event, e); }, onKeyDown: function onKeyDown(e) { return onKeyPress && onKeyPress(event, e); } }), typeof children === 'function' ? children(content) : content)); } }]); }(React.Component); function isSelected(event, selected) { if (!event || selected == null) return false; return isEqual$1(event, selected); } function slotWidth(rowBox, slots) { var rowWidth = rowBox.right - rowBox.left; var cellWidth = rowWidth / slots; return cellWidth; } function getSlotAtX(rowBox, x, rtl, slots) { var cellWidth = slotWidth(rowBox, slots); return rtl ? slots - 1 - Math.floor((x - rowBox.left) / cellWidth) : Math.floor((x - rowBox.left) / cellWidth); } function pointInBox(box, _ref) { var x = _ref.x, y = _ref.y; return y >= box.top && y <= box.bottom && x >= box.left && x <= box.right; } function dateCellSelection(start, rowBox, box, slots, rtl) { var startIdx = -1; var endIdx = -1; var lastSlotIdx = slots - 1; var cellWidth = slotWidth(rowBox, slots); // cell under the mouse var currentSlot = getSlotAtX(rowBox, box.x, rtl, slots); // Identify row as either the initial row // or the row under the current mouse point var isCurrentRow = rowBox.top < box.y && rowBox.bottom > box.y; var isStartRow = rowBox.top < start.y && rowBox.bottom > start.y; // this row's position relative to the start point var isAboveStart = start.y > rowBox.bottom; var isBelowStart = rowBox.top > start.y; var isBetween = box.top < rowBox.top && box.bottom > rowBox.bottom; // this row is between the current and start rows, so entirely selected if (isBetween) { startIdx = 0; endIdx = lastSlotIdx; } if (isCurrentRow) { if (isBelowStart) { startIdx = 0; endIdx = currentSlot; } else if (isAboveStart) { startIdx = currentSlot; endIdx = lastSlotIdx; } } if (isStartRow) { // select the cell under the initial point startIdx = endIdx = rtl ? lastSlotIdx - Math.floor((start.x - rowBox.left) / cellWidth) : Math.floor((start.x - rowBox.left) / cellWidth); if (isCurrentRow) { if (currentSlot < startIdx) startIdx = currentSlot;else endIdx = currentSlot; //select current range } else if (start.y < box.y) { // the current row is below start row // select cells to the right of the start cell endIdx = lastSlotIdx; } else { // select cells to the left of the start cell startIdx = 0; } } return { startIdx: startIdx, endIdx: endIdx }; } /** * Changes to react-overlays cause issue with auto positioning, * so we need to manually calculate the position of the popper, * and constrain it to the Month container. */ function getPosition(_ref) { var target = _ref.target, offset = _ref.offset, container = _ref.container, box = _ref.box; var _getOffset = getOffset(target), top = _getOffset.top, left = _getOffset.left, width = _getOffset.width, height = _getOffset.height; var _getOffset2 = getOffset(container), cTop = _getOffset2.top, cLeft = _getOffset2.left, cWidth = _getOffset2.width, cHeight = _getOffset2.height; var _getOffset3 = getOffset(box), bWidth = _getOffset3.width, bHeight = _getOffset3.height; var viewBottom = cTop + cHeight; var viewRight = cLeft + cWidth; var bottom = top + bHeight; var right = left + bWidth; var x = offset.x, y = offset.y; var topOffset = bottom > viewBottom ? top - bHeight - y : top + y + height; var leftOffset = right > viewRight ? left + x - bWidth + width : left + x; return { topOffset: topOffset, leftOffset: leftOffset }; } function Pop(_ref2) { var containerRef = _ref2.containerRef, accessors = _ref2.accessors, getters = _ref2.getters, selected = _ref2.selected, components = _ref2.components, localizer = _ref2.localizer, position = _ref2.position, show = _ref2.show, events = _ref2.events, slotStart = _ref2.slotStart, slotEnd = _ref2.slotEnd, onSelect = _ref2.onSelect, onDoubleClick = _ref2.onDoubleClick, onKeyPress = _ref2.onKeyPress, handleDragStart = _ref2.handleDragStart, popperRef = _ref2.popperRef, target = _ref2.target, offset = _ref2.offset; useClickOutside({ ref: popperRef, callback: show }); useLayoutEffect(function () { var _getPosition = getPosition({ target: target, offset: offset, container: containerRef.current, box: popperRef.current }), topOffset = _getPosition.topOffset, leftOffset = _getPosition.leftOffset; popperRef.current.style.top = "".concat(topOffset, "px"); popperRef.current.style.left = "".concat(leftOffset, "px"); // eslint-disable-next-line react-hooks/exhaustive-deps }, [offset.x, offset.y, target]); var width = position.width; var style = { minWidth: width + width / 2 }; return /*#__PURE__*/React.createElement("div", { style: style, className: "rbc-overlay", ref: popperRef }, /*#__PURE__*/React.createElement("div", { className: "rbc-overlay-header" }, localizer.format(slotStart, 'dayHeaderFormat')), events.map(function (event, idx) { return /*#__PURE__*/React.createElement(EventCell, { key: idx, type: "popup", localizer: localizer, event: event, getters: getters, onSelect: onSelect, accessors: accessors, components: components, onDoubleClick: onDoubleClick, onKeyPress: onKeyPress, continuesPrior: localizer.lt(accessors.end(event), slotStart, 'day'), continuesAfter: localizer.gte(accessors.start(event), slotEnd, 'day'), slotStart: slotStart, slotEnd: slotEnd, selected: isSelected(event, selected), draggable: true, onDragStart: function onDragStart() { return handleDragStart(event); }, onDragEnd: function onDragEnd() { return show(); } }); })); } var Popup = /*#__PURE__*/React.forwardRef(function (props, ref) { return /*#__PURE__*/React.createElement(Pop, Object.assign({}, props, { popperRef: ref })); }); Popup.propTypes = { accessors: PropTypes.object.isRequired, getters: PropTypes.object.isRequired, selected: PropTypes.object, components: PropTypes.object.isRequired, localizer: PropTypes.object.isRequired, position: PropTypes.object.isRequired, show: PropTypes.func.isRequired, events: PropTypes.array.isRequired, slotStart: PropTypes.instanceOf(Date).isRequired, slotEnd: PropTypes.instanceOf(Date), onSelect: PropTypes.func, onDoubleClick: PropTypes.func, onKeyPress: PropTypes.func, handleDragStart: PropTypes.func, style: PropTypes.object, offset: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }) }; function CalOverlay(_ref) { var containerRef = _ref.containerRef, _ref$popupOffset = _ref.popupOffset, popupOffset = _ref$popupOffset === void 0 ? 5 : _ref$popupOffset, overlay = _ref.overlay, accessors = _ref.accessors, localizer = _ref.localizer, components = _ref.components, getters = _ref.getters, selected = _ref.selected, handleSelectEvent = _ref.handleSelectEvent, handleDoubleClickEvent = _ref.handleDoubleClickEvent, handleKeyPressEvent = _ref.handleKeyPressEvent, handleDragStart = _ref.handleDragStart, onHide = _ref.onHide, overlayDisplay = _ref.overlayDisplay; var popperRef = useRef(null); if (!overlay.position) return null; var offset = popupOffset; if (!isNaN(popupOffset)) { offset = { x: popupOffset, y: popupOffset }; } var position = overlay.position, events = overlay.events, date = overlay.date, end = overlay.end; return /*#__PURE__*/React.createElement(Overlay, { rootClose: true, flip: true, show: true, placement: "bottom", onHide: onHide, target: overlay.target }, function (_ref2) { var props = _ref2.props; return /*#__PURE__*/React.createElement(Popup, Object.assign({}, props, { containerRef: containerRef, ref: popperRef, target: overlay.target, offset: offset, accessors: accessors, getters: getters, selected: selected, components: components, localizer: localizer, position: position, show: overlayDisplay, events: events, slotStart: date, slotEnd: end, onSelect: handleSelectEvent, onDoubleClick: handleDoubleClickEvent, onKeyPress: handleKeyPressEvent, handleDragStart: handleDragStart })); }); } var PopOverlay = /*#__PURE__*/React.forwardRef(function (props, ref) { return /*#__PURE__*/React.createElement(CalOverlay, Object.assign({}, props, { containerRef: ref })); }); PopOverlay.propTypes = { popupOffset: PropTypes.oneOfType([PropTypes.number, PropTypes.shape({ x: PropTypes.number, y: PropTypes.number })]), overlay: PropTypes.shape({ position: PropTypes.object, events: PropTypes.array, date: PropTypes.instanceOf(Date), end: PropTypes.instanceOf(Date) }), accessors: PropTypes.object.isRequired, localizer: PropTypes.object.isRequired, components: PropTypes.object.isRequired, getters: PropTypes.object.isRequired, selected: PropTypes.object, handleSelectEvent: PropTypes.func, handleDoubleClickEvent: PropTypes.func, handleKeyPressEvent: PropTypes.func, handleDragStart: PropTypes.func, onHide: PropTypes.func, overlayDisplay: PropTypes.func }; function addEventListener(type, handler) { var target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : document; return listen(target, type, handler, { passive: false }); } function isOverContainer(container, x, y) { return !container || contains(container, document.elementFromPoint(x, y)); } function getEventNodeFromPoint(node, _ref) { var clientX = _ref.clientX, clientY = _ref.clientY; var target = document.elementFromPoint(clientX, clientY); return closest(target, '.rbc-event', node); } function getShowMoreNodeFromPoint(node, _ref2) { var clientX = _ref2.clientX, clientY = _ref2.clientY; var target = document.elementFromPoint(clientX, clientY); return closest(target, '.rbc-show-more', node); } function isEvent(node, bounds) { return !!getEventNodeFromPoint(node, bounds); } function isShowMore(node, bounds) { return !!getShowMoreNodeFromPoint(node, bounds); } function getEventCoordinates(e) { var target = e; if (e.touches && e.touches.length) { target = e.touches[0]; } return { clientX: target.clientX, clientY: target.clientY, pageX: target.pageX, pageY: target.pageY }; } var clickTolerance = 5; var clickInterval = 250; var Selection = /*#__PURE__*/function () { function Selection(node) { var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, _ref3$global = _ref3.global, global = _ref3$global === void 0 ? false : _ref3$global, _ref3$longPressThresh = _ref3.longPressThreshold, longPressThreshold = _ref3$longPressThresh === void 0 ? 250 : _ref3$longPressThresh, _ref3$validContainers = _ref3.validContainers, validContainers = _ref3$validContainers === void 0 ? [] : _ref3$validContainers; _classCallCheck(this, Selection); this._initialEvent = null; this.selecting = false; this.isDetached = false; this.container = node; this.globalMouse = !node || global; this.longPressThreshold = longPressThreshold; this.validContainers = validContainers; this._listeners = Object.create(null); this._handleInitialEvent = this._handleInitialEvent.bind(this); this._handleMoveEvent = this._handleMoveEvent.bind(this); this._handleTerminatingEvent = this._handleTerminatingEvent.bind(this); this._keyListener = this._keyListener.bind(this); this._dropFromOutsideListener = this._dropFromOutsideListener.bind(this); this._dragOverFromOutsideListener = this._dragOverFromOutsideListener.bind(this); // Fixes an iOS 10 bug where scrolling could not be prevented on the window. // https://github.com/metafizzy/flickity/issues/457#issuecomment-254501356 this._removeTouchMoveWindowListener = addEventListener('touchmove', function () {}, window); this._removeKeyDownListener = addEventListener('keydown', this._keyListener); this._removeKeyUpListener = addEventListener('keyup', this._keyListener); this._removeDropFromOutsideListener = addEventListener('drop', this._dropFromOutsideListener); this._removeDragOverFromOutsideListener = addEventListener('dragover', this._dragOverFromOutsideListener); this._addInitialEventListener(); } return _createClass(Selection, [{ key: "on", value: function on(type, handler) { var handlers = this._listeners[type] || (this._listeners[type] = []); handlers.push(handler); return { remove: function remove() { var idx = handlers.indexOf(handler); if (idx !== -1) handlers.splice(idx, 1); } }; } }, { key: "emit", value: function emit(type) { for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } var result; var handlers = this._listeners[type] || []; handlers.forEach(function (fn) { if (result === undefined) result = fn.apply(void 0, args); }); return result; } }, { key: "teardown", value: function teardown() { this._initialEvent = null; this._initialEventData = null; this._selectRect = null; this.selecting = false; this._lastClickData = null; this.isDetached = true; this._listeners = Object.create(null); this._removeTouchMoveWindowListener && this._removeTouchMoveWindowListener(); this._removeInitialEventListener && this._removeInitialEventListener(); this._removeEndListener && this._removeEndListener(); this._onEscListener && this._onEscListener(); this._removeMoveListener && this._removeMoveListener(); this._removeKeyUpListener && this._removeKeyUpListener(); this._removeKeyDownListener && this._removeKeyDownListener(); this._removeDropFromOutsideListener && this._removeDropFromOutsideListener(); this._removeDragOverFromOutsideListener && this._removeDragOverFromOutsideListener(); } }, { key: "isSelected", value: function isSelected(node) { var box = this._selectRect; if (!box || !this.selecting) return false; return objectsCollide(box, getBoundsForNode(node)); } }, { key: "filter", value: function filter(items) { var box = this._selectRect; //not selecting if (!box || !this.selecting) return []; return items.filter(this.isSelected, this); } // Adds a listener that will call the handler only after the user has pressed on the screen // without moving their finger for 250ms. }, { key: "_addLongPressListener", value: function _addLongPressListener(handler, initialEvent) { var _this = this; var timer = null; var removeTouchMoveListener = null; var removeTouchEndListener = null; var handleTouchStart = function handleTouchStart(initialEvent) { timer = setTimeout(function () { cleanup(); handler(initialEvent); }, _this.longPressThreshold); removeTouchMoveListener = addEventListener('touchmove', function () { return cleanup(); }); removeTouchEndListener = addEventListener('touchend', function () { return cleanup(); }); }; var removeTouchStartListener = addEventListener('touchstart', handleTouchStart); var cleanup = function cleanup() { if (timer) { clearTimeout(timer); } if (removeTouchMoveListener) { removeTouchMoveListener(); } if (removeTouchEndListener) { removeTouchEndListener(); } timer = null; removeTouchMoveListener = null; removeTouchEndListener = null; }; if (initialEvent) { handleTouchStart(initialEvent); } return function () { cleanup(); removeTouchStartListener(); }; } // Listen for mousedown and touchstart events. When one is received, disable the other and setup // future event handling based on the type of event. }, { key: "_addInitialEventListener", value: function _addInitialEventListener() { var _this2 = this; var removeMouseDownListener = addEventListener('mousedown', function (e) { _this2._removeInitialEventListener(); _this2._handleInitialEvent(e); _this2._removeInitialEventListener = addEventListener('mousedown', _this2._handleInitialEvent); }); var removeTouchStartListener = addEventListener('touchstart', function (e) { _this2._removeInitialEventListener(); _this2._removeInitialEventListener = _this2._addLongPressListener(_this2._handleInitialEvent, e); }); this._removeInitialEventListener = function () { removeMouseDownListener(); removeTouchStartListener(); }; } }, { key: "_dropFromOutsideListener", value: function _dropFromOutsideListener(e) { var _getEventCoordinates = getEventCoordinates(e), pageX = _getEventCoordinates.pageX, pageY = _getEventCoordinates.pageY, clientX = _getEventCoordinates.clientX, clientY = _getEventCoordinates.clientY; this.emit('dropFromOutside', { x: pageX, y: pageY, clientX: clientX, clientY: clientY }); e.preventDefault(); } }, { key: "_dragOverFromOutsideListener", value: function _dragOverFromOutsideListener(e) { var _getEventCoordinates2 = getEventCoordinates(e), pageX = _getEventCoordinates2.pageX, pageY = _getEventCoordinates2.pageY, clientX = _getEventCoordinates2.clientX, clientY = _getEventCoordinates2.clientY; this.emit('dragOverFromOutside', { x: pageX, y: pageY, clientX: clientX, clientY: clientY }); e.preventDefault(); } }, { key: "_handleInitialEvent", value: function _handleInitialEvent(e) { this._initialEvent = e; if (this.isDetached) { return; } var _getEventCoordinates3 = getEventCoordinates(e), clientX = _getEventCoordinates3.clientX, clientY = _getEventCoordinates3.clientY, pageX = _getEventCoordinates3.pageX, pageY = _getEventCoordinates3.pageY; var node = this.container(), collides, offsetData; // Right clicks if (e.which === 3 || e.button === 2 || !isOverContainer(node, clientX, clientY)) return; if (!this.globalMouse && node && !contains(node, e.target)) { var _normalizeDistance = normalizeDistance(0), top = _normalizeDistance.top, left = _normalizeDistance.left, bottom = _normalizeDistance.bottom, right = _normalizeDistance.right; offsetData = getBoundsForNode(node); collides = objectsCollide({ top: offsetData.top - top, left: offsetData.left - left, bottom: offsetData.bottom + bottom, right: offsetData.right + right }, { top: pageY, left: pageX }); if (!collides) return; } var result = this.emit('beforeSelect', this._initialEventData = { isTouch: /^touch/.test(e.type), x: pageX, y: pageY, clientX: clientX, clientY: clientY }); if (result === false) return; switch (e.type) { case 'mousedown': this._removeEndListener = addEventListener('mouseup', this._handleTerminatingEvent); this._onEscListener = addEventListener('keydown', this._handleTerminatingEvent); this._removeMoveListener = addEventListener('mousemove', this._handleMoveEvent); break; case 'touchstart': this._handleMoveEvent(e); this._removeEndListener = addEventListener('touchend', this._handleTerminatingEvent); this._removeMoveListener = addEventListener('touchmove', this._handleMoveEvent); break; } } // Check whether provided event target element // - is contained within a valid container }, { key: "_isWithinValidContainer", value: function _isWithinValidContainer(e) { var eventTarget = e.target; var containers = this.validContainers; if (!containers || !containers.length || !eventTarget) { return true; } return containers.some(function (target) { return !!eventTarget.closest(target); }); } }, { key: "_handleTerminatingEvent", value: function _handleTerminatingEvent(e) { var selecting = this.selecting; var bounds = this._selectRect; // If it's not in selecting state, it's a click event if (!selecting && e.type.includes('key')) { e = this._initialEvent; } this.selecting = false; this._removeEndListener && this._removeEndListener(); this._removeMoveListener && this._removeMoveListener(); this._selectRect = null; this._initialEvent = null; this._initialEventData = null; if (!e) return; var inRoot = !this.container || contains(this.container(), e.target); var isWithinValidContainer = this._isWithinValidContainer(e); if (e.key === 'Escape' || !isWithinValidContainer) { return this.emit('reset'); } if (!selecting && inRoot) { return this._handleClickEvent(e); } // User drag-clicked in the Selectable area if (selecting) return this.emit('select', bounds); return this.emit('reset'); } }, { key: "_handleClickEvent", value: function _handleClickEvent(e) { var _getEventCoordinates4 = getEventCoordinates(e), pageX = _getEventCoordinates4.pageX, pageY = _getEventCoordinates4.pageY, clientX = _getEventCoordinates4.clientX, clientY = _getEventCoordinates4.clientY; var now = new Date().getTime(); if (this._lastClickData && now - this._lastClickData.timestamp < clickInterval) { // Double click event this._lastClickData = null; return this.emit('doubleClick', { x: pageX, y: pageY, clientX: clientX, clientY: clientY }); } // Click event this._lastClickData = { timestamp: now }; return this.emit('click', { x: pageX, y: pageY, clientX: clientX, clientY: clientY }); } }, { key: "_handleMoveEvent", value: function _handleMoveEvent(e) { if (this._initialEventData === null || this.isDetached) { return; } var _this$_initialEventDa = this._initialEventData, x = _this$_initialEventDa.x, y = _this$_initialEventDa.y; var _getEventCoordinates5 = getEventCoordinates(e), pageX = _getEventCoordinates5.pageX, pageY = _getEventCoordinates5.pageY; var w = Math.abs(x - pageX); var h = Math.abs(y - pageY); var left = Math.min(pageX, x), top = Math.min(pageY, y), old = this.selecting; var click = this.isClick(pageX, pageY); // Prevent emitting selectStart event until mouse is moved. // in Chrome on Windows, mouseMove event may be fired just after mouseDown event. if (click && !old && !(w || h)) { return; } if (!old && !click) { this.emit('selectStart', this._initialEventData); } if (!click) { this.selecting = true; this._selectRect = { top: top, left: left, x: pageX, y: pageY, right: left + w, bottom: top + h }; this.emit('selecting', this._selectRect); } e.preventDefault(); } }, { key: "_keyListener", value: function _keyListener(e) { this.ctrl = e.metaKey || e.ctrlKey; } }, { key: "isClick", value: function isClick(pageX, pageY) { var _this$_initialEventDa2 = this._initialEventData, x = _this$_initialEventDa2.x, y = _this$_initialEventDa2.y, isTouch = _this$_initialEventDa2.isTouch; return !isTouch && Math.abs(pageX - x) <= clickTolerance && Math.abs(pageY - y) <= clickTolerance; } }]); }(); /** * Resolve the disance prop from either an Int or an Object * @return {Object} */ function normalizeDistance() { var distance = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; if (_typeof(distance) !== 'object') distance = { top: distance, left: distance, right: distance, bottom: distance }; return distance; } /** * Given two objects containing "top", "left", "offsetWidth" and "offsetHeight" * properties, determine if they collide. * @param {Object|HTMLElement} a * @param {Object|HTMLElement} b * @return {bool} */ function objectsCollide(nodeA, nodeB) { var tolerance = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; var _getBoundsForNode = getBoundsForNode(nodeA), aTop = _getBoundsForNode.top, aLeft = _getBoundsForNode.left, _getBoundsForNode$rig = _getBoundsForNode.right, aRight = _getBoundsForNode$rig === void 0 ? aLeft : _getBoundsForNode$rig, _getBoundsForNode$bot = _getBoundsForNode.bottom, aBottom = _getBoundsForNode$bot === void 0 ? aTop : _getBoundsForNode$bot; var _getBoundsForNode2 = getBoundsForNode(nodeB), bTop = _getBoundsForNode2.top, bLeft = _getBoundsForNode2.left, _getBoundsForNode2$ri = _getBoundsForNode2.right, bRight = _getBoundsForNode2$ri === void 0 ? bLeft : _getBoundsForNode2$ri, _getBoundsForNode2$bo = _getBoundsForNode2.bottom, bBottom = _getBoundsForNode2$bo === void 0 ? bTop : _getBoundsForNode2$bo; return !( // 'a' bottom doesn't touch 'b' top aBottom - tolerance < bTop || // 'a' top doesn't touch 'b' bottom aTop + tolerance > bBottom || // 'a' right doesn't touch 'b' left aRight - tolerance < bLeft || // 'a' left doesn't touch 'b' right aLeft + tolerance > bRight); } /** * Given a node, get everything needed to calculate its boundaries * @param {HTMLElement} node * @return {Object} */ function getBoundsForNode(node) { if (!node.getBoundingClientRect) return node; var rect = node.getBoundingClientRect(), left = rect.left + pageOffset('left'), top = rect.top + pageOffset('top'); return { top: top, left: left, right: (node.offsetWidth || 0) + left, bottom: (node.offsetHeight || 0) + top }; } function pageOffset(dir) { if (dir === 'left') return window.pageXOffset || document.body.scrollLeft || 0; if (dir === 'top') return window.pageYOffset || document.body.scrollTop || 0; } var BackgroundCells = /*#__PURE__*/function (_React$Component) { function BackgroundCells(props, context) { var _this; _classCallCheck(this, BackgroundCells); _this = _callSuper(this, BackgroundCells, [props, context]); _this.state = { selecting: false }; _this.containerRef = /*#__PURE__*/createRef(); return _this; } _inherits(BackgroundCells, _React$Component); return _createClass(BackgroundCells, [{ key: "componentDidMount", value: function componentDidMount() { this.props.selectable && this._selectable(); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this._teardownSelectable(); } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (!prevProps.selectable && this.props.selectable) this._selectable(); if (prevProps.selectable && !this.props.selectable) this._teardownSelectable(); } }, { key: "render", value: function render() { var _this$props = this.props, range = _this$props.range, getNow = _this$props.getNow, getters = _this$props.getters, currentDate = _this$props.date, Wrapper = _this$props.components.dateCellWrapper, localizer = _this$props.localizer; var _this$state = this.state, selecting = _this$state.selecting, startIdx = _this$state.startIdx, endIdx = _this$state.endIdx; var current = getNow(); return /*#__PURE__*/React.createElement("div", { className: "rbc-row-bg", ref: this.containerRef }, range.map(function (date, index) { var selected = selecting && index >= startIdx && index <= endIdx; var _getters$dayProp = getters.dayProp(date), className = _getters$dayProp.className, style = _getters$dayProp.style; return /*#__PURE__*/React.createElement(Wrapper, { key: index, value: date, range: range }, /*#__PURE__*/React.createElement("div", { style: style, className: clsx('rbc-day-bg', className, selected && 'rbc-selected-cell', localizer.isSameDate(date, current) && 'rbc-today', currentDate && localizer.neq(currentDate, date, 'month') && 'rbc-off-range-bg') })); })); } }, { key: "_selectable", value: function _selectable() { var _this2 = this; var node = this.containerRef.current; var selector = this._selector = new Selection(this.props.container, { longPressThreshold: this.props.longPressThreshold }); var selectorClicksHandler = function selectorClicksHandler(point, actionType) { if (!isEvent(node, point) && !isShowMore(node, point)) { var rowBox = getBoundsForNode(node); var _this2$props = _this2.props, range = _this2$props.range, rtl = _this2$props.rtl; if (pointInBox(rowBox, point)) { var currentCell = getSlotAtX(rowBox, point.x, rtl, range.length); _this2._selectSlot({ startIdx: currentCell, endIdx: currentCell, action: actionType, box: point }); } } _this2._initial = {}; _this2.setState({ selecting: false }); }; selector.on('selecting', function (box) { var _this2$props2 = _this2.props, range = _this2$props2.range, rtl = _this2$props2.rtl; var startIdx = -1; var endIdx = -1; if (!_this2.state.selecting) { notify(_this2.props.onSelectStart, [box]); _this2._initial = { x: box.x, y: box.y }; } if (selector.isSelected(node)) { var nodeBox = getBoundsForNode(node); var _dateCellSelection = dateCellSelection(_this2._