UNPKG

@fellow/react-big-calendar

Version:
1,605 lines (1,388 loc) 168 kB
import _extends from '@babel/runtime/helpers/esm/extends'; import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/esm/objectWithoutPropertiesLoose'; import _inheritsLoose from '@babel/runtime/helpers/esm/inheritsLoose'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import uncontrollable from 'uncontrollable'; import cn from 'classnames'; import elementType from 'prop-types-extra/lib/elementType'; import all from 'prop-types-extra/lib/all'; import warning from 'warning'; import invariant from 'invariant'; import _assertThisInitialized from '@babel/runtime/helpers/esm/assertThisInitialized'; import { findDOMNode } from 'react-dom'; import dateMath from 'date-arithmetic'; import chunk from 'lodash/chunk'; import getPosition from 'dom-helpers/query/position'; import raf from 'dom-helpers/util/requestAnimationFrame'; import getOffset from 'dom-helpers/query/offset'; import getScrollTop from 'dom-helpers/query/scrollTop'; import getScrollLeft from 'dom-helpers/query/scrollLeft'; import Overlay from 'react-overlays/lib/Overlay'; import getHeight from 'dom-helpers/query/height'; import qsa from 'dom-helpers/query/querySelectorAll'; import contains from 'dom-helpers/query/contains'; import closest from 'dom-helpers/query/closest'; import events from 'dom-helpers/events'; import findIndex from 'lodash/findIndex'; import range from 'lodash/range'; import memoize from 'memoize-one'; import _createClass from '@babel/runtime/helpers/esm/createClass'; import sortBy from 'lodash/sortBy'; import getWidth from 'dom-helpers/query/width'; import scrollbarSize from 'dom-helpers/util/scrollbarSize'; import classes from 'dom-helpers/class'; import omit from 'lodash/omit'; import defaults from 'lodash/defaults'; import transform from 'lodash/transform'; import mapValues from 'lodash/mapValues'; 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 eventComponent = PropTypes.oneOfType([elementType, PropTypes.shape({ month: elementType, week: elementType, day: elementType, agenda: elementType })]); var viewNames = Object.keys(views).map(function (k) { return views[k]; }); var accessor = PropTypes.oneOfType([PropTypes.string, PropTypes.func]); var dateFormat = PropTypes.any; var dateRangeFormat = 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, * }} * ``` */ var views$1 = PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOf(viewNames)), all(PropTypes.object, function (props, name) { for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } var prop = props[name], err; Object.keys(prop).every(function (key) { var isBuiltinView = viewNames.indexOf(key) !== -1 && typeof prop[key] === 'boolean'; return isBuiltinView || !(err = elementType.apply(void 0, [prop, key].concat(args))); }); return err || null; })]); function notify(handler, args) { handler && handler.apply(null, [].concat(args)); } 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); !(result == null || typeof result === 'string') ? process.env.NODE_ENV !== "production" ? invariant(false, '`localizer format(..)` must return a string, null, or undefined') : invariant(false) : void 0; return result; } var DateLocalizer = function DateLocalizer(spec) { var _this = this; !(typeof spec.format === 'function') ? process.env.NODE_ENV !== "production" ? invariant(false, 'date localizer `format(..)` must be a function') : invariant(false) : void 0; !(typeof spec.firstOfWeek === 'function') ? process.env.NODE_ENV !== "production" ? invariant(false, 'date localizer `firstOfWeek(..)` must be a function') : invariant(false) : void 0; this.propType = spec.propType || localePropType; this.startOfWeek = spec.firstOfWeek; 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)); }; }; function mergeWithDefaults(localizer, culture, formatOverrides, messages) { var formats = _extends({}, localizer.formats, formatOverrides); return _extends({}, localizer, { messages: messages, startOfWeek: function startOfWeek() { return localizer.startOfWeek(culture); }, format: function format(value, _format2) { return localizer.format(value, formats[_format2] || _format2, culture); } }); } 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 "+" + total + " more"; } }; function messages(msgs) { return _extends({}, defaultMessages, msgs); } var MILLI = { seconds: 1000, minutes: 1000 * 60, hours: 1000 * 60 * 60, day: 1000 * 60 * 60 * 24 }; var MONTHS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; var dates = _extends({}, dateMath, { monthsInYear: function monthsInYear(year) { var date = new Date(year, 0, 1); return MONTHS.map(function (i) { return dates.month(date, i); }); }, firstVisibleDay: function firstVisibleDay(date, localizer) { var firstOfMonth = dates.startOf(date, 'month'); return dates.startOf(firstOfMonth, 'week', localizer.startOfWeek()); }, lastVisibleDay: function lastVisibleDay(date, localizer) { var endOfMonth = dates.endOf(date, 'month'); return dates.endOf(endOfMonth, 'week', localizer.startOfWeek()); }, visibleDays: function visibleDays(date, localizer) { var current = dates.firstVisibleDay(date, localizer), last = dates.lastVisibleDay(date, localizer), days = []; while (dates.lte(current, last, 'day')) { days.push(current); current = dates.add(current, 1, 'day'); } return days; }, ceil: function ceil(date, unit) { var floor = dates.startOf(date, unit); return dates.eq(floor, date) ? floor : dates.add(floor, 1, unit); }, range: function range(start, end, unit) { if (unit === void 0) { unit = 'day'; } var current = start, days = []; while (dates.lte(current, end, unit)) { days.push(current); current = dates.add(current, 1, unit); } return days; }, merge: 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)); }, eqTime: function eqTime(dateA, dateB) { return dates.hours(dateA) === dates.hours(dateB) && dates.minutes(dateA) === dates.minutes(dateB) && dates.seconds(dateA) === dates.seconds(dateB); }, isJustDate: function isJustDate(date) { return dates.hours(date) === 0 && dates.minutes(date) === 0 && dates.seconds(date) === 0 && dates.milliseconds(date) === 0; }, duration: function duration(start, end, unit, firstOfWeek) { if (unit === 'day') unit = 'date'; return Math.abs(dates[unit](start, undefined, firstOfWeek) - dates[unit](end, undefined, firstOfWeek)); }, diff: 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])); }, total: function total(date, unit) { var ms = date.getTime(), div = 1; switch (unit) { case 'week': div *= 7; case 'day': div *= 24; case 'hours': div *= 60; case 'minutes': div *= 60; case 'seconds': div *= 1000; } return ms / div; }, week: function week(date) { var d = new Date(date); d.setHours(0, 0, 0); d.setDate(d.getDate() + 4 - (d.getDay() || 7)); return Math.ceil(((d - new Date(d.getFullYear(), 0, 1)) / 8.64e7 + 1) / 7); }, today: function today() { return dates.startOf(new Date(), 'day'); }, yesterday: function yesterday() { return dates.add(dates.startOf(new Date(), 'day'), -1, 'day'); }, tomorrow: function tomorrow() { return dates.add(dates.startOf(new Date(), 'day'), 1, 'day'); } }); var EventCell = /*#__PURE__*/ function (_React$Component) { _inheritsLoose(EventCell, _React$Component); function EventCell() { return _React$Component.apply(this, arguments) || this; } var _proto = EventCell.prototype; _proto.render = 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, 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, EventContent = _this$props$component.eventContent, props = _objectWithoutPropertiesLoose(_this$props, ["style", "className", "event", "selected", "isAllDay", "onSelect", "onDoubleClick", "localizer", "continuesPrior", "continuesAfter", "accessors", "getters", "children", "components"]); 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 || dates.diff(start, dates.ceil(end, 'day'), 'day') > 1; var userProps = getters.eventProp(event, start, end, selected); var inner = Event ? React.createElement(Event, { event: event, title: title, isAllDay: showAsAllDay, localizer: localizer }) : title; var content = EventContent ? React.createElement(EventContent, { event: event, title: title, allDay: showAsAllDay }) : React.createElement("div", { className: "rbc-event-content", title: tooltip || undefined }, inner); return React.createElement(EventWrapper, _extends({}, this.props, { type: "date" }), React.createElement("div", _extends({}, props, { tabIndex: 0, style: _extends({}, userProps.style, style), className: cn('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); } }), typeof children === 'function' ? children(content) : content)); }; return EventCell; }(React.Component); EventCell.propTypes = process.env.NODE_ENV !== "production" ? { event: PropTypes.object.isRequired, slotStart: PropTypes.instanceOf(Date), slotEnd: PropTypes.instanceOf(Date), selected: PropTypes.bool, isAllDay: PropTypes.bool, continuesPrior: PropTypes.bool, continuesAfter: PropTypes.bool, accessors: PropTypes.object.isRequired, components: PropTypes.object.isRequired, getters: PropTypes.object.isRequired, localizer: PropTypes.object, onSelect: PropTypes.func, onDoubleClick: PropTypes.func } : {}; function isSelected(event, selected) { if (!event || selected == null) return false; return [].concat(selected).indexOf(event) !== -1; } 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 }; } var Popup = /*#__PURE__*/ function (_React$Component) { _inheritsLoose(Popup, _React$Component); function Popup() { return _React$Component.apply(this, arguments) || this; } var _proto = Popup.prototype; _proto.componentDidMount = function componentDidMount() { var _this$props$popupOffs = this.props.popupOffset, popupOffset = _this$props$popupOffs === void 0 ? 5 : _this$props$popupOffs, _getOffset = getOffset(this.refs.root), top = _getOffset.top, left = _getOffset.left, width = _getOffset.width, height = _getOffset.height, viewBottom = window.innerHeight + getScrollTop(window), viewRight = window.innerWidth + getScrollLeft(window), bottom = top + height, right = left + width; if (bottom > viewBottom || right > viewRight) { var topOffset, leftOffset; if (bottom > viewBottom) topOffset = bottom - viewBottom + (popupOffset.y || +popupOffset || 0); if (right > viewRight) leftOffset = right - viewRight + (popupOffset.x || +popupOffset || 0); this.setState({ topOffset: topOffset, leftOffset: leftOffset }); //eslint-disable-line } }; _proto.render = function render() { var _this$props = this.props, events = _this$props.events, selected = _this$props.selected, getters = _this$props.getters, accessors = _this$props.accessors, components = _this$props.components, onSelect = _this$props.onSelect, onDoubleClick = _this$props.onDoubleClick, slotStart = _this$props.slotStart, slotEnd = _this$props.slotEnd, localizer = _this$props.localizer; var _this$props$position = this.props.position, left = _this$props$position.left, width = _this$props$position.width, top = _this$props$position.top, topOffset = (this.state || {}).topOffset || 0, leftOffset = (this.state || {}).leftOffset || 0; var style = { top: Math.max(0, top - topOffset), left: left - leftOffset, minWidth: width + width / 2 }; return React.createElement("div", { ref: "root", style: style, className: "rbc-overlay" }, React.createElement("div", { className: "rbc-overlay-header" }, localizer.format(slotStart, 'dayHeaderFormat')), events.map(function (event, idx) { return React.createElement(EventCell, { key: idx, type: "popup", event: event, getters: getters, onSelect: onSelect, accessors: accessors, components: components, onDoubleClick: onDoubleClick, continuesPrior: dates.lt(accessors.end(event), slotStart, 'day'), continuesAfter: dates.gte(accessors.start(event), slotEnd, 'day'), selected: isSelected(event, selected) }); })); }; return Popup; }(React.Component); Popup.propTypes = process.env.NODE_ENV !== "production" ? { position: PropTypes.object, popupOffset: PropTypes.oneOfType([PropTypes.number, PropTypes.shape({ x: PropTypes.number, y: PropTypes.number })]), events: PropTypes.array, selected: PropTypes.object, accessors: PropTypes.object.isRequired, components: PropTypes.object.isRequired, getters: PropTypes.object.isRequired, localizer: PropTypes.object.isRequired, onSelect: PropTypes.func, onDoubleClick: PropTypes.func, slotStart: PropTypes.instanceOf(Date), slotEnd: PropTypes.number } : {}; function addEventListener(type, handler, target) { if (target === void 0) { target = document; } events.on(target, type, handler, { passive: false }); return { remove: function remove() { events.off(target, type, handler); } }; } 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 isEvent(node, bounds) { return !!getEventNodeFromPoint(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, _temp) { var _ref2 = _temp === void 0 ? {} : _temp, _ref2$global = _ref2.global, global = _ref2$global === void 0 ? false : _ref2$global, _ref2$longPressThresh = _ref2.longPressThreshold, longPressThreshold = _ref2$longPressThresh === void 0 ? 250 : _ref2$longPressThresh; this.container = node; this.globalMouse = !node || global; this.longPressThreshold = longPressThreshold; 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); // Fixes an iOS 10 bug where scrolling could not be prevented on the window. // https://github.com/metafizzy/flickity/issues/457#issuecomment-254501356 this._onTouchMoveWindowListener = addEventListener('touchmove', function () {}, window); this._onKeyDownListener = addEventListener('keydown', this._keyListener); this._onKeyUpListener = addEventListener('keyup', this._keyListener); this._addInitialEventListener(); } var _proto = Selection.prototype; _proto.on = 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); } }; }; _proto.emit = 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; }; _proto.teardown = function teardown() { this.listeners = Object.create(null); this._onTouchMoveWindowListener && this._onTouchMoveWindowListener.remove(); this._onInitialEventListener && this._onInitialEventListener.remove(); this._onEndListener && this._onEndListener.remove(); this._onEscListener && this._onEscListener.remove(); this._onMoveListener && this._onMoveListener.remove(); this._onKeyUpListener && this._onKeyUpListener.remove(); this._onKeyDownListener && this._onKeyDownListener.remove(); }; _proto.isSelected = function isSelected(node) { var box = this._selectRect; if (!box || !this.selecting) return false; return objectsCollide(box, getBoundsForNode(node)); }; _proto.filter = 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. ; _proto._addLongPressListener = function _addLongPressListener(handler, initialEvent) { var _this = this; var timer = null; var touchMoveListener = null; var touchEndListener = null; var handleTouchStart = function handleTouchStart(initialEvent) { timer = setTimeout(function () { cleanup(); handler(initialEvent); }, _this.longPressThreshold); touchMoveListener = addEventListener('touchmove', function () { return cleanup(); }); touchEndListener = addEventListener('touchend', function () { return cleanup(); }); }; var touchStartListener = addEventListener('touchstart', handleTouchStart); var cleanup = function cleanup() { if (timer) { clearTimeout(timer); } if (touchMoveListener) { touchMoveListener.remove(); } if (touchEndListener) { touchEndListener.remove(); } timer = null; touchMoveListener = null; touchEndListener = null; }; if (initialEvent) { handleTouchStart(initialEvent); } return { remove: function remove() { cleanup(); touchStartListener.remove(); } }; } // Listen for mousedown and touchstart events. When one is received, disable the other and setup // future event handling based on the type of event. ; _proto._addInitialEventListener = function _addInitialEventListener() { var _this2 = this; var mouseDownListener = addEventListener('mousedown', function (e) { _this2._onInitialEventListener.remove(); _this2._handleInitialEvent(e); _this2._onInitialEventListener = addEventListener('mousedown', _this2._handleInitialEvent); }); var touchStartListener = addEventListener('touchstart', function (e) { _this2._onInitialEventListener.remove(); _this2._onInitialEventListener = _this2._addLongPressListener(_this2._handleInitialEvent, e); }); this._onInitialEventListener = { remove: function remove() { mouseDownListener.remove(); touchStartListener.remove(); } }; }; _proto._handleInitialEvent = function _handleInitialEvent(e) { var _getEventCoordinates = getEventCoordinates(e), clientX = _getEventCoordinates.clientX, clientY = _getEventCoordinates.clientY, pageX = _getEventCoordinates.pageX, pageY = _getEventCoordinates.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._onEndListener = addEventListener('mouseup', this._handleTerminatingEvent); this._onEscListener = addEventListener('keydown', this._handleTerminatingEvent); this._onMoveListener = addEventListener('mousemove', this._handleMoveEvent); break; case 'touchstart': this._handleMoveEvent(e); this._onEndListener = addEventListener('touchend', this._handleTerminatingEvent); this._onMoveListener = addEventListener('touchmove', this._handleMoveEvent); break; default: break; } }; _proto._handleTerminatingEvent = function _handleTerminatingEvent(e) { var _getEventCoordinates2 = getEventCoordinates(e), pageX = _getEventCoordinates2.pageX, pageY = _getEventCoordinates2.pageY; this.selecting = false; this._onEndListener && this._onEndListener.remove(); this._onMoveListener && this._onMoveListener.remove(); if (!this._initialEventData) return; var inRoot = !this.container || contains(this.container(), e.target); var bounds = this._selectRect; var click = this.isClick(pageX, pageY); this._initialEventData = null; if (e.key === 'Escape') { return this.emit('reset'); } if (!inRoot) { return this.emit('reset'); } if (click && inRoot) { return this._handleClickEvent(e); } // User drag-clicked in the Selectable area if (!click) return this.emit('select', bounds); }; _proto._handleClickEvent = function _handleClickEvent(e) { var _getEventCoordinates3 = getEventCoordinates(e), pageX = _getEventCoordinates3.pageX, pageY = _getEventCoordinates3.pageY, clientX = _getEventCoordinates3.clientX, clientY = _getEventCoordinates3.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 }); }; _proto._handleMoveEvent = function _handleMoveEvent(e) { if (this._initialEventData === null) { return; } var _this$_initialEventDa = this._initialEventData, x = _this$_initialEventDa.x, y = _this$_initialEventDa.y; var _getEventCoordinates4 = getEventCoordinates(e), pageX = _getEventCoordinates4.pageX, pageY = _getEventCoordinates4.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; // Prevent emitting selectStart event until mouse is moved. // in Chrome on Windows, mouseMove event may be fired just after mouseDown event. if (this.isClick(pageX, pageY) && !old && !(w || h)) { return; } this.selecting = true; this._selectRect = { top: top, left: left, x: pageX, y: pageY, right: left + w, bottom: top + h }; if (!old) { this.emit('selectStart', this._initialEventData); } if (!this.isClick(pageX, pageY)) this.emit('selecting', this._selectRect); e.preventDefault(); }; _proto._keyListener = function _keyListener(e) { this.ctrl = e.metaKey || e.ctrlKey; }; _proto.isClick = 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; }; return Selection; }(); /** * Resolve the disance prop from either an Int or an Object * @return {Object} */ function normalizeDistance(distance) { if (distance === void 0) { distance = 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, tolerance) { if (tolerance === void 0) { tolerance = 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) { _inheritsLoose(BackgroundCells, _React$Component); function BackgroundCells(props, context) { var _this; _this = _React$Component.call(this, props, context) || this; _this.state = { selecting: false }; return _this; } var _proto = BackgroundCells.prototype; _proto.componentDidMount = function componentDidMount() { this.props.selectable && this._selectable(); }; _proto.componentWillUnmount = function componentWillUnmount() { this._teardownSelectable(); }; _proto.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { if (nextProps.selectable && !this.props.selectable) this._selectable(); if (!nextProps.selectable && this.props.selectable) this._teardownSelectable(); }; _proto.render = 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; var _this$state = this.state, selecting = _this$state.selecting, startIdx = _this$state.startIdx, endIdx = _this$state.endIdx; var current = getNow(); return React.createElement("div", { className: "rbc-row-bg" }, 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 React.createElement(Wrapper, { key: index, value: date, range: range }, React.createElement("div", { style: style, className: cn('rbc-day-bg', className, selected && 'rbc-selected-cell', dates.eq(date, current, 'day') && 'rbc-today', currentDate && dates.month(currentDate) !== dates.month(date) && 'rbc-off-range-bg') })); })); }; _proto._selectable = function _selectable() { var _this2 = this; var node = findDOMNode(this); var selector = this._selector = new Selection(this.props.container, { longPressThreshold: this.props.longPressThreshold }); var selectorClicksHandler = function selectorClicksHandler(point, actionType) { if (!isEvent(findDOMNode(_this2), 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._initial, nodeBox, box, range.length, rtl); startIdx = _dateCellSelection.startIdx; endIdx = _dateCellSelection.endIdx; } _this2.setState({ selecting: true, startIdx: startIdx, endIdx: endIdx }); }); selector.on('beforeSelect', function (box) { if (_this2.props.selectable !== 'ignoreEvents') return; return !isEvent(findDOMNode(_this2), box); }); selector.on('click', function (point) { return selectorClicksHandler(point, 'click'); }); selector.on('doubleClick', function (point) { return selectorClicksHandler(point, 'doubleClick'); }); selector.on('select', function (bounds) { _this2._selectSlot(_extends({}, _this2.state, { action: 'select', bounds: bounds })); _this2._initial = {}; _this2.setState({ selecting: false }); notify(_this2.props.onSelectEnd, [_this2.state]); }); }; _proto._teardownSelectable = function _teardownSelectable() { if (!this._selector) return; this._selector.teardown(); this._selector = null; }; _proto._selectSlot = function _selectSlot(_ref) { var endIdx = _ref.endIdx, startIdx = _ref.startIdx, action = _ref.action, bounds = _ref.bounds, box = _ref.box; if (endIdx !== -1 && startIdx !== -1) this.props.onSelectSlot && this.props.onSelectSlot({ start: startIdx, end: endIdx, action: action, bounds: bounds, box: box }); }; return BackgroundCells; }(React.Component); BackgroundCells.propTypes = process.env.NODE_ENV !== "production" ? { date: PropTypes.instanceOf(Date), getNow: PropTypes.func.isRequired, getters: PropTypes.object.isRequired, components: PropTypes.object.isRequired, container: PropTypes.func, dayPropGetter: PropTypes.func, selectable: PropTypes.oneOf([true, false, 'ignoreEvents']), longPressThreshold: PropTypes.number, onSelectSlot: PropTypes.func.isRequired, onSelectEnd: PropTypes.func, onSelectStart: PropTypes.func, range: PropTypes.arrayOf(PropTypes.instanceOf(Date)), rtl: PropTypes.bool, type: PropTypes.string } : {}; /* eslint-disable react/prop-types */ var EventRowMixin = { propTypes: { slotMetrics: PropTypes.object.isRequired, selected: PropTypes.object, isAllDay: PropTypes.bool, accessors: PropTypes.object.isRequired, localizer: PropTypes.object.isRequired, components: PropTypes.object.isRequired, getters: PropTypes.object.isRequired, onSelect: PropTypes.func, onDoubleClick: PropTypes.func }, defaultProps: { segments: [], selected: {} }, renderEvent: function renderEvent(props, event) { var selected = props.selected, _ = props.isAllDay, accessors = props.accessors, getters = props.getters, onSelect = props.onSelect, onDoubleClick = props.onDoubleClick, localizer = props.localizer, slotMetrics = props.slotMetrics, components = props.components; var continuesPrior = slotMetrics.continuesPrior(event); var continuesAfter = slotMetrics.continuesAfter(event); return React.createElement(EventCell, { event: event, getters: getters, localizer: localizer, accessors: accessors, components: components, onSelect: onSelect, onDoubleClick: onDoubleClick, continuesPrior: continuesPrior, continuesAfter: continuesAfter, selected: isSelected(event, selected) }); }, renderSpan: function renderSpan(slots, len, key, content) { if (content === void 0) { content = ' '; } var per = Math.abs(len) / slots * 100 + '%'; return React.createElement("div", { key: key, className: "rbc-row-segment" // IE10/11 need max-width. flex-basis doesn't respect box-sizing , style: { WebkitFlexBasis: per, flexBasis: per, maxWidth: per } }, content); } }; var EventRow = /*#__PURE__*/ function (_React$Component) { _inheritsLoose(EventRow, _React$Component); function EventRow() { return _React$Component.apply(this, arguments) || this; } var _proto = EventRow.prototype; _proto.render = function render() { var _this = this; var _this$props = this.props, segments = _this$props.segments, slots = _this$props.slotMetrics.slots, className = _this$props.className; var lastEnd = 1; return React.createElement("div", { className: cn(className, 'rbc-row') }, segments.reduce(function (row, _ref, li) { var event = _ref.event, left = _ref.left, right = _ref.right, span = _ref.span; var key = '_lvl_' + li; var gap = left - lastEnd; var content = EventRowMixin.renderEvent(_this.props, event); if (gap) row.push(EventRowMixin.renderSpan(slots, gap, key + "_gap")); row.push(EventRowMixin.renderSpan(slots, span, key, content)); lastEnd = right + 1; return row; }, [])); }; return EventRow; }(React.Component); EventRow.propTypes = process.env.NODE_ENV !== "production" ? _extends({ segments: PropTypes.array }, EventRowMixin.propTypes) : {}; EventRow.defaultProps = _extends({}, EventRowMixin.defaultProps); function endOfRange(dateRange, unit) { if (unit === void 0) { unit = 'day'; } return { first: dateRange[0], last: dates.add(dateRange[dateRange.length - 1], 1, unit) }; } function eventSegments(event, range, accessors) { var _endOfRange = endOfRange(range), first = _endOfRange.first, last = _endOfRange.last; var slots = dates.diff(first, last, 'day'); var start = dates.max(dates.startOf(accessors.start(event), 'day'), first); var end = dates.min(dates.ceil(accessors.end(event), 'day'), last); var padding = findIndex(range, function (x) { return dates.eq(x, start, 'day'); }); var span = dates.diff(start, end, 'day'); span = Math.min(span, slots); span = Math.max(span, 1); return { event: event, span: span, left: padding + 1, right: Math.max(padding + span, 1) }; } function eventLevels(rowSegments, limit) { if (limit === void 0) { limit = Infinity; } var i, j, seg, levels = [], extra = []; for (i = 0; i < rowSegments.length; i++) { seg = rowSegments[i]; for (j = 0; j < levels.length; j++) { if (!segsOverlap(seg, levels[j])) break; } if (j >= limit) { extra.push(seg); } else { (levels[j] || (levels[j] = [])).push(seg); } } for (i = 0; i < levels.length; i++) { levels[i].sort(function (a, b) { return a.left - b.left; }); //eslint-disable-line } return { levels: levels, extra: extra }; } function inRange(e, start, end, accessors) { var eStart = dates.startOf(accessors.start(e), 'day'); var eEnd = accessors.end(e); var startsBeforeEnd = dates.lte(eStart, end, 'day'); // when the event is zero duration we need to handle a bit differently var endsAfterStart = !dates.eq(eStart, eEnd, 'minutes') ? dates.gt(eEnd, start, 'minutes') : dates.gte(eEnd, start, 'minutes'); return startsBeforeEnd && endsAfterStart; } function segsOverlap(seg, otherSegs) { return otherSegs.some(function (otherSeg) { return otherSeg.left <= seg.right && otherSeg.right >= seg.left; }); } function sortEvents(evtA, evtB, accessors) { var startSort = +dates.startOf(accessors.start(evtA), 'day') - +dates.startOf(accessors.start(evtB), 'day'); var durA = dates.diff(accessors.start(evtA), dates.ceil(accessors.end(evtA), 'day'), 'day'); var durB = dates.diff(accessors.start(evtB), dates.ceil(accessors.end(evtB), 'day'), 'day'); return startSort || // sort by start Day first Math.max(durB, 1) - Math.max(durA, 1) || // events spanning multiple days go first !!accessors.allDay(evtB) - !!accessors.allDay(evtA) || // then allDay single day events +accessors.start(evtA) - +accessors.start(evtB); // then sort by start time } var isSegmentInSlot = function isSegmentInSlot(seg, slot) { return seg.left <= slot && seg.right >= slot; }; var eventsInSlot = function eventsInSlot(segments, slot) { return segments.filter(function (seg) { return isSegmentInSlot(seg, slot); }).length; }; var EventEndingRow = /*#__PURE__*/ function (_React$Component) { _inheritsLoose(EventEndingRow, _React$Component); function EventEndingRow() { return _React$Component.apply(this, arguments) || this; } var _proto = EventEndingRow.prototype; _proto.render = function render() { var _this$props = this.props, segments = _this$props.segments, slots = _this$props.slotMetrics.slots; var rowSegments = eventLevels(segments).levels[0]; var current = 1, lastEnd = 1, row = []; while (current <= slots) { var key = '_lvl_' + current; var _ref = rowSegments.filter(function (seg) { return isSegmentInSlot(seg, current); })[0] || {}, event = _ref.event, left = _ref.left, right = _ref.right, span = _ref.span; //eslint-disable-line if (!event) { current++; continue; } var gap = Math.max(0, left - lastEnd); if (this.canRenderSlotEvent(left, span)) { var content = EventRowMixin.renderEvent(this.props, event); if (gap) { row.push(EventRowMixin.renderSpan(slots, gap, key + '_gap')); } row.push(EventRowMixin.renderSpan(slots, span, key, content)); lastEnd = current = right + 1; } else { if (gap) { row.push(EventRowMixin.renderSpan(slots, gap, key + '_gap')); } row.push(EventRowMixin.renderSpan(slots, 1, key, this.renderShowMore(segments, current))); lastEnd = current = current + 1; } } return React.createElement("div", { className: "rbc-row" }, row); }; _proto.canRenderSlotEvent = function canRenderSlotEvent(slot, span) { var segments = this.props.segments; return range(slot, slot + span).every(function (s) { var count = eventsInSlot(segments, s); return count === 1; }); }; _proto.renderShowMore = function renderShowMore(segments, slot) { var _this = this; var localizer = this.props.localizer; var count = eventsInSlot(segments, slot); return count ? React.createElement("a", { key: 'sm_' + slot, href: "#", className: 'rbc-show-more', onClick: function onClick(e) { return _this.showMore(slot, e); } }, localizer.messages.showMore(count)) : false; }; _proto.showMore = function showMore(slot, e) { e.preventDefault(); this.props.onShowMore(slot); }; return EventEndingRow; }(React.Component); EventEndingRow.propTypes = process.env.NODE_ENV !== "production" ? _extends({ segments: PropTypes.array, slots: PropTypes.number, onShowMore: PropTypes.func }, EventRowMixin.propTypes) : {}; EventEndingRow.defaultProps = _extends({}, EventRowMixin.defaultProps); var isSegmentInSlot$1 = function isSegmentInSlot(seg, slot) { return seg.left <= slot && seg.right >= slot; }; var isEqual = function isEqual(a, b) { return a.range === b.range && a.events === b.events; }; function getSlotMetrics() { return memoize(function (options) { var range = options.range, events = options.events, maxRows = options.maxRows, minRows = options.minRows, accessors = options.accessors; var _endOfRange = endOfRange(range), first = _endOfRange.first, last = _endOfRange.last; var segments = events.map(function (evt) { return eventSegments(evt, range, accessors); }); var _eventLevels = eventLevels(segments, Math.max(maxRows - 1, 1)), levels = _eventLevels.levels, extra = _eventLevels.extra; while (levels.length < minRows) { levels.push([]); } return { first: first, last: last, levels: levels, extra: extra, range: range, slots: range.length, clone: function clone(args) { var metrics = getSlotMetrics(); return metrics(_extends({}, options, args)); }, getDateForSlot: function getDateForSlot(slotNumber) { return range[slotNumber]; }, getSlotForDate: function getSlotForDate(date) { return range.find(function (r) { return dates.eq(r, date, 'day'); }); }, getEventsForSlot: function getEventsForSlot(slot) { return segments.filter(function (seg) { return isSegmentInSlot$1(seg, slot); }).map(function (seg) { return seg.event; }); }, continuesPrior: function continuesPrior(event) { return dates.lt(accessors.start(event), first, 'day'); }, continuesAfter: function continuesAfter(event) { var eventEnd = accessors.end(event); var singleDayDuration = dates.eq(accessors.start(event), eventEnd, 'minutes'); return singleDayDuration ? dates.gte(eventEnd, last, 'minutes') : dates.gt(eventEnd, last, 'minutes'); } }; }, isEqual); } var DateContentRow = /*#__PURE__*/ function (_React$Component) { _inheritsLoose(DateContentRow, _React$Component); function DateContentRow() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this; _this.handleSelectSlot = function (slot) { var _this$props = _this.props, range = _this$props.range, onSelectSlot = _this$props.onSelectSlot; onSelectSlot(range.slice(slot.start, slot.end + 1), slot); }; _this.h