@fellow/react-big-calendar
Version:
Calendar! with events
1,605 lines (1,388 loc) • 168 kB
JavaScript
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