From 80fb9addd6f3ffc28a345c4ac58b549f646aa2a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 3 Mar 2021 14:30:55 +0700 Subject: [PATCH 01/60] Update data for examples to reflect allDay --- examples/events.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/events.js b/examples/events.js index 90aaa4b4c..063b305cf 100644 --- a/examples/events.js +++ b/examples/events.js @@ -38,20 +38,22 @@ export default [ { id: 5, title: 'Conference', - start: new Date(2015, 3, 11), - end: new Date(2015, 3, 13), + start: new Date(2015, 3, 12, 10, 30, 0, 0), + end: new Date(2015, 3, 12, 12, 30, 0, 0), desc: 'Big conference for important people', }, { id: 6, title: 'Meeting', - start: new Date(2015, 3, 12, 10, 30, 0, 0), - end: new Date(2015, 3, 12, 12, 30, 0, 0), + allDay: true, + start: new Date(2015, 3, 11), + end: new Date(2015, 3, 13), desc: 'Pre-meeting meeting, to prepare for the meeting', }, { id: 7, title: 'Lunch', + allDay: true, start: new Date(2015, 3, 12, 12, 0, 0, 0), end: new Date(2015, 3, 12, 13, 0, 0, 0), desc: 'Power lunch', @@ -77,12 +79,14 @@ export default [ }, { id: 11, + allDay: true, title: 'Planning Meeting with Paige', start: new Date(2015, 3, 13, 8, 0, 0), - end: new Date(2015, 3, 13, 10, 30, 0), + end: new Date(2015, 3, 16, 10, 30, 0), }, { id: 11.1, + allDay: true, title: 'Inconvenient Conference Call', start: new Date(2015, 3, 13, 9, 30, 0), end: new Date(2015, 3, 13, 12, 0, 0), From 87bc3857c92444d627b387e9ee1ed653204c57a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 3 Mar 2021 14:35:53 +0700 Subject: [PATCH 02/60] Implement customizable footer --- src/Calendar.js | 1 + src/DateContentRow.js | 37 +++++++++++++++++++++++++++++++++++-- src/DateFooter.js | 14 ++++++++++++++ src/Month.js | 29 +++++++++++++++++++++++++++++ src/less/month.less | 15 ++++++++++----- src/sass/month.scss | 14 ++++++++++---- 6 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 src/DateFooter.js diff --git a/src/Calendar.js b/src/Calendar.js index 94f703426..8c6795605 100644 --- a/src/Calendar.js +++ b/src/Calendar.js @@ -747,6 +747,7 @@ class Calendar extends React.Component { header: PropTypes.elementType, dateHeader: PropTypes.elementType, event: PropTypes.elementType, + footer: PropTypes.elementType, }), }), diff --git a/src/DateContentRow.js b/src/DateContentRow.js index b0e23651c..f9b682196 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -56,7 +56,20 @@ class DateContentRow extends React.Component { let headingHeight = this.headingRow ? getHeight(this.headingRow) : 0 let eventSpace = getHeight(findDOMNode(this)) - headingHeight - return Math.max(Math.floor(eventSpace / eventHeight), 1) + // This is 5 instead of 1 because there's a bug in this library :( + // For some reason, eventSpace == eventHeight == 18 on the first render, so it only shows 1 event. + // There might be a way to fix it by changing CSS but that's not an option right now + // Since responsive design is out of scope, this is actually a viable option + // + // When the vertical space is limited in the future, and the events row overflows the date, + // Consider parameterize it to control from the outside of this library + // or change CSS to make sure this calculation always work as expected + const MINIMUM_EVENTS_ROW = 5 + const result = Math.max( + Math.floor(eventSpace / eventHeight), + MINIMUM_EVENTS_ROW + ) + return result } renderHeadingCell = (date, index) => { @@ -72,6 +85,19 @@ class DateContentRow extends React.Component { }) } + renderFooterCell = (date, index) => { + let { renderFooter, getNow } = this.props + + return renderFooter({ + date, + key: `footer_${index}`, + className: clsx( + 'rbc-date-cell', + dates.eq(date, getNow(), 'day') && 'rbc-now' + ), + }) + } + renderDummy = () => { let { className, range, renderHeader, showAllEvents } = this.props return ( @@ -115,6 +141,7 @@ class DateContentRow extends React.Component { getNow, renderHeader, + renderFooter, onSelect, localizer, onSelectStart, @@ -178,7 +205,7 @@ class DateContentRow extends React.Component { role="row" > {renderHeader && ( -
+
{range.map(this.renderHeadingCell)}
)} @@ -197,6 +224,11 @@ class DateContentRow extends React.Component {
+ {renderFooter && ( +
+ {range.map(this.renderFooterCell)} +
+ )} ) } @@ -212,6 +244,7 @@ DateContentRow.propTypes = { resourceId: PropTypes.any, renderForMeasure: PropTypes.bool, renderHeader: PropTypes.func, + renderFooter: PropTypes.func, container: PropTypes.func, selected: PropTypes.object, diff --git a/src/DateFooter.js b/src/DateFooter.js new file mode 100644 index 000000000..3a9c72022 --- /dev/null +++ b/src/DateFooter.js @@ -0,0 +1,14 @@ +import PropTypes from 'prop-types' +import React from 'react' + +const DateFooter = ({ label }) => { + return {label} +} + +DateFooter.propTypes = { + label: PropTypes.node, + date: PropTypes.instanceOf(Date), + isOffRange: PropTypes.bool, +} + +export default DateFooter diff --git a/src/Month.js b/src/Month.js index bdbb691c0..0ec570758 100644 --- a/src/Month.js +++ b/src/Month.js @@ -16,6 +16,7 @@ import Overlay from 'react-overlays/Overlay' import DateContentRow from './DateContentRow' import Header from './Header' import DateHeader from './DateHeader' +import DateFooter from './DateFooter' import { inRange, sortEvents } from './utils/eventLevels' @@ -133,6 +134,7 @@ class MonthView extends React.Component { getters={getters} localizer={localizer} renderHeader={this.readerDateHeading} + renderFooter={this.renderDateFooter} renderForMeasure={needLimitMeasure} onShowMore={this.handleShowMore} onSelect={this.handleSelectEvent} @@ -177,6 +179,33 @@ class MonthView extends React.Component { ) } + renderDateFooter = ({ date, className, ...props }) => { + let { date: currentDate, localizer } = this.props + + let isOffRange = dates.month(date) !== dates.month(currentDate) + let isCurrent = dates.eq(date, currentDate, 'day') + let DateFooterComponent = this.props.components.dateFooter || DateFooter + let label = localizer.format(date, 'dateFormat') + + return ( +
+ +
+ ) + } + renderHeaders(row) { let { localizer, components } = this.props let first = row[0] diff --git a/src/less/month.less b/src/less/month.less index ec69b237d..f9fd1f483 100644 --- a/src/less/month.less +++ b/src/less/month.less @@ -1,6 +1,5 @@ @import './variables.less'; - .rbc-row { display: flex; flex-direction: row; @@ -18,7 +17,6 @@ background-color: @date-selection-bg-color; } - .rbc-show-more { &:extend(.rbc-ellipsis); background-color: rgba(255, 255, 255, 0.3); @@ -61,6 +59,11 @@ border-top: 1px solid @cell-border; } } +.rbc-row-footer { + position: absolute; + width: 100%; + bottom: 0; +} .rbc-date-cell { flex: 1 1 0; @@ -73,7 +76,9 @@ } > a { - &, &:active, &:visited { + &, + &:active, + &:visited { color: inherit; text-decoration: none; } @@ -106,7 +111,7 @@ z-index: @event-zindex + 1; border: 1px solid #e5e5e5; background-color: #fff; - box-shadow: 0 5px 15px rgba(0,0,0,.25); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.25); padding: 10px; > * + * { @@ -116,6 +121,6 @@ .rbc-overlay-header { border-bottom: 1px solid #e5e5e5; - margin: -10px -10px 5px -10px ; + margin: -10px -10px 5px -10px; padding: 2px 10px; } diff --git a/src/sass/month.scss b/src/sass/month.scss index 9f2fecdf7..030e65dde 100644 --- a/src/sass/month.scss +++ b/src/sass/month.scss @@ -17,7 +17,6 @@ background-color: $date-selection-bg-color; } - .rbc-show-more { @extend .rbc-ellipsis; background-color: rgba(255, 255, 255, 0.3); @@ -60,6 +59,11 @@ border-top: 1px solid $cell-border; } } +.rbc-row-footer { + position: absolute; + width: 100%; + bottom: 0; +} .rbc-date-cell { flex: 1 1 0; @@ -72,7 +76,9 @@ } > a { - &, &:active, &:visited { + &, + &:active, + &:visited { color: inherit; text-decoration: none; } @@ -105,7 +111,7 @@ z-index: $event-zindex + 1; border: 1px solid #e5e5e5; background-color: #fff; - box-shadow: 0 5px 15px rgba(0,0,0,.25); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.25); padding: 10px; > * + * { @@ -115,6 +121,6 @@ .rbc-overlay-header { border-bottom: 1px solid #e5e5e5; - margin: -10px -10px 5px -10px ; + margin: -10px -10px 5px -10px; padding: 2px 10px; } From c2947ac70e3e46fb259d87b14517d50369881deb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 3 Mar 2021 14:36:23 +0700 Subject: [PATCH 03/60] Implement new examples --- examples/App.js | 2 +- examples/demos/rendering.js | 76 +++++++++++++++++++++++++++---------- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/examples/App.js b/examples/App.js index 7a57d90f8..589d54c71 100644 --- a/examples/App.js +++ b/examples/App.js @@ -52,7 +52,7 @@ const EXAMPLES = { dndOutsideSource: 'Addon: Drag and drop (from outside calendar)', } -const DEFAULT_EXAMPLE = 'basic' +const DEFAULT_EXAMPLE = 'rendering' class Example extends React.Component { constructor(...args) { diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index 889601a9c..8f9439d11 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -1,11 +1,14 @@ -import React from 'react' +import React, { Children, useEffect, useState } from 'react' import { Calendar, Views } from 'react-big-calendar' import events from '../events' function Event({ event }) { return ( - - {event.title} + + + {event.allDay ? 'ALL' : 'NOT ALL'} + {event.title} + {event.desc && ': ' + event.desc} ) @@ -39,21 +42,56 @@ const customSlotPropGetter = date => { else return {} } -let Rendering = ({ localizer }) => ( - -) +const ColoredEventWrapper = ({ children, event }) => { + console.log() + return React.cloneElement(Children.only(children), { + style: { + ...children.style, + backgroundColor: event.allDay ? 'lightBlue' : 'transparent', + padding: 0, + }, + }) +} +const TesterHeader = ({ label }) => { + return
{label}
+} +const TesterFooter = ({ label }) => { + return ( +
+ +
+ ) +} + +let Rendering = ({ localizer }) => { + const [localEvents, setEvents] = useState([]) + useEffect(() => { + const allDayEvents = events.filter(event => event.allDay) + const notAllDayEvents = events.filter(event => !event.allDay) + setEvents([...allDayEvents, ...notAllDayEvents]) + }, []) + return ( + + ) +} export default Rendering From 091691e946e9e9e4b5eb58e5f3866ff82a91f878 Mon Sep 17 00:00:00 2001 From: binh1298 Date: Wed, 3 Mar 2021 15:41:17 +0700 Subject: [PATCH 04/60] Apply suggestions from code review Co-authored-by: Pham Hong Phi --- examples/demos/rendering.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index 8f9439d11..86f6ccee2 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -43,7 +43,6 @@ const customSlotPropGetter = date => { } const ColoredEventWrapper = ({ children, event }) => { - console.log() return React.cloneElement(Children.only(children), { style: { ...children.style, @@ -52,10 +51,10 @@ const ColoredEventWrapper = ({ children, event }) => { }, }) } -const TesterHeader = ({ label }) => { +const CalendarHeader = ({ label }) => { return
{label}
} -const TesterFooter = ({ label }) => { +const CalendarFooter = ({ label }) => { return (
From 4dcf253b9e922a33230f9d0f0784b037a29c8c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 3 Mar 2021 16:09:24 +0700 Subject: [PATCH 05/60] Remove not all label --- examples/demos/rendering.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index 86f6ccee2..690f7adfb 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -5,10 +5,7 @@ import events from '../events' function Event({ event }) { return ( - - {event.allDay ? 'ALL' : 'NOT ALL'} - {event.title} - + {event.title} {event.desc && ': ' + event.desc} ) From 43f3ed14bcfbb9113b8a24d66bcf0750896386c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 3 Mar 2021 16:10:44 +0700 Subject: [PATCH 06/60] Remove Children.only --- examples/demos/rendering.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index 690f7adfb..683f67e15 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -40,7 +40,7 @@ const customSlotPropGetter = date => { } const ColoredEventWrapper = ({ children, event }) => { - return React.cloneElement(Children.only(children), { + return React.cloneElement(children, { style: { ...children.style, backgroundColor: event.allDay ? 'lightBlue' : 'transparent', @@ -80,8 +80,8 @@ let Rendering = ({ localizer }) => { event: Event, eventWrapper: ColoredEventWrapper, month: { - dateHeader: TesterHeader, - dateFooter: TesterFooter, + dateHeader: CalendarHeader, + dateFooter: CalendarFooter, }, // agenda: { // event: EventAgenda, From 22e56dcf316128b2c943a201173e0ca461d806c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 3 Mar 2021 17:08:01 +0700 Subject: [PATCH 07/60] Push lib --- .gitignore | 2 +- .size-snapshot.json | 22 +- lib/Agenda.js | 333 +++++ lib/BackgroundCells.js | 277 ++++ lib/BackgroundWrapper.js | 12 + lib/Calendar.js | 1240 +++++++++++++++++ lib/CalendarContext.js | 13 + lib/DateContentRow.js | 373 +++++ lib/DateHeader.js | 44 + lib/Day.js | 93 ++ lib/DayColumn.js | 624 +++++++++ lib/EventCell.js | 174 +++ lib/EventEndingRow.js | 168 +++ lib/EventRow.js | 87 ++ lib/EventRowMixin.js | 87 ++ lib/EventWrapper.js | 12 + lib/Header.js | 32 + lib/Month.js | 542 +++++++ lib/NoopWrapper.js | 12 + lib/Popup.js | 193 +++ lib/ResourceHeader.js | 27 + lib/ScrollableWeekWrapper.js | 23 + lib/Selection.js | 594 ++++++++ lib/TimeGrid.js | 449 ++++++ lib/TimeGridEvent.js | 135 ++ lib/TimeGridHeader.js | 313 +++++ lib/TimeGutter.js | 133 ++ lib/TimeSlotGroup.js | 98 ++ lib/Toolbar.js | 149 ++ lib/Views.js | 31 + lib/Week.js | 111 ++ lib/WorkWeek.js | 94 ++ lib/addons/dragAndDrop/DnDContext.js | 12 + .../dragAndDrop/EventContainerWrapper.js | 351 +++++ lib/addons/dragAndDrop/EventWrapper.js | 237 ++++ lib/addons/dragAndDrop/WeekWrapper.js | 370 +++++ lib/addons/dragAndDrop/common.js | 96 ++ lib/addons/dragAndDrop/index.js | 12 + lib/addons/dragAndDrop/styles.css | 80 ++ lib/addons/dragAndDrop/styles.scss | 78 ++ lib/addons/dragAndDrop/withDragAndDrop.js | 208 +++ lib/css/react-big-calendar.css | 673 +++++++++ lib/index.js | 45 + lib/localizer.js | 87 ++ lib/localizers/date-fns.js | 98 ++ lib/localizers/globalize.js | 178 +++ lib/localizers/moment.js | 89 ++ lib/localizers/oldGlobalize.js | 89 ++ lib/sass/agenda.scss | 73 + lib/sass/event.scss | 56 + lib/sass/month.scss | 120 ++ lib/sass/reset.scss | 22 + lib/sass/styles.scss | 110 ++ lib/sass/time-column.scss | 135 ++ lib/sass/time-grid.scss | 142 ++ lib/sass/toolbar.scss | 106 ++ lib/sass/variables.scss | 33 + lib/utils/DateSlotMetrics.js | 99 ++ lib/utils/DayEventLayout.js | 40 + lib/utils/Resources.js | 35 + lib/utils/TimeSlots.js | 157 +++ lib/utils/accessors.js | 33 + lib/utils/constants.js | 19 + lib/utils/dates.js | 193 +++ lib/utils/eventLevels.js | 126 ++ lib/utils/helpers.js | 31 + lib/utils/layout-algorithms/no-overlap.js | 119 ++ lib/utils/layout-algorithms/overlap.js | 234 ++++ lib/utils/messages.js | 37 + lib/utils/move.js | 52 + lib/utils/propTypes.js | 79 ++ lib/utils/selection.js | 88 ++ 72 files changed, 11327 insertions(+), 12 deletions(-) create mode 100644 lib/Agenda.js create mode 100644 lib/BackgroundCells.js create mode 100644 lib/BackgroundWrapper.js create mode 100644 lib/Calendar.js create mode 100644 lib/CalendarContext.js create mode 100644 lib/DateContentRow.js create mode 100644 lib/DateHeader.js create mode 100644 lib/Day.js create mode 100644 lib/DayColumn.js create mode 100644 lib/EventCell.js create mode 100644 lib/EventEndingRow.js create mode 100644 lib/EventRow.js create mode 100644 lib/EventRowMixin.js create mode 100644 lib/EventWrapper.js create mode 100644 lib/Header.js create mode 100644 lib/Month.js create mode 100644 lib/NoopWrapper.js create mode 100644 lib/Popup.js create mode 100644 lib/ResourceHeader.js create mode 100644 lib/ScrollableWeekWrapper.js create mode 100644 lib/Selection.js create mode 100644 lib/TimeGrid.js create mode 100644 lib/TimeGridEvent.js create mode 100644 lib/TimeGridHeader.js create mode 100644 lib/TimeGutter.js create mode 100644 lib/TimeSlotGroup.js create mode 100644 lib/Toolbar.js create mode 100644 lib/Views.js create mode 100644 lib/Week.js create mode 100644 lib/WorkWeek.js create mode 100644 lib/addons/dragAndDrop/DnDContext.js create mode 100644 lib/addons/dragAndDrop/EventContainerWrapper.js create mode 100644 lib/addons/dragAndDrop/EventWrapper.js create mode 100644 lib/addons/dragAndDrop/WeekWrapper.js create mode 100644 lib/addons/dragAndDrop/common.js create mode 100644 lib/addons/dragAndDrop/index.js create mode 100644 lib/addons/dragAndDrop/styles.css create mode 100644 lib/addons/dragAndDrop/styles.scss create mode 100644 lib/addons/dragAndDrop/withDragAndDrop.js create mode 100644 lib/css/react-big-calendar.css create mode 100644 lib/index.js create mode 100644 lib/localizer.js create mode 100644 lib/localizers/date-fns.js create mode 100644 lib/localizers/globalize.js create mode 100644 lib/localizers/moment.js create mode 100644 lib/localizers/oldGlobalize.js create mode 100644 lib/sass/agenda.scss create mode 100644 lib/sass/event.scss create mode 100644 lib/sass/month.scss create mode 100644 lib/sass/reset.scss create mode 100644 lib/sass/styles.scss create mode 100644 lib/sass/time-column.scss create mode 100644 lib/sass/time-grid.scss create mode 100644 lib/sass/toolbar.scss create mode 100644 lib/sass/variables.scss create mode 100644 lib/utils/DateSlotMetrics.js create mode 100644 lib/utils/DayEventLayout.js create mode 100644 lib/utils/Resources.js create mode 100644 lib/utils/TimeSlots.js create mode 100644 lib/utils/accessors.js create mode 100644 lib/utils/constants.js create mode 100644 lib/utils/dates.js create mode 100644 lib/utils/eventLevels.js create mode 100644 lib/utils/helpers.js create mode 100644 lib/utils/layout-algorithms/no-overlap.js create mode 100644 lib/utils/layout-algorithms/overlap.js create mode 100644 lib/utils/messages.js create mode 100644 lib/utils/move.js create mode 100644 lib/utils/propTypes.js create mode 100644 lib/utils/selection.js diff --git a/.gitignore b/.gitignore index 94dda071e..54510d6af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -lib/ +# lib/ dist/ # Logs diff --git a/.size-snapshot.json b/.size-snapshot.json index b6e1a03e1..6b64d6f7c 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 509547, - "minified": 149932, - "gzipped": 45769 + "bundled": 493239, + "minified": 154665, + "gzipped": 47351 }, "./dist/react-big-calendar.min.js": { - "bundled": 446246, - "minified": 130919, - "gzipped": 41339 + "bundled": 420519, + "minified": 131098, + "gzipped": 41400 }, "dist/react-big-calendar.esm.js": { - "bundled": 176376, - "minified": 84316, - "gzipped": 21023, + "bundled": 183071, + "minified": 87281, + "gzipped": 21627, "treeshaked": { "rollup": { - "code": 60196, + "code": 62394, "import_statements": 1590 }, "webpack": { - "code": 64714 + "code": 66954 } } } diff --git a/lib/Agenda.js b/lib/Agenda.js new file mode 100644 index 000000000..332eb24d1 --- /dev/null +++ b/lib/Agenda.js @@ -0,0 +1,333 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireWildcard(require('react')) + +var _addClass = _interopRequireDefault(require('dom-helpers/addClass')) + +var _removeClass = _interopRequireDefault(require('dom-helpers/removeClass')) + +var _width = _interopRequireDefault(require('dom-helpers/width')) + +var _scrollbarSize = _interopRequireDefault( + require('dom-helpers/scrollbarSize') +) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var _constants = require('./utils/constants') + +var _eventLevels = require('./utils/eventLevels') + +var _selection = require('./utils/selection') + +function Agenda(_ref) { + var selected = _ref.selected, + getters = _ref.getters, + accessors = _ref.accessors, + localizer = _ref.localizer, + components = _ref.components, + length = _ref.length, + date = _ref.date, + events = _ref.events + var headerRef = (0, _react.useRef)(null) + var dateColRef = (0, _react.useRef)(null) + var timeColRef = (0, _react.useRef)(null) + var contentRef = (0, _react.useRef)(null) + var tbodyRef = (0, _react.useRef)(null) + ;(0, _react.useEffect)(function() { + _adjustHeader() + }) + + var renderDay = function renderDay(day, events, dayKey) { + var Event = components.event, + AgendaDate = components.date + events = events.filter(function(e) { + return (0, + _eventLevels.inRange)(e, dates.startOf(day, 'day'), dates.endOf(day, 'day'), accessors) + }) + return events.map(function(event, idx) { + var title = accessors.title(event) + var end = accessors.end(event) + var start = accessors.start(event) + var userProps = getters.eventProp( + event, + start, + end, + (0, _selection.isSelected)(event, selected) + ) + var dateLabel = idx === 0 && localizer.format(day, 'agendaDateFormat') + var first = + idx === 0 + ? _react.default.createElement( + 'td', + { + rowSpan: events.length, + className: 'rbc-agenda-date-cell', + }, + AgendaDate + ? _react.default.createElement(AgendaDate, { + day: day, + label: dateLabel, + }) + : dateLabel + ) + : false + return _react.default.createElement( + 'tr', + { + key: dayKey + '_' + idx, + className: userProps.className, + style: userProps.style, + }, + first, + _react.default.createElement( + 'td', + { + className: 'rbc-agenda-time-cell', + }, + timeRangeLabel(day, event) + ), + _react.default.createElement( + 'td', + { + className: 'rbc-agenda-event-cell', + }, + Event + ? _react.default.createElement(Event, { + event: event, + title: title, + }) + : title + ) + ) + }, []) + } + + var timeRangeLabel = function timeRangeLabel(day, event) { + var labelClass = '', + TimeComponent = components.time, + label = localizer.messages.allDay + var end = accessors.end(event) + var start = accessors.start(event) + + if (!accessors.allDay(event)) { + if (dates.eq(start, end)) { + label = localizer.format(start, 'agendaTimeFormat') + } else if (dates.eq(start, end, 'day')) { + label = localizer.format( + { + start: start, + end: end, + }, + 'agendaTimeRangeFormat' + ) + } else if (dates.eq(day, start, 'day')) { + label = localizer.format(start, 'agendaTimeFormat') + } else if (dates.eq(day, end, 'day')) { + label = localizer.format(end, 'agendaTimeFormat') + } + } + + if (dates.gt(day, start, 'day')) labelClass = 'rbc-continues-prior' + if (dates.lt(day, end, 'day')) labelClass += ' rbc-continues-after' + return _react.default.createElement( + 'span', + { + className: labelClass.trim(), + }, + TimeComponent + ? _react.default.createElement(TimeComponent, { + event: event, + day: day, + label: label, + }) + : label + ) + } + + var _adjustHeader = function _adjustHeader() { + if (!tbodyRef.current) return + var header = headerRef.current + var firstRow = tbodyRef.current.firstChild + if (!firstRow) return + var isOverflowing = + contentRef.current.scrollHeight > contentRef.current.clientHeight + var _widths = [] + var widths = _widths + _widths = [ + (0, _width.default)(firstRow.children[0]), + (0, _width.default)(firstRow.children[1]), + ] + + if (widths[0] !== _widths[0] || widths[1] !== _widths[1]) { + dateColRef.current.style.width = _widths[0] + 'px' + timeColRef.current.style.width = _widths[1] + 'px' + } + + if (isOverflowing) { + ;(0, _addClass.default)(header, 'rbc-header-overflowing') + header.style.marginRight = (0, _scrollbarSize.default)() + 'px' + } else { + ;(0, _removeClass.default)(header, 'rbc-header-overflowing') + } + } + + var messages = localizer.messages + var end = dates.add(date, length, 'day') + var range = dates.range(date, end, 'day') + events = events.filter(function(event) { + return (0, _eventLevels.inRange)(event, date, end, accessors) + }) + events.sort(function(a, b) { + return +accessors.start(a) - +accessors.start(b) + }) + return _react.default.createElement( + 'div', + { + className: 'rbc-agenda-view', + }, + events.length !== 0 + ? _react.default.createElement( + _react.default.Fragment, + null, + _react.default.createElement( + 'table', + { + ref: headerRef, + className: 'rbc-agenda-table', + }, + _react.default.createElement( + 'thead', + null, + _react.default.createElement( + 'tr', + null, + _react.default.createElement( + 'th', + { + className: 'rbc-header', + ref: dateColRef, + }, + messages.date + ), + _react.default.createElement( + 'th', + { + className: 'rbc-header', + ref: timeColRef, + }, + messages.time + ), + _react.default.createElement( + 'th', + { + className: 'rbc-header', + }, + messages.event + ) + ) + ) + ), + _react.default.createElement( + 'div', + { + className: 'rbc-agenda-content', + ref: contentRef, + }, + _react.default.createElement( + 'table', + { + className: 'rbc-agenda-table', + }, + _react.default.createElement( + 'tbody', + { + ref: tbodyRef, + }, + range.map(function(day, idx) { + return renderDay(day, events, idx) + }) + ) + ) + ) + ) + : _react.default.createElement( + 'span', + { + className: 'rbc-agenda-empty', + }, + messages.noEventsInRange + ) + ) +} + +Agenda.propTypes = + process.env.NODE_ENV !== 'production' + ? { + events: _propTypes.default.array, + date: _propTypes.default.instanceOf(Date), + length: _propTypes.default.number.isRequired, + selected: _propTypes.default.object, + accessors: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + localizer: _propTypes.default.object.isRequired, + } + : {} +Agenda.defaultProps = { + length: 30, +} + +Agenda.range = function(start, _ref2) { + var _ref2$length = _ref2.length, + length = _ref2$length === void 0 ? Agenda.defaultProps.length : _ref2$length + var end = dates.add(start, length, 'day') + return { + start: start, + end: end, + } +} + +Agenda.navigate = function(date, action, _ref3) { + var _ref3$length = _ref3.length, + length = _ref3$length === void 0 ? Agenda.defaultProps.length : _ref3$length + + switch (action) { + case _constants.navigate.PREVIOUS: + return dates.add(date, -length, 'day') + + case _constants.navigate.NEXT: + return dates.add(date, length, 'day') + + default: + return date + } +} + +Agenda.title = function(start, _ref4) { + var _ref4$length = _ref4.length, + length = + _ref4$length === void 0 ? Agenda.defaultProps.length : _ref4$length, + localizer = _ref4.localizer + var end = dates.add(start, length, 'day') + return localizer.format( + { + start: start, + end: end, + }, + 'agendaHeaderFormat' + ) +} + +var _default = Agenda +exports.default = _default +module.exports = exports['default'] diff --git a/lib/BackgroundCells.js b/lib/BackgroundCells.js new file mode 100644 index 000000000..16682d16d --- /dev/null +++ b/lib/BackgroundCells.js @@ -0,0 +1,277 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _reactDom = require('react-dom') + +var _clsx = _interopRequireDefault(require('clsx')) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var _helpers = require('./utils/helpers') + +var _selection = require('./utils/selection') + +var _Selection = _interopRequireWildcard(require('./Selection')) + +var BackgroundCells = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(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.UNSAFE_componentWillReceiveProps = function UNSAFE_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.default.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.default.createElement( + Wrapper, + { + key: index, + value: date, + range: range, + }, + _react.default.createElement('div', { + style: style, + className: (0, _clsx.default)( + '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 = (0, _reactDom.findDOMNode)(this) + var selector = (this._selector = new _Selection.default( + this.props.container, + { + longPressThreshold: this.props.longPressThreshold, + } + )) + + var selectorClicksHandler = function selectorClicksHandler( + point, + actionType + ) { + if ( + !(0, _Selection.isEvent)((0, _reactDom.findDOMNode)(_this2), point) + ) { + var rowBox = (0, _Selection.getBoundsForNode)(node) + var _this2$props = _this2.props, + range = _this2$props.range, + rtl = _this2$props.rtl + + if ((0, _selection.pointInBox)(rowBox, point)) { + var currentCell = (0, _selection.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) { + ;(0, _helpers.notify)(_this2.props.onSelectStart, [box]) + _this2._initial = { + x: box.x, + y: box.y, + } + } + + if (selector.isSelected(node)) { + var nodeBox = (0, _Selection.getBoundsForNode)(node) + + var _dateCellSelection = (0, _selection.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 !(0, _Selection.isEvent)((0, _reactDom.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( + (0, _extends2.default)({}, _this2.state, { + action: 'select', + bounds: bounds, + }) + ) + + _this2._initial = {} + + _this2.setState({ + selecting: false, + }) + + ;(0, _helpers.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, + resourceId: this.props.resourceId, + }) + } + + return BackgroundCells + })(_react.default.Component) + +BackgroundCells.propTypes = + process.env.NODE_ENV !== 'production' + ? { + date: _propTypes.default.instanceOf(Date), + getNow: _propTypes.default.func.isRequired, + getters: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + container: _propTypes.default.func, + dayPropGetter: _propTypes.default.func, + selectable: _propTypes.default.oneOf([true, false, 'ignoreEvents']), + longPressThreshold: _propTypes.default.number, + onSelectSlot: _propTypes.default.func.isRequired, + onSelectEnd: _propTypes.default.func, + onSelectStart: _propTypes.default.func, + range: _propTypes.default.arrayOf(_propTypes.default.instanceOf(Date)), + rtl: _propTypes.default.bool, + type: _propTypes.default.string, + resourceId: _propTypes.default.any, + } + : {} +var _default = BackgroundCells +exports.default = _default +module.exports = exports['default'] diff --git a/lib/BackgroundWrapper.js b/lib/BackgroundWrapper.js new file mode 100644 index 000000000..b85ac653e --- /dev/null +++ b/lib/BackgroundWrapper.js @@ -0,0 +1,12 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _NoopWrapper = _interopRequireDefault(require('./NoopWrapper')) + +var _default = _NoopWrapper.default +exports.default = _default +module.exports = exports['default'] diff --git a/lib/Calendar.js b/lib/Calendar.js new file mode 100644 index 000000000..642f08222 --- /dev/null +++ b/lib/Calendar.js @@ -0,0 +1,1240 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _uncontrollable = require('uncontrollable') + +var _clsx = _interopRequireDefault(require('clsx')) + +var _propTypes2 = require('./utils/propTypes') + +var _helpers = require('./utils/helpers') + +var _constants = require('./utils/constants') + +var _localizer = require('./localizer') + +var _messages = _interopRequireDefault(require('./utils/messages')) + +var _move = _interopRequireDefault(require('./utils/move')) + +var _Views = _interopRequireDefault(require('./Views')) + +var _Toolbar = _interopRequireDefault(require('./Toolbar')) + +var _NoopWrapper = _interopRequireDefault(require('./NoopWrapper')) + +var _omit = _interopRequireDefault(require('lodash/omit')) + +var _defaults = _interopRequireDefault(require('lodash/defaults')) + +var _transform = _interopRequireDefault(require('lodash/transform')) + +var _mapValues = _interopRequireDefault(require('lodash/mapValues')) + +var _accessors = require('./utils/accessors') + +function viewNames(_views) { + return !Array.isArray(_views) ? Object.keys(_views) : _views +} + +function isValidView(view, _ref) { + var _views = _ref.views + var names = viewNames(_views) + return names.indexOf(view) !== -1 +} +/** + * react-big-calendar is a full featured Calendar component for managing events and dates. It uses + * modern `flexbox` for layout, making it super responsive and performant. Leaving most of the layout heavy lifting + * to the browser. __note:__ The default styles use `height: 100%` which means your container must set an explicit + * height (feel free to adjust the styles to suit your specific needs). + * + * Big Calendar is unopiniated about editing and moving events, preferring to let you implement it in a way that makes + * the most sense to your app. It also tries not to be prescriptive about your event data structures, just tell it + * how to find the start and end datetimes and you can pass it whatever you want. + * + * One thing to note is that, `react-big-calendar` treats event start/end dates as an _exclusive_ range. + * which means that the event spans up to, but not including, the end date. In the case + * of displaying events on whole days, end dates are rounded _up_ to the next day. So an + * event ending on `Apr 8th 12:00:00 am` will not appear on the 8th, whereas one ending + * on `Apr 8th 12:01:00 am` will. If you want _inclusive_ ranges consider providing a + * function `endAccessor` that returns the end date + 1 day for those events that end at midnight. + */ + +var Calendar = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(Calendar, _React$Component) + + function Calendar() { + 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.getViews = function() { + var views = _this.props.views + + if (Array.isArray(views)) { + return (0, _transform.default)( + views, + function(obj, name) { + return (obj[name] = _Views.default[name]) + }, + {} + ) + } + + if (typeof views === 'object') { + return (0, _mapValues.default)(views, function(value, key) { + if (value === true) { + return _Views.default[key] + } + + return value + }) + } + + return _Views.default + } + + _this.getView = function() { + var views = _this.getViews() + + return views[_this.props.view] + } + + _this.getDrilldownView = function(date) { + var _this$props = _this.props, + view = _this$props.view, + drilldownView = _this$props.drilldownView, + getDrilldownView = _this$props.getDrilldownView + if (!getDrilldownView) return drilldownView + return getDrilldownView(date, view, Object.keys(_this.getViews())) + } + + _this.handleRangeChange = function(date, viewComponent, view) { + var _this$props2 = _this.props, + onRangeChange = _this$props2.onRangeChange, + localizer = _this$props2.localizer + + if (onRangeChange) { + if (viewComponent.range) { + onRangeChange( + viewComponent.range(date, { + localizer: localizer, + }), + view + ) + } else { + if (process.env.NODE_ENV !== 'production') { + console.error('onRangeChange prop not supported for this view') + } + } + } + } + + _this.handleNavigate = function(action, newDate) { + var _this$props3 = _this.props, + view = _this$props3.view, + date = _this$props3.date, + getNow = _this$props3.getNow, + onNavigate = _this$props3.onNavigate, + props = (0, _objectWithoutPropertiesLoose2.default)(_this$props3, [ + 'view', + 'date', + 'getNow', + 'onNavigate', + ]) + + var ViewComponent = _this.getView() + + var today = getNow() + date = (0, _move.default)( + ViewComponent, + (0, _extends2.default)({}, props, { + action: action, + date: newDate || date || today, + today: today, + }) + ) + onNavigate(date, view, action) + + _this.handleRangeChange(date, ViewComponent) + } + + _this.handleViewChange = function(view) { + if (view !== _this.props.view && isValidView(view, _this.props)) { + _this.props.onView(view) + } + + var views = _this.getViews() + + _this.handleRangeChange( + _this.props.date || _this.props.getNow(), + views[view], + view + ) + } + + _this.handleSelectEvent = function() { + for ( + var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; + _key2 < _len2; + _key2++ + ) { + args[_key2] = arguments[_key2] + } + + ;(0, _helpers.notify)(_this.props.onSelectEvent, args) + } + + _this.handleDoubleClickEvent = function() { + for ( + var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; + _key3 < _len3; + _key3++ + ) { + args[_key3] = arguments[_key3] + } + + ;(0, _helpers.notify)(_this.props.onDoubleClickEvent, args) + } + + _this.handleKeyPressEvent = function() { + for ( + var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; + _key4 < _len4; + _key4++ + ) { + args[_key4] = arguments[_key4] + } + + ;(0, _helpers.notify)(_this.props.onKeyPressEvent, args) + } + + _this.handleSelectSlot = function(slotInfo) { + ;(0, _helpers.notify)(_this.props.onSelectSlot, slotInfo) + } + + _this.handleDrillDown = function(date, view) { + var onDrillDown = _this.props.onDrillDown + + if (onDrillDown) { + onDrillDown(date, view, _this.drilldownView) + return + } + + if (view) _this.handleViewChange(view) + + _this.handleNavigate(_constants.navigate.DATE, date) + } + + _this.state = { + context: _this.getContext(_this.props), + } + return _this + } + + var _proto = Calendar.prototype + + _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps( + nextProps + ) { + this.setState({ + context: this.getContext(nextProps), + }) + } + + _proto.getContext = function getContext(_ref2) { + var startAccessor = _ref2.startAccessor, + endAccessor = _ref2.endAccessor, + allDayAccessor = _ref2.allDayAccessor, + tooltipAccessor = _ref2.tooltipAccessor, + titleAccessor = _ref2.titleAccessor, + resourceAccessor = _ref2.resourceAccessor, + resourceIdAccessor = _ref2.resourceIdAccessor, + resourceTitleAccessor = _ref2.resourceTitleAccessor, + eventPropGetter = _ref2.eventPropGetter, + backgroundEventPropGetter = _ref2.backgroundEventPropGetter, + slotPropGetter = _ref2.slotPropGetter, + slotGroupPropGetter = _ref2.slotGroupPropGetter, + dayPropGetter = _ref2.dayPropGetter, + view = _ref2.view, + views = _ref2.views, + localizer = _ref2.localizer, + culture = _ref2.culture, + _ref2$messages = _ref2.messages, + messages = _ref2$messages === void 0 ? {} : _ref2$messages, + _ref2$components = _ref2.components, + components = _ref2$components === void 0 ? {} : _ref2$components, + _ref2$formats = _ref2.formats, + formats = _ref2$formats === void 0 ? {} : _ref2$formats + var names = viewNames(views) + var msgs = (0, _messages.default)(messages) + return { + viewNames: names, + localizer: (0, _localizer.mergeWithDefaults)( + localizer, + culture, + formats, + msgs + ), + getters: { + eventProp: function eventProp() { + return ( + (eventPropGetter && eventPropGetter.apply(void 0, arguments)) || + {} + ) + }, + backgroundEventProp: function backgroundEventProp() { + return ( + (backgroundEventPropGetter && + backgroundEventPropGetter.apply(void 0, arguments)) || + {} + ) + }, + slotProp: function slotProp() { + return ( + (slotPropGetter && slotPropGetter.apply(void 0, arguments)) || {} + ) + }, + slotGroupProp: function slotGroupProp() { + return ( + (slotGroupPropGetter && + slotGroupPropGetter.apply(void 0, arguments)) || + {} + ) + }, + dayProp: function dayProp() { + return ( + (dayPropGetter && dayPropGetter.apply(void 0, arguments)) || {} + ) + }, + }, + components: (0, _defaults.default)( + components[view] || {}, + (0, _omit.default)(components, names), + { + eventWrapper: _NoopWrapper.default, + backgroundEventWrapper: _NoopWrapper.default, + eventContainerWrapper: _NoopWrapper.default, + dateCellWrapper: _NoopWrapper.default, + weekWrapper: _NoopWrapper.default, + timeSlotWrapper: _NoopWrapper.default, + } + ), + accessors: { + start: (0, _accessors.wrapAccessor)(startAccessor), + end: (0, _accessors.wrapAccessor)(endAccessor), + allDay: (0, _accessors.wrapAccessor)(allDayAccessor), + tooltip: (0, _accessors.wrapAccessor)(tooltipAccessor), + title: (0, _accessors.wrapAccessor)(titleAccessor), + resource: (0, _accessors.wrapAccessor)(resourceAccessor), + resourceId: (0, _accessors.wrapAccessor)(resourceIdAccessor), + resourceTitle: (0, _accessors.wrapAccessor)(resourceTitleAccessor), + }, + } + } + + _proto.render = function render() { + var _this$props4 = this.props, + view = _this$props4.view, + toolbar = _this$props4.toolbar, + events = _this$props4.events, + _this$props4$backgrou = _this$props4.backgroundEvents, + backgroundEvents = + _this$props4$backgrou === void 0 ? [] : _this$props4$backgrou, + style = _this$props4.style, + className = _this$props4.className, + elementProps = _this$props4.elementProps, + current = _this$props4.date, + getNow = _this$props4.getNow, + length = _this$props4.length, + showMultiDayTimes = _this$props4.showMultiDayTimes, + onShowMore = _this$props4.onShowMore, + _0 = _this$props4.components, + _1 = _this$props4.formats, + _2 = _this$props4.messages, + _3 = _this$props4.culture, + props = (0, _objectWithoutPropertiesLoose2.default)(_this$props4, [ + 'view', + 'toolbar', + 'events', + 'backgroundEvents', + 'style', + 'className', + 'elementProps', + 'date', + 'getNow', + 'length', + 'showMultiDayTimes', + 'onShowMore', + 'components', + 'formats', + 'messages', + 'culture', + ]) + current = current || getNow() + var View = this.getView() + var _this$state$context = this.state.context, + accessors = _this$state$context.accessors, + components = _this$state$context.components, + getters = _this$state$context.getters, + localizer = _this$state$context.localizer, + viewNames = _this$state$context.viewNames + var CalToolbar = components.toolbar || _Toolbar.default + var label = View.title(current, { + localizer: localizer, + length: length, + }) + return _react.default.createElement( + 'div', + (0, _extends2.default)({}, elementProps, { + className: (0, _clsx.default)( + className, + 'rbc-calendar', + props.rtl && 'rbc-rtl' + ), + style: style, + }), + toolbar && + _react.default.createElement(CalToolbar, { + date: current, + view: view, + views: viewNames, + label: label, + onView: this.handleViewChange, + onNavigate: this.handleNavigate, + localizer: localizer, + }), + _react.default.createElement( + View, + (0, _extends2.default)({}, props, { + events: events, + backgroundEvents: backgroundEvents, + date: current, + getNow: getNow, + length: length, + localizer: localizer, + getters: getters, + components: components, + accessors: accessors, + showMultiDayTimes: showMultiDayTimes, + getDrilldownView: this.getDrilldownView, + onNavigate: this.handleNavigate, + onDrillDown: this.handleDrillDown, + onSelectEvent: this.handleSelectEvent, + onDoubleClickEvent: this.handleDoubleClickEvent, + onKeyPressEvent: this.handleKeyPressEvent, + onSelectSlot: this.handleSelectSlot, + onShowMore: onShowMore, + }) + ) + ) + } + /** + * + * @param date + * @param viewComponent + * @param {'month'|'week'|'work_week'|'day'|'agenda'} [view] - optional + * parameter. It appears when range change on view changing. It could be handy + * when you need to have both: range and view type at once, i.e. for manage rbc + * state via url + */ + + return Calendar + })(_react.default.Component) + +Calendar.defaultProps = { + elementProps: {}, + popup: false, + toolbar: true, + view: _constants.views.MONTH, + views: [ + _constants.views.MONTH, + _constants.views.WEEK, + _constants.views.DAY, + _constants.views.AGENDA, + ], + step: 30, + length: 30, + drilldownView: _constants.views.DAY, + titleAccessor: 'title', + tooltipAccessor: 'title', + allDayAccessor: 'allDay', + startAccessor: 'start', + endAccessor: 'end', + resourceAccessor: 'resourceId', + resourceIdAccessor: 'id', + resourceTitleAccessor: 'title', + longPressThreshold: 250, + getNow: function getNow() { + return new Date() + }, + dayLayoutAlgorithm: 'overlap', +} +Calendar.propTypes = + process.env.NODE_ENV !== 'production' + ? { + localizer: _propTypes.default.object.isRequired, + + /** + * Props passed to main calendar `
`. + * + */ + elementProps: _propTypes.default.object, + + /** + * The current date value of the calendar. Determines the visible view range. + * If `date` is omitted then the result of `getNow` is used; otherwise the + * current date is used. + * + * @controllable onNavigate + */ + date: _propTypes.default.instanceOf(Date), + + /** + * The current view of the calendar. + * + * @default 'month' + * @controllable onView + */ + view: _propTypes.default.string, + + /** + * The initial view set for the Calendar. + * @type Calendar.Views ('month'|'week'|'work_week'|'day'|'agenda') + * @default 'month' + */ + defaultView: _propTypes.default.string, + + /** + * An array of event objects to display on the calendar. Events objects + * can be any shape, as long as the Calendar knows how to retrieve the + * following details of the event: + * + * - start time + * - end time + * - title + * - whether its an "all day" event or not + * - any resource the event may be related to + * + * Each of these properties can be customized or generated dynamically by + * setting the various "accessor" props. Without any configuration the default + * event should look like: + * + * ```js + * Event { + * title: string, + * start: Date, + * end: Date, + * allDay?: boolean + * resource?: any, + * } + * ``` + */ + events: _propTypes.default.arrayOf(_propTypes.default.object), + + /** + * An array of background event objects to display on the calendar. Background + * Events behave similarly to Events but are not factored into Event overlap logic, + * allowing them to sit behind any Events that may occur during the same period. + * Background Events objects can be any shape, as long as the Calendar knows how to + * retrieve the following details of the event: + * + * - start time + * - end time + * + * Each of these properties can be customized or generated dynamically by + * setting the various "accessor" props. Without any configuration the default + * event should look like: + * + * ```js + * BackgroundEvent { + * start: Date, + * end: Date, + * } + * ``` + */ + backgroundEvents: _propTypes.default.arrayOf(_propTypes.default.object), + + /** + * Accessor for the event title, used to display event information. Should + * resolve to a `renderable` value. + * + * ```js + * string | (event: Object) => string + * ``` + * + * @type {(func|string)} + */ + titleAccessor: _propTypes2.accessor, + + /** + * Accessor for the event tooltip. Should + * resolve to a `renderable` value. Removes the tooltip if null. + * + * ```js + * string | (event: Object) => string + * ``` + * + * @type {(func|string)} + */ + tooltipAccessor: _propTypes2.accessor, + + /** + * Determines whether the event should be considered an "all day" event and ignore time. + * Must resolve to a `boolean` value. + * + * ```js + * string | (event: Object) => boolean + * ``` + * + * @type {(func|string)} + */ + allDayAccessor: _propTypes2.accessor, + + /** + * The start date/time of the event. Must resolve to a JavaScript `Date` object. + * + * ```js + * string | (event: Object) => Date + * ``` + * + * @type {(func|string)} + */ + startAccessor: _propTypes2.accessor, + + /** + * The end date/time of the event. Must resolve to a JavaScript `Date` object. + * + * ```js + * string | (event: Object) => Date + * ``` + * + * @type {(func|string)} + */ + endAccessor: _propTypes2.accessor, + + /** + * Returns the id of the `resource` that the event is a member of. This + * id should match at least one resource in the `resources` array. + * + * ```js + * string | (event: Object) => Date + * ``` + * + * @type {(func|string)} + */ + resourceAccessor: _propTypes2.accessor, + + /** + * An array of resource objects that map events to a specific resource. + * Resource objects, like events, can be any shape or have any properties, + * but should be uniquly identifiable via the `resourceIdAccessor`, as + * well as a "title" or name as provided by the `resourceTitleAccessor` prop. + */ + resources: _propTypes.default.arrayOf(_propTypes.default.object), + + /** + * Provides a unique identifier for each resource in the `resources` array + * + * ```js + * string | (resource: Object) => any + * ``` + * + * @type {(func|string)} + */ + resourceIdAccessor: _propTypes2.accessor, + + /** + * Provides a human readable name for the resource object, used in headers. + * + * ```js + * string | (resource: Object) => any + * ``` + * + * @type {(func|string)} + */ + resourceTitleAccessor: _propTypes2.accessor, + + /** + * Determines the current date/time which is highlighted in the views. + * + * The value affects which day is shaded and which time is shown as + * the current time. It also affects the date used by the Today button in + * the toolbar. + * + * Providing a value here can be useful when you are implementing time zones + * using the `startAccessor` and `endAccessor` properties. + * + * @type {func} + * @default () => new Date() + */ + getNow: _propTypes.default.func, + + /** + * Callback fired when the `date` value changes. + * + * @controllable date + */ + onNavigate: _propTypes.default.func, + + /** + * Callback fired when the `view` value changes. + * + * @controllable view + */ + onView: _propTypes.default.func, + + /** + * Callback fired when date header, or the truncated events links are clicked + * + */ + onDrillDown: _propTypes.default.func, + + /** + * + * ```js + * (dates: Date[] | { start: Date; end: Date }, view: 'month'|'week'|'work_week'|'day'|'agenda'|undefined) => void + * ``` + * + * Callback fired when the visible date range changes. Returns an Array of dates + * or an object with start and end dates for BUILTIN views. Optionally new `view` + * will be returned when callback called after view change. + * + * Custom views may return something different. + */ + onRangeChange: _propTypes.default.func, + + /** + * A callback fired when a date selection is made. Only fires when `selectable` is `true`. + * + * ```js + * ( + * slotInfo: { + * start: Date, + * end: Date, + * resourceId: (number|string), + * slots: Array, + * action: "select" | "click" | "doubleClick", + * bounds: ?{ // For "select" action + * x: number, + * y: number, + * top: number, + * right: number, + * left: number, + * bottom: number, + * }, + * box: ?{ // For "click" or "doubleClick" actions + * clientX: number, + * clientY: number, + * x: number, + * y: number, + * }, + * } + * ) => any + * ``` + */ + onSelectSlot: _propTypes.default.func, + + /** + * Callback fired when a calendar event is selected. + * + * ```js + * (event: Object, e: SyntheticEvent) => any + * ``` + * + * @controllable selected + */ + onSelectEvent: _propTypes.default.func, + + /** + * Callback fired when a calendar event is clicked twice. + * + * ```js + * (event: Object, e: SyntheticEvent) => void + * ``` + */ + onDoubleClickEvent: _propTypes.default.func, + + /** + * Callback fired when a focused calendar event recieves a key press. + * + * ```js + * (event: Object, e: SyntheticEvent) => void + * ``` + */ + onKeyPressEvent: _propTypes.default.func, + + /** + * Callback fired when dragging a selection in the Time views. + * + * Returning `false` from the handler will prevent a selection. + * + * ```js + * (range: { start: Date, end: Date, resourceId: (number|string) }) => ?boolean + * ``` + */ + onSelecting: _propTypes.default.func, + + /** + * Callback fired when a +{count} more is clicked + * + * ```js + * (events: Object, date: Date) => any + * ``` + */ + onShowMore: _propTypes.default.func, + + /** + * Displays all events on the month view instead of + * having some hidden behind +{count} more. This will + * cause the rows in the month view to be scrollable if + * the number of events exceed the height of the row. + */ + showAllEvents: _propTypes.default.bool, + + /** + * The selected event, if any. + */ + selected: _propTypes.default.object, + + /** + * An array of built-in view names to allow the calendar to display. + * accepts either an array of builtin view names, + * + * ```jsx + * views={['month', 'day', 'agenda']} + * ``` + * or an object hash of the view name and the component (or boolean for builtin). + * + * ```jsx + * views={{ + * month: true, + * week: false, + * myweek: WorkWeekViewComponent, + * }} + * ``` + * + * Custom views can be any React component, that implements the following + * interface: + * + * ```js + * interface View { + * static title(date: Date, { formats: DateFormat[], culture: string?, ...props }): string + * static navigate(date: Date, action: 'PREV' | 'NEXT' | 'DATE'): Date + * } + * ``` + * + * @type Views ('month'|'week'|'work_week'|'day'|'agenda') + * @View + ['month', 'week', 'day', 'agenda'] + */ + views: _propTypes2.views, + + /** + * The string name of the destination view for drill-down actions, such + * as clicking a date header, or the truncated events links. If + * `getDrilldownView` is also specified it will be used instead. + * + * Set to `null` to disable drill-down actions. + * + * ```js + * + * ``` + */ + drilldownView: _propTypes.default.string, + + /** + * Functionally equivalent to `drilldownView`, but accepts a function + * that can return a view name. It's useful for customizing the drill-down + * actions depending on the target date and triggering view. + * + * Return `null` to disable drill-down actions. + * + * ```js + * + * if (currentViewName === 'month' && configuredViewNames.includes('week')) + * return 'week' + * + * return null; + * }} + * /> + * ``` + */ + getDrilldownView: _propTypes.default.func, + + /** + * Determines the end date from date prop in the agenda view + * date prop + length (in number of days) = end date + */ + length: _propTypes.default.number, + + /** + * Determines whether the toolbar is displayed + */ + toolbar: _propTypes.default.bool, + + /** + * Show truncated events in an overlay when you click the "+_x_ more" link. + */ + popup: _propTypes.default.bool, + + /** + * Distance in pixels, from the edges of the viewport, the "show more" overlay should be positioned. + * + * ```jsx + * + * + * ``` + */ + popupOffset: _propTypes.default.oneOfType([ + _propTypes.default.number, + _propTypes.default.shape({ + x: _propTypes.default.number, + y: _propTypes.default.number, + }), + ]), + + /** + * Allows mouse selection of ranges of dates/times. + * + * The 'ignoreEvents' option prevents selection code from running when a + * drag begins over an event. Useful when you want custom event click or drag + * logic + */ + selectable: _propTypes.default.oneOf([true, false, 'ignoreEvents']), + + /** + * Specifies the number of miliseconds the user must press and hold on the screen for a touch + * to be considered a "long press." Long presses are used for time slot selection on touch + * devices. + * + * @type {number} + * @default 250 + */ + longPressThreshold: _propTypes.default.number, + + /** + * Determines the selectable time increments in week and day views, in minutes. + */ + step: _propTypes.default.number, + + /** + * The number of slots per "section" in the time grid views. Adjust with `step` + * to change the default of 1 hour long groups, with 30 minute slots. + */ + timeslots: _propTypes.default.number, + + /** + *Switch the calendar to a `right-to-left` read direction. + */ + rtl: _propTypes.default.bool, + + /** + * Optionally provide a function that returns an object of className or style props + * to be applied to the the event node. + * + * ```js + * ( + * event: Object, + * start: Date, + * end: Date, + * isSelected: boolean + * ) => { className?: string, style?: Object } + * ``` + */ + eventPropGetter: _propTypes.default.func, + + /** + * Optionally provide a function that returns an object of className or style props + * to be applied to the time-slot node. Caution! Styles that change layout or + * position may break the calendar in unexpected ways. + * + * ```js + * (date: Date, resourceId: (number|string)) => { className?: string, style?: Object } + * ``` + */ + slotPropGetter: _propTypes.default.func, + + /** + * Optionally provide a function that returns an object of props to be applied + * to the time-slot group node. Useful to dynamically change the sizing of time nodes. + * ```js + * () => { style?: Object } + * ``` + */ + slotGroupPropGetter: _propTypes.default.func, + + /** + * Optionally provide a function that returns an object of className or style props + * to be applied to the the day background. Caution! Styles that change layout or + * position may break the calendar in unexpected ways. + * + * ```js + * (date: Date) => { className?: string, style?: Object } + * ``` + */ + dayPropGetter: _propTypes.default.func, + + /** + * Support to show multi-day events with specific start and end times in the + * main time grid (rather than in the all day header). + * + * **Note: This may cause calendars with several events to look very busy in + * the week and day views.** + */ + showMultiDayTimes: _propTypes.default.bool, + + /** + * Constrains the minimum _time_ of the Day and Week views. + */ + min: _propTypes.default.instanceOf(Date), + + /** + * Constrains the maximum _time_ of the Day and Week views. + */ + max: _propTypes.default.instanceOf(Date), + + /** + * Determines how far down the scroll pane is initially scrolled down. + */ + scrollToTime: _propTypes.default.instanceOf(Date), + + /** + * Specify a specific culture code for the Calendar. + * + * **Note: it's generally better to handle this globally via your i18n library.** + */ + culture: _propTypes.default.string, + + /** + * Localizer specific formats, tell the Calendar how to format and display dates. + * + * `format` types are dependent on the configured localizer; both Moment and Globalize + * accept strings of tokens according to their own specification, such as: `'DD mm yyyy'`. + * + * ```jsx + * let formats = { + * dateFormat: 'dd', + * + * dayFormat: (date, , localizer) => + * localizer.format(date, 'DDD', culture), + * + * dayRangeHeaderFormat: ({ start, end }, culture, localizer) => + * localizer.format(start, { date: 'short' }, culture) + ' – ' + + * localizer.format(end, { date: 'short' }, culture) + * } + * + * + * ``` + * + * All localizers accept a function of + * the form `(date: Date, culture: ?string, localizer: Localizer) -> string` + */ + formats: _propTypes.default.shape({ + /** + * Format for the day of the month heading in the Month view. + * e.g. "01", "02", "03", etc + */ + dateFormat: _propTypes2.dateFormat, + + /** + * A day of the week format for Week and Day headings, + * e.g. "Wed 01/04" + * + */ + dayFormat: _propTypes2.dateFormat, + + /** + * Week day name format for the Month week day headings, + * e.g: "Sun", "Mon", "Tue", etc + * + */ + weekdayFormat: _propTypes2.dateFormat, + + /** + * The timestamp cell formats in Week and Time views, e.g. "4:00 AM" + */ + timeGutterFormat: _propTypes2.dateFormat, + + /** + * Toolbar header format for the Month view, e.g "2015 April" + * + */ + monthHeaderFormat: _propTypes2.dateFormat, + + /** + * Toolbar header format for the Week views, e.g. "Mar 29 - Apr 04" + */ + dayRangeHeaderFormat: _propTypes2.dateRangeFormat, + + /** + * Toolbar header format for the Day view, e.g. "Wednesday Apr 01" + */ + dayHeaderFormat: _propTypes2.dateFormat, + + /** + * Toolbar header format for the Agenda view, e.g. "4/1/2015 – 5/1/2015" + */ + agendaHeaderFormat: _propTypes2.dateRangeFormat, + + /** + * A time range format for selecting time slots, e.g "8:00am – 2:00pm" + */ + selectRangeFormat: _propTypes2.dateRangeFormat, + agendaDateFormat: _propTypes2.dateFormat, + agendaTimeFormat: _propTypes2.dateFormat, + agendaTimeRangeFormat: _propTypes2.dateRangeFormat, + + /** + * Time range displayed on events. + */ + eventTimeRangeFormat: _propTypes2.dateRangeFormat, + + /** + * An optional event time range for events that continue onto another day + */ + eventTimeRangeStartFormat: _propTypes2.dateFormat, + + /** + * An optional event time range for events that continue from another day + */ + eventTimeRangeEndFormat: _propTypes2.dateFormat, + }), + + /** + * Customize how different sections of the calendar render by providing custom Components. + * In particular the `Event` component can be specified for the entire calendar, or you can + * provide an individual component for each view type. + * + * ```jsx + * let components = { + * event: MyEvent, // used by each view (Month, Day, Week) + * eventWrapper: MyEventWrapper, + * eventContainerWrapper: MyEventContainerWrapper, + * dateCellWrapper: MyDateCellWrapper, + * timeSlotWrapper: MyTimeSlotWrapper, + * timeGutterHeader: MyTimeGutterWrapper, + * toolbar: MyToolbar, + * agenda: { + * event: MyAgendaEvent // with the agenda view use a different component to render events + * time: MyAgendaTime, + * date: MyAgendaDate, + * }, + * day: { + * header: MyDayHeader, + * event: MyDayEvent, + * }, + * week: { + * header: MyWeekHeader, + * event: MyWeekEvent, + * }, + * month: { + * header: MyMonthHeader, + * dateHeader: MyMonthDateHeader, + * event: MyMonthEvent, + * } + * } + * + * ``` + */ + components: _propTypes.default.shape({ + event: _propTypes.default.elementType, + eventWrapper: _propTypes.default.elementType, + eventContainerWrapper: _propTypes.default.elementType, + dateCellWrapper: _propTypes.default.elementType, + timeSlotWrapper: _propTypes.default.elementType, + timeGutterHeader: _propTypes.default.elementType, + resourceHeader: _propTypes.default.elementType, + toolbar: _propTypes.default.elementType, + agenda: _propTypes.default.shape({ + date: _propTypes.default.elementType, + time: _propTypes.default.elementType, + event: _propTypes.default.elementType, + }), + day: _propTypes.default.shape({ + header: _propTypes.default.elementType, + event: _propTypes.default.elementType, + }), + week: _propTypes.default.shape({ + header: _propTypes.default.elementType, + event: _propTypes.default.elementType, + }), + month: _propTypes.default.shape({ + header: _propTypes.default.elementType, + dateHeader: _propTypes.default.elementType, + event: _propTypes.default.elementType, + }), + }), + + /** + * String messages used throughout the component, override to provide localizations + */ + messages: _propTypes.default.shape({ + allDay: _propTypes.default.node, + previous: _propTypes.default.node, + next: _propTypes.default.node, + today: _propTypes.default.node, + month: _propTypes.default.node, + week: _propTypes.default.node, + day: _propTypes.default.node, + agenda: _propTypes.default.node, + date: _propTypes.default.node, + time: _propTypes.default.node, + event: _propTypes.default.node, + noEventsInRange: _propTypes.default.node, + showMore: _propTypes.default.func, + }), + + /** + * A day event layout(arrangement) algorithm. + * `overlap` allows events to be overlapped. + * `no-overlap` resizes events to avoid overlap. + * or custom `Function(events, minimumStartDifference, slotMetrics, accessors)` + */ + dayLayoutAlgorithm: _propTypes2.DayLayoutAlgorithmPropType, + } + : {} + +var _default = (0, _uncontrollable.uncontrollable)(Calendar, { + view: 'onView', + date: 'onNavigate', + selected: 'onSelectEvent', +}) + +exports.default = _default +module.exports = exports['default'] diff --git a/lib/CalendarContext.js b/lib/CalendarContext.js new file mode 100644 index 000000000..47c59ebc1 --- /dev/null +++ b/lib/CalendarContext.js @@ -0,0 +1,13 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _react = _interopRequireDefault(require('react')) + +var _default = _react.default.createContext() + +exports.default = _default +module.exports = exports['default'] diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js new file mode 100644 index 000000000..3e31bfe43 --- /dev/null +++ b/lib/DateContentRow.js @@ -0,0 +1,373 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _assertThisInitialized2 = _interopRequireDefault( + require('@babel/runtime/helpers/assertThisInitialized') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _clsx = _interopRequireDefault(require('clsx')) + +var _height = _interopRequireDefault(require('dom-helpers/height')) + +var _querySelectorAll = _interopRequireDefault( + require('dom-helpers/querySelectorAll') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _reactDom = require('react-dom') + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var _BackgroundCells = _interopRequireDefault(require('./BackgroundCells')) + +var _EventRow = _interopRequireDefault(require('./EventRow')) + +var _EventEndingRow = _interopRequireDefault(require('./EventEndingRow')) + +var _NoopWrapper = _interopRequireDefault(require('./NoopWrapper')) + +var _ScrollableWeekWrapper = _interopRequireDefault( + require('./ScrollableWeekWrapper') +) + +var DateSlotMetrics = _interopRequireWildcard( + require('./utils/DateSlotMetrics') +) + +var DateContentRow = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(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.handleShowMore = function(slot, target) { + var _this$props2 = _this.props, + range = _this$props2.range, + onShowMore = _this$props2.onShowMore + + var metrics = _this.slotMetrics(_this.props) + + var row = (0, _querySelectorAll.default)( + (0, _reactDom.findDOMNode)( + (0, _assertThisInitialized2.default)(_this) + ), + '.rbc-row-bg' + )[0] + var cell + if (row) cell = row.children[slot - 1] + var events = metrics.getEventsForSlot(slot) + onShowMore(events, range[slot - 1], cell, slot, target) + } + + _this.createHeadingRef = function(r) { + _this.headingRow = r + } + + _this.createEventRef = function(r) { + _this.eventRow = r + } + + _this.getContainer = function() { + var container = _this.props.container + return container + ? container() + : (0, _reactDom.findDOMNode)( + (0, _assertThisInitialized2.default)(_this) + ) + } + + _this.renderHeadingCell = function(date, index) { + var _this$props3 = _this.props, + renderHeader = _this$props3.renderHeader, + getNow = _this$props3.getNow + return renderHeader({ + date: date, + key: 'header_' + index, + className: (0, _clsx.default)( + 'rbc-date-cell', + dates.eq(date, getNow(), 'day') && 'rbc-now' + ), + }) + } + + _this.renderDummy = function() { + var _this$props4 = _this.props, + className = _this$props4.className, + range = _this$props4.range, + renderHeader = _this$props4.renderHeader, + showAllEvents = _this$props4.showAllEvents + return _react.default.createElement( + 'div', + { + className: className, + }, + _react.default.createElement( + 'div', + { + className: (0, _clsx.default)( + 'rbc-row-content', + showAllEvents && 'rbc-row-content-scrollable' + ), + }, + renderHeader && + _react.default.createElement( + 'div', + { + className: 'rbc-row', + ref: _this.createHeadingRef, + }, + range.map(_this.renderHeadingCell) + ), + _react.default.createElement( + 'div', + { + className: 'rbc-row', + ref: _this.createEventRef, + }, + _react.default.createElement( + 'div', + { + className: 'rbc-row-segment', + }, + _react.default.createElement( + 'div', + { + className: 'rbc-event', + }, + _react.default.createElement( + 'div', + { + className: 'rbc-event-content', + }, + '\xA0' + ) + ) + ) + ) + ) + ) + } + + _this.slotMetrics = DateSlotMetrics.getSlotMetrics() + return _this + } + + var _proto = DateContentRow.prototype + + _proto.getRowLimit = function getRowLimit() { + var eventHeight = (0, _height.default)(this.eventRow) + var headingHeight = this.headingRow + ? (0, _height.default)(this.headingRow) + : 0 + var eventSpace = + (0, _height.default)((0, _reactDom.findDOMNode)(this)) - headingHeight + return Math.max(Math.floor(eventSpace / eventHeight), 1) + } + + _proto.render = function render() { + var _this$props5 = this.props, + date = _this$props5.date, + rtl = _this$props5.rtl, + range = _this$props5.range, + className = _this$props5.className, + selected = _this$props5.selected, + selectable = _this$props5.selectable, + renderForMeasure = _this$props5.renderForMeasure, + accessors = _this$props5.accessors, + getters = _this$props5.getters, + components = _this$props5.components, + getNow = _this$props5.getNow, + renderHeader = _this$props5.renderHeader, + onSelect = _this$props5.onSelect, + localizer = _this$props5.localizer, + onSelectStart = _this$props5.onSelectStart, + onSelectEnd = _this$props5.onSelectEnd, + onDoubleClick = _this$props5.onDoubleClick, + onKeyPress = _this$props5.onKeyPress, + resourceId = _this$props5.resourceId, + longPressThreshold = _this$props5.longPressThreshold, + isAllDay = _this$props5.isAllDay, + resizable = _this$props5.resizable, + showAllEvents = _this$props5.showAllEvents + if (renderForMeasure) return this.renderDummy() + var metrics = this.slotMetrics(this.props) + var levels = metrics.levels, + extra = metrics.extra + var ScrollableWeekComponent = showAllEvents + ? _ScrollableWeekWrapper.default + : _NoopWrapper.default + var WeekWrapper = components.weekWrapper + var eventRowProps = { + selected: selected, + accessors: accessors, + getters: getters, + localizer: localizer, + components: components, + onSelect: onSelect, + onDoubleClick: onDoubleClick, + onKeyPress: onKeyPress, + resourceId: resourceId, + slotMetrics: metrics, + resizable: resizable, + } + return _react.default.createElement( + 'div', + { + className: className, + role: 'rowgroup', + }, + _react.default.createElement(_BackgroundCells.default, { + date: date, + getNow: getNow, + rtl: rtl, + range: range, + selectable: selectable, + container: this.getContainer, + getters: getters, + onSelectStart: onSelectStart, + onSelectEnd: onSelectEnd, + onSelectSlot: this.handleSelectSlot, + components: components, + longPressThreshold: longPressThreshold, + resourceId: resourceId, + }), + _react.default.createElement( + 'div', + { + className: (0, _clsx.default)( + 'rbc-row-content', + showAllEvents && 'rbc-row-content-scrollable' + ), + role: 'row', + }, + renderHeader && + _react.default.createElement( + 'div', + { + className: 'rbc-row ', + ref: this.createHeadingRef, + }, + range.map(this.renderHeadingCell) + ), + _react.default.createElement( + ScrollableWeekComponent, + null, + _react.default.createElement( + WeekWrapper, + (0, _extends2.default)( + { + isAllDay: isAllDay, + }, + eventRowProps + ), + levels.map(function(segs, idx) { + return _react.default.createElement( + _EventRow.default, + (0, _extends2.default)( + { + key: idx, + segments: segs, + }, + eventRowProps + ) + ) + }), + !!extra.length && + _react.default.createElement( + _EventEndingRow.default, + (0, _extends2.default)( + { + segments: extra, + onShowMore: this.handleShowMore, + }, + eventRowProps + ) + ) + ) + ) + ) + ) + } + + return DateContentRow + })(_react.default.Component) + +DateContentRow.propTypes = + process.env.NODE_ENV !== 'production' + ? { + date: _propTypes.default.instanceOf(Date), + events: _propTypes.default.array.isRequired, + range: _propTypes.default.array.isRequired, + rtl: _propTypes.default.bool, + resizable: _propTypes.default.bool, + resourceId: _propTypes.default.any, + renderForMeasure: _propTypes.default.bool, + renderHeader: _propTypes.default.func, + container: _propTypes.default.func, + selected: _propTypes.default.object, + selectable: _propTypes.default.oneOf([true, false, 'ignoreEvents']), + longPressThreshold: _propTypes.default.number, + onShowMore: _propTypes.default.func, + showAllEvents: _propTypes.default.bool, + onSelectSlot: _propTypes.default.func, + onSelect: _propTypes.default.func, + onSelectEnd: _propTypes.default.func, + onSelectStart: _propTypes.default.func, + onDoubleClick: _propTypes.default.func, + onKeyPress: _propTypes.default.func, + dayPropGetter: _propTypes.default.func, + getNow: _propTypes.default.func.isRequired, + isAllDay: _propTypes.default.bool, + accessors: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + localizer: _propTypes.default.object.isRequired, + minRows: _propTypes.default.number.isRequired, + maxRows: _propTypes.default.number.isRequired, + } + : {} +DateContentRow.defaultProps = { + minRows: 0, + maxRows: Infinity, +} +var _default = DateContentRow +exports.default = _default +module.exports = exports['default'] diff --git a/lib/DateHeader.js b/lib/DateHeader.js new file mode 100644 index 000000000..7d32a6f32 --- /dev/null +++ b/lib/DateHeader.js @@ -0,0 +1,44 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var DateHeader = function DateHeader(_ref) { + var label = _ref.label, + drilldownView = _ref.drilldownView, + onDrillDown = _ref.onDrillDown + + if (!drilldownView) { + return _react.default.createElement('span', null, label) + } + + return _react.default.createElement( + 'a', + { + href: '#', + onClick: onDrillDown, + role: 'cell', + }, + label + ) +} + +DateHeader.propTypes = + process.env.NODE_ENV !== 'production' + ? { + label: _propTypes.default.node, + date: _propTypes.default.instanceOf(Date), + drilldownView: _propTypes.default.string, + onDrillDown: _propTypes.default.func, + isOffRange: _propTypes.default.bool, + } + : {} +var _default = DateHeader +exports.default = _default +module.exports = exports['default'] diff --git a/lib/Day.js b/lib/Day.js new file mode 100644 index 000000000..579cbcbb1 --- /dev/null +++ b/lib/Day.js @@ -0,0 +1,93 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var _constants = require('./utils/constants') + +var _TimeGrid = _interopRequireDefault(require('./TimeGrid')) + +var Day = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(Day, _React$Component) + + function Day() { + return _React$Component.apply(this, arguments) || this + } + + var _proto = Day.prototype + + _proto.render = function render() { + var _this$props = this.props, + date = _this$props.date, + props = (0, _objectWithoutPropertiesLoose2.default)(_this$props, [ + 'date', + ]) + var range = Day.range(date) + return _react.default.createElement( + _TimeGrid.default, + (0, _extends2.default)({}, props, { + range: range, + eventOffset: 10, + }) + ) + } + + return Day + })(_react.default.Component) + +Day.propTypes = + process.env.NODE_ENV !== 'production' + ? { + date: _propTypes.default.instanceOf(Date).isRequired, + } + : {} + +Day.range = function(date) { + return [dates.startOf(date, 'day')] +} + +Day.navigate = function(date, action) { + switch (action) { + case _constants.navigate.PREVIOUS: + return dates.add(date, -1, 'day') + + case _constants.navigate.NEXT: + return dates.add(date, 1, 'day') + + default: + return date + } +} + +Day.title = function(date, _ref) { + var localizer = _ref.localizer + return localizer.format(date, 'dayHeaderFormat') +} + +var _default = Day +exports.default = _default +module.exports = exports['default'] diff --git a/lib/DayColumn.js b/lib/DayColumn.js new file mode 100644 index 000000000..079781ecf --- /dev/null +++ b/lib/DayColumn.js @@ -0,0 +1,624 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _assertThisInitialized2 = _interopRequireDefault( + require('@babel/runtime/helpers/assertThisInitialized') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _reactDom = require('react-dom') + +var _clsx = _interopRequireDefault(require('clsx')) + +var _Selection = _interopRequireWildcard(require('./Selection')) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var TimeSlotUtils = _interopRequireWildcard(require('./utils/TimeSlots')) + +var _selection = require('./utils/selection') + +var _helpers = require('./utils/helpers') + +var DayEventLayout = _interopRequireWildcard(require('./utils/DayEventLayout')) + +var _TimeSlotGroup = _interopRequireDefault(require('./TimeSlotGroup')) + +var _TimeGridEvent = _interopRequireDefault(require('./TimeGridEvent')) + +var _propTypes2 = require('./utils/propTypes') + +var DayColumn = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(DayColumn, _React$Component) + + function DayColumn() { + 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.state = { + selecting: false, + timeIndicatorPosition: null, + } + _this.intervalTriggered = false + + _this.renderEvents = function(_ref) { + var events = _ref.events, + isBackgroundEvent = _ref.isBackgroundEvent + var _this$props = _this.props, + rtl = _this$props.rtl, + selected = _this$props.selected, + accessors = _this$props.accessors, + localizer = _this$props.localizer, + getters = _this$props.getters, + components = _this$props.components, + step = _this$props.step, + timeslots = _this$props.timeslots, + dayLayoutAlgorithm = _this$props.dayLayoutAlgorithm, + resizable = _this$props.resizable + + var _assertThisInitialize = (0, _assertThisInitialized2.default)(_this), + slotMetrics = _assertThisInitialize.slotMetrics + + var messages = localizer.messages + var styledEvents = DayEventLayout.getStyledEvents({ + events: events, + accessors: accessors, + slotMetrics: slotMetrics, + minimumStartDifference: Math.ceil((step * timeslots) / 2), + dayLayoutAlgorithm: dayLayoutAlgorithm, + }) + return styledEvents.map(function(_ref2, idx) { + var event = _ref2.event, + style = _ref2.style + var end = accessors.end(event) + var start = accessors.start(event) + var format = 'eventTimeRangeFormat' + var label + var startsBeforeDay = slotMetrics.startsBeforeDay(start) + var startsAfterDay = slotMetrics.startsAfterDay(end) + if (startsBeforeDay) format = 'eventTimeRangeEndFormat' + else if (startsAfterDay) format = 'eventTimeRangeStartFormat' + if (startsBeforeDay && startsAfterDay) label = messages.allDay + else + label = localizer.format( + { + start: start, + end: end, + }, + format + ) + var continuesEarlier = + startsBeforeDay || slotMetrics.startsBefore(start) + var continuesLater = startsAfterDay || slotMetrics.startsAfter(end) + return _react.default.createElement(_TimeGridEvent.default, { + style: style, + event: event, + label: label, + key: 'evt_' + idx, + getters: getters, + rtl: rtl, + components: components, + continuesEarlier: continuesEarlier, + continuesLater: continuesLater, + accessors: accessors, + selected: (0, _selection.isSelected)(event, selected), + onClick: function onClick(e) { + return _this._select(event, e) + }, + onDoubleClick: function onDoubleClick(e) { + return _this._doubleClick(event, e) + }, + isBackgroundEvent: isBackgroundEvent, + onKeyPress: function onKeyPress(e) { + return _this._keyPress(event, e) + }, + resizable: resizable, + }) + }) + } + + _this._selectable = function() { + var node = (0, _reactDom.findDOMNode)( + (0, _assertThisInitialized2.default)(_this) + ) + var selector = (_this._selector = new _Selection.default( + function() { + return (0, _reactDom.findDOMNode)( + (0, _assertThisInitialized2.default)(_this) + ) + }, + { + longPressThreshold: _this.props.longPressThreshold, + } + )) + + var maybeSelect = function maybeSelect(box) { + var onSelecting = _this.props.onSelecting + var current = _this.state || {} + var state = selectionState(box) + var start = state.startDate, + end = state.endDate + + if (onSelecting) { + if ( + (dates.eq(current.startDate, start, 'minutes') && + dates.eq(current.endDate, end, 'minutes')) || + onSelecting({ + start: start, + end: end, + resourceId: _this.props.resource, + }) === false + ) + return + } + + if ( + _this.state.start !== state.start || + _this.state.end !== state.end || + _this.state.selecting !== state.selecting + ) { + _this.setState(state) + } + } + + var selectionState = function selectionState(point) { + var currentSlot = _this.slotMetrics.closestSlotFromPoint( + point, + (0, _Selection.getBoundsForNode)(node) + ) + + if (!_this.state.selecting) { + _this._initialSlot = currentSlot + } + + var initialSlot = _this._initialSlot + + if (dates.lte(initialSlot, currentSlot)) { + currentSlot = _this.slotMetrics.nextSlot(currentSlot) + } else if (dates.gt(initialSlot, currentSlot)) { + initialSlot = _this.slotMetrics.nextSlot(initialSlot) + } + + var selectRange = _this.slotMetrics.getRange( + dates.min(initialSlot, currentSlot), + dates.max(initialSlot, currentSlot) + ) + + return (0, _extends2.default)({}, selectRange, { + selecting: true, + top: selectRange.top + '%', + height: selectRange.height + '%', + }) + } + + var selectorClicksHandler = function selectorClicksHandler( + box, + actionType + ) { + if ( + !(0, _Selection.isEvent)( + (0, _reactDom.findDOMNode)( + (0, _assertThisInitialized2.default)(_this) + ), + box + ) + ) { + var _selectionState = selectionState(box), + startDate = _selectionState.startDate, + endDate = _selectionState.endDate + + _this._selectSlot({ + startDate: startDate, + endDate: endDate, + action: actionType, + box: box, + }) + } + + _this.setState({ + selecting: false, + }) + } + + selector.on('selecting', maybeSelect) + selector.on('selectStart', maybeSelect) + selector.on('beforeSelect', function(box) { + if (_this.props.selectable !== 'ignoreEvents') return + return !(0, + _Selection.isEvent)((0, _reactDom.findDOMNode)((0, _assertThisInitialized2.default)(_this)), box) + }) + selector.on('click', function(box) { + return selectorClicksHandler(box, 'click') + }) + selector.on('doubleClick', function(box) { + return selectorClicksHandler(box, 'doubleClick') + }) + selector.on('select', function(bounds) { + if (_this.state.selecting) { + _this._selectSlot( + (0, _extends2.default)({}, _this.state, { + action: 'select', + bounds: bounds, + }) + ) + + _this.setState({ + selecting: false, + }) + } + }) + selector.on('reset', function() { + if (_this.state.selecting) { + _this.setState({ + selecting: false, + }) + } + }) + } + + _this._teardownSelectable = function() { + if (!_this._selector) return + + _this._selector.teardown() + + _this._selector = null + } + + _this._selectSlot = function(_ref3) { + var startDate = _ref3.startDate, + endDate = _ref3.endDate, + action = _ref3.action, + bounds = _ref3.bounds, + box = _ref3.box + var current = startDate, + slots = [] + + while (dates.lte(current, endDate)) { + slots.push(current) + current = new Date(+current + _this.props.step * 60 * 1000) // using Date ensures not to create an endless loop the day DST begins + } + + ;(0, _helpers.notify)(_this.props.onSelectSlot, { + slots: slots, + start: startDate, + end: endDate, + resourceId: _this.props.resource, + action: action, + bounds: bounds, + box: box, + }) + } + + _this._select = function() { + for ( + var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; + _key2 < _len2; + _key2++ + ) { + args[_key2] = arguments[_key2] + } + + ;(0, _helpers.notify)(_this.props.onSelectEvent, args) + } + + _this._doubleClick = function() { + for ( + var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; + _key3 < _len3; + _key3++ + ) { + args[_key3] = arguments[_key3] + } + + ;(0, _helpers.notify)(_this.props.onDoubleClickEvent, args) + } + + _this._keyPress = function() { + for ( + var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; + _key4 < _len4; + _key4++ + ) { + args[_key4] = arguments[_key4] + } + + ;(0, _helpers.notify)(_this.props.onKeyPressEvent, args) + } + + _this.slotMetrics = TimeSlotUtils.getSlotMetrics(_this.props) + return _this + } + + var _proto = DayColumn.prototype + + _proto.componentDidMount = function componentDidMount() { + this.props.selectable && this._selectable() + + if (this.props.isNow) { + this.setTimeIndicatorPositionUpdateInterval() + } + } + + _proto.componentWillUnmount = function componentWillUnmount() { + this._teardownSelectable() + + this.clearTimeIndicatorInterval() + } + + _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps( + nextProps + ) { + if (nextProps.selectable && !this.props.selectable) this._selectable() + if (!nextProps.selectable && this.props.selectable) + this._teardownSelectable() + this.slotMetrics = this.slotMetrics.update(nextProps) + } + + _proto.componentDidUpdate = function componentDidUpdate( + prevProps, + prevState + ) { + var getNowChanged = !dates.eq( + prevProps.getNow(), + this.props.getNow(), + 'minutes' + ) + + if (prevProps.isNow !== this.props.isNow || getNowChanged) { + this.clearTimeIndicatorInterval() + + if (this.props.isNow) { + var tail = + !getNowChanged && + dates.eq(prevProps.date, this.props.date, 'minutes') && + prevState.timeIndicatorPosition === this.state.timeIndicatorPosition + this.setTimeIndicatorPositionUpdateInterval(tail) + } + } else if ( + this.props.isNow && + (!dates.eq(prevProps.min, this.props.min, 'minutes') || + !dates.eq(prevProps.max, this.props.max, 'minutes')) + ) { + this.positionTimeIndicator() + } + } + /** + * @param tail {Boolean} - whether `positionTimeIndicator` call should be + * deferred or called upon setting interval (`true` - if deferred); + */ + + _proto.setTimeIndicatorPositionUpdateInterval = function setTimeIndicatorPositionUpdateInterval( + tail + ) { + var _this2 = this + + if (tail === void 0) { + tail = false + } + + if (!this.intervalTriggered && !tail) { + this.positionTimeIndicator() + } + + this._timeIndicatorTimeout = window.setTimeout(function() { + _this2.intervalTriggered = true + + _this2.positionTimeIndicator() + + _this2.setTimeIndicatorPositionUpdateInterval() + }, 60000) + } + + _proto.clearTimeIndicatorInterval = function clearTimeIndicatorInterval() { + this.intervalTriggered = false + window.clearTimeout(this._timeIndicatorTimeout) + } + + _proto.positionTimeIndicator = function positionTimeIndicator() { + var _this$props2 = this.props, + min = _this$props2.min, + max = _this$props2.max, + getNow = _this$props2.getNow + var current = getNow() + + if (current >= min && current <= max) { + var top = this.slotMetrics.getCurrentTimePosition(current) + this.intervalTriggered = true + this.setState({ + timeIndicatorPosition: top, + }) + } else { + this.clearTimeIndicatorInterval() + } + } + + _proto.render = function render() { + var _this$props3 = this.props, + max = _this$props3.max, + rtl = _this$props3.rtl, + isNow = _this$props3.isNow, + resource = _this$props3.resource, + accessors = _this$props3.accessors, + localizer = _this$props3.localizer, + _this$props3$getters = _this$props3.getters, + dayProp = _this$props3$getters.dayProp, + getters = (0, _objectWithoutPropertiesLoose2.default)( + _this$props3$getters, + ['dayProp'] + ), + _this$props3$componen = _this$props3.components, + EventContainer = _this$props3$componen.eventContainerWrapper, + components = (0, _objectWithoutPropertiesLoose2.default)( + _this$props3$componen, + ['eventContainerWrapper'] + ) + var slotMetrics = this.slotMetrics + var _this$state = this.state, + selecting = _this$state.selecting, + top = _this$state.top, + height = _this$state.height, + startDate = _this$state.startDate, + endDate = _this$state.endDate + var selectDates = { + start: startDate, + end: endDate, + } + + var _dayProp = dayProp(max), + className = _dayProp.className, + style = _dayProp.style + + return _react.default.createElement( + 'div', + { + style: style, + className: (0, _clsx.default)( + className, + 'rbc-day-slot', + 'rbc-time-column', + isNow && 'rbc-now', + isNow && 'rbc-today', // WHY + selecting && 'rbc-slot-selecting' + ), + }, + slotMetrics.groups.map(function(grp, idx) { + return _react.default.createElement(_TimeSlotGroup.default, { + key: idx, + group: grp, + resource: resource, + getters: getters, + components: components, + }) + }), + _react.default.createElement( + EventContainer, + { + localizer: localizer, + resource: resource, + accessors: accessors, + getters: getters, + components: components, + slotMetrics: slotMetrics, + }, + _react.default.createElement( + 'div', + { + className: (0, _clsx.default)( + 'rbc-events-container', + rtl && 'rtl' + ), + }, + this.renderEvents({ + events: this.props.backgroundEvents, + isBackgroundEvent: true, + }), + this.renderEvents({ + events: this.props.events, + }) + ) + ), + selecting && + _react.default.createElement( + 'div', + { + className: 'rbc-slot-selection', + style: { + top: top, + height: height, + }, + }, + _react.default.createElement( + 'span', + null, + localizer.format(selectDates, 'selectRangeFormat') + ) + ), + isNow && + this.intervalTriggered && + _react.default.createElement('div', { + className: 'rbc-current-time-indicator', + style: { + top: this.state.timeIndicatorPosition + '%', + }, + }) + ) + } + + return DayColumn + })(_react.default.Component) + +DayColumn.propTypes = + process.env.NODE_ENV !== 'production' + ? { + events: _propTypes.default.array.isRequired, + backgroundEvents: _propTypes.default.array.isRequired, + step: _propTypes.default.number.isRequired, + date: _propTypes.default.instanceOf(Date).isRequired, + min: _propTypes.default.instanceOf(Date).isRequired, + max: _propTypes.default.instanceOf(Date).isRequired, + getNow: _propTypes.default.func.isRequired, + isNow: _propTypes.default.bool, + rtl: _propTypes.default.bool, + resizable: _propTypes.default.bool, + accessors: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + localizer: _propTypes.default.object.isRequired, + showMultiDayTimes: _propTypes.default.bool, + culture: _propTypes.default.string, + timeslots: _propTypes.default.number, + selected: _propTypes.default.object, + selectable: _propTypes.default.oneOf([true, false, 'ignoreEvents']), + eventOffset: _propTypes.default.number, + longPressThreshold: _propTypes.default.number, + onSelecting: _propTypes.default.func, + onSelectSlot: _propTypes.default.func.isRequired, + onSelectEvent: _propTypes.default.func.isRequired, + onDoubleClickEvent: _propTypes.default.func.isRequired, + onKeyPressEvent: _propTypes.default.func, + className: _propTypes.default.string, + dragThroughEvents: _propTypes.default.bool, + resource: _propTypes.default.any, + dayLayoutAlgorithm: _propTypes2.DayLayoutAlgorithmPropType, + } + : {} +DayColumn.defaultProps = { + dragThroughEvents: true, + timeslots: 2, +} +var _default = DayColumn +exports.default = _default +module.exports = exports['default'] diff --git a/lib/EventCell.js b/lib/EventCell.js new file mode 100644 index 000000000..d61dafed6 --- /dev/null +++ b/lib/EventCell.js @@ -0,0 +1,174 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _clsx = _interopRequireDefault(require('clsx')) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var EventCell = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(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, + _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 = (0, _objectWithoutPropertiesLoose2.default)(_this$props, [ + 'style', + 'className', + 'event', + 'selected', + 'isAllDay', + 'onSelect', + 'onDoubleClick', + 'onKeyPress', + 'localizer', + 'continuesPrior', + 'continuesAfter', + 'accessors', + 'getters', + 'children', + 'components', + 'slotStart', + 'slotEnd', + ]) + 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 || + dates.diff(start, dates.ceil(end, 'day'), 'day') > 1 + var userProps = getters.eventProp(event, start, end, selected) + + var content = _react.default.createElement( + 'div', + { + className: 'rbc-event-content', + title: tooltip || undefined, + }, + Event + ? _react.default.createElement(Event, { + event: event, + continuesPrior: continuesPrior, + continuesAfter: continuesAfter, + title: title, + isAllDay: allDay, + localizer: localizer, + slotStart: slotStart, + slotEnd: slotEnd, + }) + : title + ) + + return _react.default.createElement( + EventWrapper, + (0, _extends2.default)({}, this.props, { + type: 'date', + }), + _react.default.createElement( + 'div', + (0, _extends2.default)({}, props, { + tabIndex: 0, + style: (0, _extends2.default)({}, userProps.style, style), + className: (0, _clsx.default)( + '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) + }, + onKeyPress: function onKeyPress(e) { + return _onKeyPress && _onKeyPress(event, e) + }, + }), + typeof children === 'function' ? children(content) : content + ) + ) + } + + return EventCell + })(_react.default.Component) + +EventCell.propTypes = + process.env.NODE_ENV !== 'production' + ? { + event: _propTypes.default.object.isRequired, + slotStart: _propTypes.default.instanceOf(Date), + slotEnd: _propTypes.default.instanceOf(Date), + resizable: _propTypes.default.bool, + selected: _propTypes.default.bool, + isAllDay: _propTypes.default.bool, + continuesPrior: _propTypes.default.bool, + continuesAfter: _propTypes.default.bool, + accessors: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + localizer: _propTypes.default.object, + onSelect: _propTypes.default.func, + onDoubleClick: _propTypes.default.func, + onKeyPress: _propTypes.default.func, + } + : {} +var _default = EventCell +exports.default = _default +module.exports = exports['default'] diff --git a/lib/EventEndingRow.js b/lib/EventEndingRow.js new file mode 100644 index 000000000..97c09b597 --- /dev/null +++ b/lib/EventEndingRow.js @@ -0,0 +1,168 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _EventRowMixin = _interopRequireDefault(require('./EventRowMixin')) + +var _eventLevels = require('./utils/eventLevels') + +var _range = _interopRequireDefault(require('lodash/range')) + +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) { + ;(0, _inheritsLoose2.default)(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 = (0, _eventLevels.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.default.renderEvent(this.props, event) + + if (gap) { + row.push( + _EventRowMixin.default.renderSpan(slots, gap, key + '_gap') + ) + } + + row.push(_EventRowMixin.default.renderSpan(slots, span, key, content)) + lastEnd = current = right + 1 + } else { + if (gap) { + row.push( + _EventRowMixin.default.renderSpan(slots, gap, key + '_gap') + ) + } + + row.push( + _EventRowMixin.default.renderSpan( + slots, + 1, + key, + this.renderShowMore(segments, current) + ) + ) + lastEnd = current = current + 1 + } + } + + return _react.default.createElement( + 'div', + { + className: 'rbc-row', + }, + row + ) + } + + _proto.canRenderSlotEvent = function canRenderSlotEvent(slot, span) { + var segments = this.props.segments + return (0, _range.default)(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.default.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, e.target) + } + + return EventEndingRow + })(_react.default.Component) + +EventEndingRow.propTypes = + process.env.NODE_ENV !== 'production' + ? (0, _extends2.default)( + { + segments: _propTypes.default.array, + slots: _propTypes.default.number, + onShowMore: _propTypes.default.func, + }, + _EventRowMixin.default.propTypes + ) + : {} +EventEndingRow.defaultProps = (0, _extends2.default)( + {}, + _EventRowMixin.default.defaultProps +) +var _default = EventEndingRow +exports.default = _default +module.exports = exports['default'] diff --git a/lib/EventRow.js b/lib/EventRow.js new file mode 100644 index 000000000..f471789d3 --- /dev/null +++ b/lib/EventRow.js @@ -0,0 +1,87 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _clsx = _interopRequireDefault(require('clsx')) + +var _react = _interopRequireDefault(require('react')) + +var _EventRowMixin = _interopRequireDefault(require('./EventRowMixin')) + +var EventRow = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(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.default.createElement( + 'div', + { + className: (0, _clsx.default)(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.default.renderEvent(_this.props, event) + + if (gap) + row.push( + _EventRowMixin.default.renderSpan(slots, gap, key + '_gap') + ) + row.push(_EventRowMixin.default.renderSpan(slots, span, key, content)) + lastEnd = right + 1 + return row + }, []) + ) + } + + return EventRow + })(_react.default.Component) + +EventRow.propTypes = + process.env.NODE_ENV !== 'production' + ? (0, _extends2.default)( + { + segments: _propTypes.default.array, + }, + _EventRowMixin.default.propTypes + ) + : {} +EventRow.defaultProps = (0, _extends2.default)( + {}, + _EventRowMixin.default.defaultProps +) +var _default = EventRow +exports.default = _default +module.exports = exports['default'] diff --git a/lib/EventRowMixin.js b/lib/EventRowMixin.js new file mode 100644 index 000000000..ed868afa4 --- /dev/null +++ b/lib/EventRowMixin.js @@ -0,0 +1,87 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _EventCell = _interopRequireDefault(require('./EventCell')) + +var _selection = require('./utils/selection') + +/* eslint-disable react/prop-types */ +var _default = { + propTypes: { + slotMetrics: _propTypes.default.object.isRequired, + selected: _propTypes.default.object, + isAllDay: _propTypes.default.bool, + accessors: _propTypes.default.object.isRequired, + localizer: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + onSelect: _propTypes.default.func, + onDoubleClick: _propTypes.default.func, + onKeyPress: _propTypes.default.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, + onKeyPress = props.onKeyPress, + localizer = props.localizer, + slotMetrics = props.slotMetrics, + components = props.components, + resizable = props.resizable + var continuesPrior = slotMetrics.continuesPrior(event) + var continuesAfter = slotMetrics.continuesAfter(event) + return _react.default.createElement(_EventCell.default, { + event: event, + getters: getters, + localizer: localizer, + accessors: accessors, + components: components, + onSelect: onSelect, + onDoubleClick: onDoubleClick, + onKeyPress: onKeyPress, + continuesPrior: continuesPrior, + continuesAfter: continuesAfter, + slotStart: slotMetrics.first, + slotEnd: slotMetrics.last, + selected: (0, _selection.isSelected)(event, selected), + resizable: resizable, + }) + }, + renderSpan: function renderSpan(slots, len, key, content) { + if (content === void 0) { + content = ' ' + } + + var per = (Math.abs(len) / slots) * 100 + '%' + return _react.default.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 + ) + }, +} +exports.default = _default +module.exports = exports['default'] diff --git a/lib/EventWrapper.js b/lib/EventWrapper.js new file mode 100644 index 000000000..b85ac653e --- /dev/null +++ b/lib/EventWrapper.js @@ -0,0 +1,12 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _NoopWrapper = _interopRequireDefault(require('./NoopWrapper')) + +var _default = _NoopWrapper.default +exports.default = _default +module.exports = exports['default'] diff --git a/lib/Header.js b/lib/Header.js new file mode 100644 index 000000000..c45505b3c --- /dev/null +++ b/lib/Header.js @@ -0,0 +1,32 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var Header = function Header(_ref) { + var label = _ref.label + return _react.default.createElement( + 'span', + { + role: 'columnheader', + 'aria-sort': 'none', + }, + label + ) +} + +Header.propTypes = + process.env.NODE_ENV !== 'production' + ? { + label: _propTypes.default.node, + } + : {} +var _default = Header +exports.default = _default +module.exports = exports['default'] diff --git a/lib/Month.js b/lib/Month.js new file mode 100644 index 000000000..bb67f7ab3 --- /dev/null +++ b/lib/Month.js @@ -0,0 +1,542 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _assertThisInitialized2 = _interopRequireDefault( + require('@babel/runtime/helpers/assertThisInitialized') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _reactDom = require('react-dom') + +var _clsx = _interopRequireDefault(require('clsx')) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var _chunk = _interopRequireDefault(require('lodash/chunk')) + +var _constants = require('./utils/constants') + +var _helpers = require('./utils/helpers') + +var _position = _interopRequireDefault(require('dom-helpers/position')) + +var animationFrame = _interopRequireWildcard( + require('dom-helpers/animationFrame') +) + +var _Popup = _interopRequireDefault(require('./Popup')) + +var _Overlay = _interopRequireDefault(require('react-overlays/Overlay')) + +var _DateContentRow = _interopRequireDefault(require('./DateContentRow')) + +var _Header = _interopRequireDefault(require('./Header')) + +var _DateHeader = _interopRequireDefault(require('./DateHeader')) + +var _eventLevels = require('./utils/eventLevels') + +var eventsForWeek = function eventsForWeek(evts, start, end, accessors) { + return evts.filter(function(e) { + return (0, _eventLevels.inRange)(e, start, end, accessors) + }) +} + +var MonthView = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(MonthView, _React$Component) + + function MonthView() { + 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.getContainer = function() { + return (0, _reactDom.findDOMNode)( + (0, _assertThisInitialized2.default)(_this) + ) + } + + _this.renderWeek = function(week, weekIdx) { + var _this$props = _this.props, + events = _this$props.events, + components = _this$props.components, + selectable = _this$props.selectable, + getNow = _this$props.getNow, + selected = _this$props.selected, + date = _this$props.date, + localizer = _this$props.localizer, + longPressThreshold = _this$props.longPressThreshold, + accessors = _this$props.accessors, + getters = _this$props.getters, + showAllEvents = _this$props.showAllEvents + var _this$state = _this.state, + needLimitMeasure = _this$state.needLimitMeasure, + rowLimit = _this$state.rowLimit + events = eventsForWeek( + events, + week[0], + week[week.length - 1], + accessors + ) + events.sort(function(a, b) { + return (0, _eventLevels.sortEvents)(a, b, accessors) + }) + return _react.default.createElement(_DateContentRow.default, { + key: weekIdx, + ref: weekIdx === 0 ? _this.slotRowRef : undefined, + container: _this.getContainer, + className: 'rbc-month-row', + getNow: getNow, + date: date, + range: week, + events: events, + maxRows: showAllEvents ? Infinity : rowLimit, + selected: selected, + selectable: selectable, + components: components, + accessors: accessors, + getters: getters, + localizer: localizer, + renderHeader: _this.readerDateHeading, + renderForMeasure: needLimitMeasure, + onShowMore: _this.handleShowMore, + onSelect: _this.handleSelectEvent, + onDoubleClick: _this.handleDoubleClickEvent, + onKeyPress: _this.handleKeyPressEvent, + onSelectSlot: _this.handleSelectSlot, + longPressThreshold: longPressThreshold, + rtl: _this.props.rtl, + resizable: _this.props.resizable, + showAllEvents: showAllEvents, + }) + } + + _this.readerDateHeading = function(_ref) { + var date = _ref.date, + className = _ref.className, + props = (0, _objectWithoutPropertiesLoose2.default)(_ref, [ + 'date', + 'className', + ]) + var _this$props2 = _this.props, + currentDate = _this$props2.date, + getDrilldownView = _this$props2.getDrilldownView, + localizer = _this$props2.localizer + var isOffRange = dates.month(date) !== dates.month(currentDate) + var isCurrent = dates.eq(date, currentDate, 'day') + var drilldownView = getDrilldownView(date) + var label = localizer.format(date, 'dateFormat') + var DateHeaderComponent = + _this.props.components.dateHeader || _DateHeader.default + return _react.default.createElement( + 'div', + (0, _extends2.default)({}, props, { + className: (0, _clsx.default)( + className, + isOffRange && 'rbc-off-range', + isCurrent && 'rbc-current' + ), + role: 'cell', + }), + _react.default.createElement(DateHeaderComponent, { + label: label, + date: date, + drilldownView: drilldownView, + isOffRange: isOffRange, + onDrillDown: function onDrillDown(e) { + return _this.handleHeadingClick(date, drilldownView, e) + }, + }) + ) + } + + _this.handleSelectSlot = function(range, slotInfo) { + _this._pendingSelection = _this._pendingSelection.concat(range) + clearTimeout(_this._selectTimer) + _this._selectTimer = setTimeout(function() { + return _this.selectDates(slotInfo) + }) + } + + _this.handleHeadingClick = function(date, view, e) { + e.preventDefault() + + _this.clearSelection() + + ;(0, _helpers.notify)(_this.props.onDrillDown, [date, view]) + } + + _this.handleSelectEvent = function() { + _this.clearSelection() + + for ( + var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; + _key2 < _len2; + _key2++ + ) { + args[_key2] = arguments[_key2] + } + + ;(0, _helpers.notify)(_this.props.onSelectEvent, args) + } + + _this.handleDoubleClickEvent = function() { + _this.clearSelection() + + for ( + var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; + _key3 < _len3; + _key3++ + ) { + args[_key3] = arguments[_key3] + } + + ;(0, _helpers.notify)(_this.props.onDoubleClickEvent, args) + } + + _this.handleKeyPressEvent = function() { + _this.clearSelection() + + for ( + var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; + _key4 < _len4; + _key4++ + ) { + args[_key4] = arguments[_key4] + } + + ;(0, _helpers.notify)(_this.props.onKeyPressEvent, args) + } + + _this.handleShowMore = function(events, date, cell, slot, target) { + var _this$props3 = _this.props, + popup = _this$props3.popup, + onDrillDown = _this$props3.onDrillDown, + onShowMore = _this$props3.onShowMore, + getDrilldownView = _this$props3.getDrilldownView //cancel any pending selections so only the event click goes through. + + _this.clearSelection() + + if (popup) { + var position = (0, _position.default)( + cell, + (0, _reactDom.findDOMNode)( + (0, _assertThisInitialized2.default)(_this) + ) + ) + + _this.setState({ + overlay: { + date: date, + events: events, + position: position, + target: target, + }, + }) + } else { + ;(0, _helpers.notify)(onDrillDown, [ + date, + getDrilldownView(date) || _constants.views.DAY, + ]) + } + + ;(0, _helpers.notify)(onShowMore, [events, date, slot]) + } + + _this.overlayDisplay = function() { + _this.setState({ + overlay: null, + }) + } + + _this._bgRows = [] + _this._pendingSelection = [] + _this.slotRowRef = _react.default.createRef() + _this.state = { + rowLimit: 5, + needLimitMeasure: true, + } + return _this + } + + var _proto = MonthView.prototype + + _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps( + _ref2 + ) { + var date = _ref2.date + this.setState({ + needLimitMeasure: !dates.eq(date, this.props.date, 'month'), + }) + } + + _proto.componentDidMount = function componentDidMount() { + var _this2 = this + + var running + if (this.state.needLimitMeasure) this.measureRowLimit(this.props) + window.addEventListener( + 'resize', + (this._resizeListener = function() { + if (!running) { + animationFrame.request(function() { + running = false + + _this2.setState({ + needLimitMeasure: true, + }) //eslint-disable-line + }) + } + }), + false + ) + } + + _proto.componentDidUpdate = function componentDidUpdate() { + if (this.state.needLimitMeasure) this.measureRowLimit(this.props) + } + + _proto.componentWillUnmount = function componentWillUnmount() { + window.removeEventListener('resize', this._resizeListener, false) + } + + _proto.render = function render() { + var _this$props4 = this.props, + date = _this$props4.date, + localizer = _this$props4.localizer, + className = _this$props4.className, + month = dates.visibleDays(date, localizer), + weeks = (0, _chunk.default)(month, 7) + this._weekCount = weeks.length + return _react.default.createElement( + 'div', + { + className: (0, _clsx.default)('rbc-month-view', className), + role: 'table', + 'aria-label': 'Month View', + }, + _react.default.createElement( + 'div', + { + className: 'rbc-row rbc-month-header', + role: 'row', + }, + this.renderHeaders(weeks[0]) + ), + weeks.map(this.renderWeek), + this.props.popup && this.renderOverlay() + ) + } + + _proto.renderHeaders = function renderHeaders(row) { + var _this$props5 = this.props, + localizer = _this$props5.localizer, + components = _this$props5.components + var first = row[0] + var last = row[row.length - 1] + var HeaderComponent = components.header || _Header.default + return dates.range(first, last, 'day').map(function(day, idx) { + return _react.default.createElement( + 'div', + { + key: 'header_' + idx, + className: 'rbc-header', + }, + _react.default.createElement(HeaderComponent, { + date: day, + localizer: localizer, + label: localizer.format(day, 'weekdayFormat'), + }) + ) + }) + } + + _proto.renderOverlay = function renderOverlay() { + var _this3 = this + + var overlay = (this.state && this.state.overlay) || {} + var _this$props6 = this.props, + accessors = _this$props6.accessors, + localizer = _this$props6.localizer, + components = _this$props6.components, + getters = _this$props6.getters, + selected = _this$props6.selected, + popupOffset = _this$props6.popupOffset + return _react.default.createElement( + _Overlay.default, + { + rootClose: true, + placement: 'bottom', + show: !!overlay.position, + onHide: function onHide() { + return _this3.setState({ + overlay: null, + }) + }, + target: function target() { + return overlay.target + }, + }, + function(_ref3) { + var props = _ref3.props + return _react.default.createElement( + _Popup.default, + (0, _extends2.default)({}, props, { + popupOffset: popupOffset, + accessors: accessors, + getters: getters, + selected: selected, + components: components, + localizer: localizer, + position: overlay.position, + show: _this3.overlayDisplay, + events: overlay.events, + slotStart: overlay.date, + slotEnd: overlay.end, + onSelect: _this3.handleSelectEvent, + onDoubleClick: _this3.handleDoubleClickEvent, + onKeyPress: _this3.handleKeyPressEvent, + handleDragStart: _this3.props.handleDragStart, + }) + ) + } + ) + } + + _proto.measureRowLimit = function measureRowLimit() { + this.setState({ + needLimitMeasure: false, + rowLimit: this.slotRowRef.current.getRowLimit(), + }) + } + + _proto.selectDates = function selectDates(slotInfo) { + var slots = this._pendingSelection.slice() + + this._pendingSelection = [] + slots.sort(function(a, b) { + return +a - +b + }) + ;(0, _helpers.notify)(this.props.onSelectSlot, { + slots: slots, + start: slots[0], + end: slots[slots.length - 1], + action: slotInfo.action, + bounds: slotInfo.bounds, + box: slotInfo.box, + }) + } + + _proto.clearSelection = function clearSelection() { + clearTimeout(this._selectTimer) + this._pendingSelection = [] + } + + return MonthView + })(_react.default.Component) + +MonthView.propTypes = + process.env.NODE_ENV !== 'production' + ? { + events: _propTypes.default.array.isRequired, + date: _propTypes.default.instanceOf(Date), + min: _propTypes.default.instanceOf(Date), + max: _propTypes.default.instanceOf(Date), + step: _propTypes.default.number, + getNow: _propTypes.default.func.isRequired, + scrollToTime: _propTypes.default.instanceOf(Date), + rtl: _propTypes.default.bool, + resizable: _propTypes.default.bool, + width: _propTypes.default.number, + accessors: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + localizer: _propTypes.default.object.isRequired, + selected: _propTypes.default.object, + selectable: _propTypes.default.oneOf([true, false, 'ignoreEvents']), + longPressThreshold: _propTypes.default.number, + onNavigate: _propTypes.default.func, + onSelectSlot: _propTypes.default.func, + onSelectEvent: _propTypes.default.func, + onDoubleClickEvent: _propTypes.default.func, + onKeyPressEvent: _propTypes.default.func, + onShowMore: _propTypes.default.func, + showAllEvents: _propTypes.default.bool, + onDrillDown: _propTypes.default.func, + getDrilldownView: _propTypes.default.func.isRequired, + popup: _propTypes.default.bool, + handleDragStart: _propTypes.default.func, + popupOffset: _propTypes.default.oneOfType([ + _propTypes.default.number, + _propTypes.default.shape({ + x: _propTypes.default.number, + y: _propTypes.default.number, + }), + ]), + } + : {} + +MonthView.range = function(date, _ref4) { + var localizer = _ref4.localizer + var start = dates.firstVisibleDay(date, localizer) + var end = dates.lastVisibleDay(date, localizer) + return { + start: start, + end: end, + } +} + +MonthView.navigate = function(date, action) { + switch (action) { + case _constants.navigate.PREVIOUS: + return dates.add(date, -1, 'month') + + case _constants.navigate.NEXT: + return dates.add(date, 1, 'month') + + default: + return date + } +} + +MonthView.title = function(date, _ref5) { + var localizer = _ref5.localizer + return localizer.format(date, 'monthHeaderFormat') +} + +var _default = MonthView +exports.default = _default +module.exports = exports['default'] diff --git a/lib/NoopWrapper.js b/lib/NoopWrapper.js new file mode 100644 index 000000000..293e01c8c --- /dev/null +++ b/lib/NoopWrapper.js @@ -0,0 +1,12 @@ +'use strict' + +exports.__esModule = true +exports.default = void 0 + +function NoopWrapper(props) { + return props.children +} + +var _default = NoopWrapper +exports.default = _default +module.exports = exports['default'] diff --git a/lib/Popup.js b/lib/Popup.js new file mode 100644 index 000000000..e27833a76 --- /dev/null +++ b/lib/Popup.js @@ -0,0 +1,193 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _offset = _interopRequireDefault(require('dom-helpers/offset')) + +var _scrollTop = _interopRequireDefault(require('dom-helpers/scrollTop')) + +var _scrollLeft = _interopRequireDefault(require('dom-helpers/scrollLeft')) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var _EventCell = _interopRequireDefault(require('./EventCell')) + +var _selection = require('./utils/selection') + +var Popup = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(Popup, _React$Component) + + function Popup() { + return _React$Component.apply(this, arguments) || this + } + + var _proto = Popup.prototype + + _proto.componentDidMount = function componentDidMount() { + var _this$props = this.props, + _this$props$popupOffs = _this$props.popupOffset, + popupOffset = + _this$props$popupOffs === void 0 ? 5 : _this$props$popupOffs, + popperRef = _this$props.popperRef, + _getOffset = (0, _offset.default)(popperRef.current), + top = _getOffset.top, + left = _getOffset.left, + width = _getOffset.width, + height = _getOffset.height, + viewBottom = window.innerHeight + (0, _scrollTop.default)(window), + viewRight = window.innerWidth + (0, _scrollLeft.default)(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 = this + + var _this$props2 = this.props, + events = _this$props2.events, + selected = _this$props2.selected, + getters = _this$props2.getters, + accessors = _this$props2.accessors, + components = _this$props2.components, + onSelect = _this$props2.onSelect, + onDoubleClick = _this$props2.onDoubleClick, + onKeyPress = _this$props2.onKeyPress, + slotStart = _this$props2.slotStart, + slotEnd = _this$props2.slotEnd, + localizer = _this$props2.localizer, + popperRef = _this$props2.popperRef + var width = this.props.position.width, + topOffset = (this.state || {}).topOffset || 0, + leftOffset = (this.state || {}).leftOffset || 0 + var style = { + top: -topOffset, + left: -leftOffset, + minWidth: width + width / 2, + } + return _react.default.createElement( + 'div', + { + style: (0, _extends2.default)({}, this.props.style, style), + className: 'rbc-overlay', + ref: popperRef, + }, + _react.default.createElement( + 'div', + { + className: 'rbc-overlay-header', + }, + localizer.format(slotStart, 'dayHeaderFormat') + ), + events.map(function(event, idx) { + return _react.default.createElement(_EventCell.default, { + key: idx, + type: 'popup', + event: event, + getters: getters, + onSelect: onSelect, + accessors: accessors, + components: components, + onDoubleClick: onDoubleClick, + onKeyPress: onKeyPress, + continuesPrior: dates.lt(accessors.end(event), slotStart, 'day'), + continuesAfter: dates.gte(accessors.start(event), slotEnd, 'day'), + slotStart: slotStart, + slotEnd: slotEnd, + selected: (0, _selection.isSelected)(event, selected), + draggable: true, + onDragStart: function onDragStart() { + return _this.props.handleDragStart(event) + }, + onDragEnd: function onDragEnd() { + return _this.props.show() + }, + }) + }) + ) + } + + return Popup + })(_react.default.Component) + +Popup.propTypes = + process.env.NODE_ENV !== 'production' + ? { + position: _propTypes.default.object, + popupOffset: _propTypes.default.oneOfType([ + _propTypes.default.number, + _propTypes.default.shape({ + x: _propTypes.default.number, + y: _propTypes.default.number, + }), + ]), + events: _propTypes.default.array, + selected: _propTypes.default.object, + accessors: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + localizer: _propTypes.default.object.isRequired, + onSelect: _propTypes.default.func, + onDoubleClick: _propTypes.default.func, + onKeyPress: _propTypes.default.func, + handleDragStart: _propTypes.default.func, + show: _propTypes.default.func, + slotStart: _propTypes.default.instanceOf(Date), + slotEnd: _propTypes.default.number, + popperRef: _propTypes.default.oneOfType([ + _propTypes.default.func, + _propTypes.default.shape({ + current: _propTypes.default.Element, + }), + ]), + /** + * The Overlay component, of react-overlays, creates a ref that is passed to the Popup, and + * requires proper ref forwarding to be used without error + */ + } + : {} + +var _default = _react.default.forwardRef(function(props, ref) { + return _react.default.createElement( + Popup, + (0, _extends2.default)( + { + popperRef: ref, + }, + props + ) + ) +}) + +exports.default = _default +module.exports = exports['default'] diff --git a/lib/ResourceHeader.js b/lib/ResourceHeader.js new file mode 100644 index 000000000..8dd010c26 --- /dev/null +++ b/lib/ResourceHeader.js @@ -0,0 +1,27 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var ResourceHeader = function ResourceHeader(_ref) { + var label = _ref.label + return _react.default.createElement(_react.default.Fragment, null, label) +} + +ResourceHeader.propTypes = + process.env.NODE_ENV !== 'production' + ? { + label: _propTypes.default.node, + index: _propTypes.default.number, + resource: _propTypes.default.object, + } + : {} +var _default = ResourceHeader +exports.default = _default +module.exports = exports['default'] diff --git a/lib/ScrollableWeekWrapper.js b/lib/ScrollableWeekWrapper.js new file mode 100644 index 000000000..50f04cfe4 --- /dev/null +++ b/lib/ScrollableWeekWrapper.js @@ -0,0 +1,23 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _react = _interopRequireDefault(require('react')) + +var ScrollableWeekWrapper = function ScrollableWeekWrapper(_ref) { + var children = _ref.children + return _react.default.createElement( + 'div', + { + className: 'rbc-row-content-scroll-container', + }, + children + ) +} + +var _default = ScrollableWeekWrapper +exports.default = _default +module.exports = exports['default'] diff --git a/lib/Selection.js b/lib/Selection.js new file mode 100644 index 000000000..f145583d0 --- /dev/null +++ b/lib/Selection.js @@ -0,0 +1,594 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.getEventNodeFromPoint = getEventNodeFromPoint +exports.isEvent = isEvent +exports.objectsCollide = objectsCollide +exports.getBoundsForNode = getBoundsForNode +exports.default = void 0 + +var _contains = _interopRequireDefault(require('dom-helpers/contains')) + +var _closest = _interopRequireDefault(require('dom-helpers/closest')) + +var _listen = _interopRequireDefault(require('dom-helpers/listen')) + +function addEventListener(type, handler, target) { + if (target === void 0) { + target = document + } + + return (0, _listen.default)(target, type, handler, { + passive: false, + }) +} + +function isOverContainer(container, x, y) { + return ( + !container || + (0, _contains.default)(container, document.elementFromPoint(x, y)) + ) +} + +function getEventNodeFromPoint(node, _ref) { + var clientX = _ref.clientX, + clientY = _ref.clientY + var target = document.elementFromPoint(clientX, clientY) + return (0, _closest.default)(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.isDetached = false + 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) + 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._onDragOverfromOutisde = addEventListener( + 'dragover', + this._dragOverFromOutsideListener + ) + + 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.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() + } + + _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 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. + + _proto._addInitialEventListener = 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() + } + } + + _proto._dropFromOutsideListener = 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() + } + + _proto._dragOverFromOutsideListener = 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() + } + + _proto._handleInitialEvent = function _handleInitialEvent(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 && + !(0, _contains.default)(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 + + default: + break + } + } + + _proto._handleTerminatingEvent = function _handleTerminatingEvent(e) { + var _getEventCoordinates4 = getEventCoordinates(e), + pageX = _getEventCoordinates4.pageX, + pageY = _getEventCoordinates4.pageY + + this.selecting = false + this._removeEndListener && this._removeEndListener() + this._removeMoveListener && this._removeMoveListener() + if (!this._initialEventData) return + var inRoot = + !this.container || (0, _contains.default)(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 _getEventCoordinates5 = getEventCoordinates(e), + pageX = _getEventCoordinates5.pageX, + pageY = _getEventCoordinates5.pageY, + clientX = _getEventCoordinates5.clientX, + clientY = _getEventCoordinates5.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 || this.isDetached) { + return + } + + var _this$_initialEventDa = this._initialEventData, + x = _this$_initialEventDa.x, + y = _this$_initialEventDa.y + + var _getEventCoordinates6 = getEventCoordinates(e), + pageX = _getEventCoordinates6.pageX, + pageY = _getEventCoordinates6.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 _default = Selection +exports.default = _default diff --git a/lib/TimeGrid.js b/lib/TimeGrid.js new file mode 100644 index 000000000..b5954c476 --- /dev/null +++ b/lib/TimeGrid.js @@ -0,0 +1,449 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _clsx = _interopRequireDefault(require('clsx')) + +var animationFrame = _interopRequireWildcard( + require('dom-helpers/animationFrame') +) + +var _react = _interopRequireWildcard(require('react')) + +var _reactDom = require('react-dom') + +var _memoizeOne = _interopRequireDefault(require('memoize-one')) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var _DayColumn = _interopRequireDefault(require('./DayColumn')) + +var _TimeGutter = _interopRequireDefault(require('./TimeGutter')) + +var _width = _interopRequireDefault(require('dom-helpers/width')) + +var _TimeGridHeader = _interopRequireDefault(require('./TimeGridHeader')) + +var _helpers = require('./utils/helpers') + +var _eventLevels = require('./utils/eventLevels') + +var _Resources = _interopRequireDefault(require('./utils/Resources')) + +var _propTypes2 = require('./utils/propTypes') + +var TimeGrid = + /*#__PURE__*/ + (function(_Component) { + ;(0, _inheritsLoose2.default)(TimeGrid, _Component) + + function TimeGrid(props) { + var _this + + _this = _Component.call(this, props) || this + + _this.handleScroll = function(e) { + if (_this.scrollRef.current) { + _this.scrollRef.current.scrollLeft = e.target.scrollLeft + } + } + + _this.handleResize = function() { + animationFrame.cancel(_this.rafHandle) + _this.rafHandle = animationFrame.request(_this.checkOverflow) + } + + _this.gutterRef = function(ref) { + _this.gutter = ref && (0, _reactDom.findDOMNode)(ref) + } + + _this.handleSelectAlldayEvent = function() { + //cancel any pending selections so only the event click goes through. + _this.clearSelection() + + for ( + var _len = arguments.length, args = new Array(_len), _key = 0; + _key < _len; + _key++ + ) { + args[_key] = arguments[_key] + } + + ;(0, _helpers.notify)(_this.props.onSelectEvent, args) + } + + _this.handleSelectAllDaySlot = function(slots, slotInfo) { + var onSelectSlot = _this.props.onSelectSlot + ;(0, _helpers.notify)(onSelectSlot, { + slots: slots, + start: slots[0], + end: slots[slots.length - 1], + action: slotInfo.action, + resourceId: slotInfo.resourceId, + }) + } + + _this.checkOverflow = function() { + if (_this._updatingOverflow) return + var content = _this.contentRef.current + var isOverflowing = content.scrollHeight > content.clientHeight + + if (_this.state.isOverflowing !== isOverflowing) { + _this._updatingOverflow = true + + _this.setState( + { + isOverflowing: isOverflowing, + }, + function() { + _this._updatingOverflow = false + } + ) + } + } + + _this.memoizedResources = (0, _memoizeOne.default)(function( + resources, + accessors + ) { + return (0, _Resources.default)(resources, accessors) + }) + _this.state = { + gutterWidth: undefined, + isOverflowing: null, + } + _this.scrollRef = _react.default.createRef() + _this.contentRef = _react.default.createRef() + _this._scrollRatio = null + return _this + } + + var _proto = TimeGrid.prototype + + _proto.UNSAFE_componentWillMount = function UNSAFE_componentWillMount() { + this.calculateScroll() + } + + _proto.componentDidMount = function componentDidMount() { + this.checkOverflow() + + if (this.props.width == null) { + this.measureGutter() + } + + this.applyScroll() + window.addEventListener('resize', this.handleResize) + } + + _proto.componentWillUnmount = function componentWillUnmount() { + window.removeEventListener('resize', this.handleResize) + animationFrame.cancel(this.rafHandle) + + if (this.measureGutterAnimationFrameRequest) { + window.cancelAnimationFrame(this.measureGutterAnimationFrameRequest) + } + } + + _proto.componentDidUpdate = function componentDidUpdate() { + if (this.props.width == null) { + this.measureGutter() + } + + this.applyScroll() //this.checkOverflow() + } + + _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps( + nextProps + ) { + var _this$props = this.props, + range = _this$props.range, + scrollToTime = _this$props.scrollToTime // When paginating, reset scroll + + if ( + !dates.eq(nextProps.range[0], range[0], 'minute') || + !dates.eq(nextProps.scrollToTime, scrollToTime, 'minute') + ) { + this.calculateScroll(nextProps) + } + } + + _proto.renderEvents = function renderEvents( + range, + events, + backgroundEvents, + now + ) { + var _this2 = this + + var _this$props2 = this.props, + min = _this$props2.min, + max = _this$props2.max, + components = _this$props2.components, + accessors = _this$props2.accessors, + localizer = _this$props2.localizer, + dayLayoutAlgorithm = _this$props2.dayLayoutAlgorithm + var resources = this.memoizedResources(this.props.resources, accessors) + var groupedEvents = resources.groupEvents(events) + var groupedBackgroundEvents = resources.groupEvents(backgroundEvents) + return resources.map(function(_ref, i) { + var id = _ref[0], + resource = _ref[1] + return range.map(function(date, jj) { + var daysEvents = (groupedEvents.get(id) || []).filter(function( + event + ) { + return dates.inRange( + date, + accessors.start(event), + accessors.end(event), + 'day' + ) + }) + var daysBackgroundEvents = ( + groupedBackgroundEvents.get(id) || [] + ).filter(function(event) { + return dates.inRange( + date, + accessors.start(event), + accessors.end(event), + 'day' + ) + }) + return _react.default.createElement( + _DayColumn.default, + (0, _extends2.default)({}, _this2.props, { + localizer: localizer, + min: dates.merge(date, min), + max: dates.merge(date, max), + resource: resource && id, + components: components, + isNow: dates.eq(date, now, 'day'), + key: i + '-' + jj, + date: date, + events: daysEvents, + backgroundEvents: daysBackgroundEvents, + dayLayoutAlgorithm: dayLayoutAlgorithm, + }) + ) + }) + }) + } + + _proto.render = function render() { + var _this$props3 = this.props, + events = _this$props3.events, + backgroundEvents = _this$props3.backgroundEvents, + range = _this$props3.range, + width = _this$props3.width, + rtl = _this$props3.rtl, + selected = _this$props3.selected, + getNow = _this$props3.getNow, + resources = _this$props3.resources, + components = _this$props3.components, + accessors = _this$props3.accessors, + getters = _this$props3.getters, + localizer = _this$props3.localizer, + min = _this$props3.min, + max = _this$props3.max, + showMultiDayTimes = _this$props3.showMultiDayTimes, + longPressThreshold = _this$props3.longPressThreshold, + resizable = _this$props3.resizable + width = width || this.state.gutterWidth + var start = range[0], + end = range[range.length - 1] + this.slots = range.length + var allDayEvents = [], + rangeEvents = [], + rangeBackgroundEvents = [] + events.forEach(function(event) { + if ((0, _eventLevels.inRange)(event, start, end, accessors)) { + var eStart = accessors.start(event), + eEnd = accessors.end(event) + + if ( + accessors.allDay(event) || + (dates.isJustDate(eStart) && dates.isJustDate(eEnd)) || + (!showMultiDayTimes && !dates.eq(eStart, eEnd, 'day')) + ) { + allDayEvents.push(event) + } else { + rangeEvents.push(event) + } + } + }) + backgroundEvents.forEach(function(event) { + if ((0, _eventLevels.inRange)(event, start, end, accessors)) { + rangeBackgroundEvents.push(event) + } + }) + allDayEvents.sort(function(a, b) { + return (0, _eventLevels.sortEvents)(a, b, accessors) + }) + return _react.default.createElement( + 'div', + { + className: (0, _clsx.default)( + 'rbc-time-view', + resources && 'rbc-time-view-resources' + ), + }, + _react.default.createElement(_TimeGridHeader.default, { + range: range, + events: allDayEvents, + width: width, + rtl: rtl, + getNow: getNow, + localizer: localizer, + selected: selected, + resources: this.memoizedResources(resources, accessors), + selectable: this.props.selectable, + accessors: accessors, + getters: getters, + components: components, + scrollRef: this.scrollRef, + isOverflowing: this.state.isOverflowing, + longPressThreshold: longPressThreshold, + onSelectSlot: this.handleSelectAllDaySlot, + onSelectEvent: this.handleSelectAlldayEvent, + onDoubleClickEvent: this.props.onDoubleClickEvent, + onKeyPressEvent: this.props.onKeyPressEvent, + onDrillDown: this.props.onDrillDown, + getDrilldownView: this.props.getDrilldownView, + resizable: resizable, + }), + _react.default.createElement( + 'div', + { + ref: this.contentRef, + className: 'rbc-time-content', + onScroll: this.handleScroll, + }, + _react.default.createElement(_TimeGutter.default, { + date: start, + ref: this.gutterRef, + localizer: localizer, + min: dates.merge(start, min), + max: dates.merge(start, max), + step: this.props.step, + getNow: this.props.getNow, + timeslots: this.props.timeslots, + components: components, + className: 'rbc-time-gutter', + getters: getters, + }), + this.renderEvents(range, rangeEvents, rangeBackgroundEvents, getNow()) + ) + ) + } + + _proto.clearSelection = function clearSelection() { + clearTimeout(this._selectTimer) + this._pendingSelection = [] + } + + _proto.measureGutter = function measureGutter() { + var _this3 = this + + if (this.measureGutterAnimationFrameRequest) { + window.cancelAnimationFrame(this.measureGutterAnimationFrameRequest) + } + + this.measureGutterAnimationFrameRequest = window.requestAnimationFrame( + function() { + var width = (0, _width.default)(_this3.gutter) + + if (width && _this3.state.gutterWidth !== width) { + _this3.setState({ + gutterWidth: width, + }) + } + } + ) + } + + _proto.applyScroll = function applyScroll() { + if (this._scrollRatio != null) { + var content = this.contentRef.current + content.scrollTop = content.scrollHeight * this._scrollRatio // Only do this once + + this._scrollRatio = null + } + } + + _proto.calculateScroll = function calculateScroll(props) { + if (props === void 0) { + props = this.props + } + + var _props = props, + min = _props.min, + max = _props.max, + scrollToTime = _props.scrollToTime + var diffMillis = scrollToTime - dates.startOf(scrollToTime, 'day') + var totalMillis = dates.diff(max, min) + this._scrollRatio = diffMillis / totalMillis + } + + return TimeGrid + })(_react.Component) + +exports.default = TimeGrid +TimeGrid.propTypes = + process.env.NODE_ENV !== 'production' + ? { + events: _propTypes.default.array.isRequired, + backgroundEvents: _propTypes.default.array.isRequired, + resources: _propTypes.default.array, + step: _propTypes.default.number, + timeslots: _propTypes.default.number, + range: _propTypes.default.arrayOf(_propTypes.default.instanceOf(Date)), + min: _propTypes.default.instanceOf(Date), + max: _propTypes.default.instanceOf(Date), + getNow: _propTypes.default.func.isRequired, + scrollToTime: _propTypes.default.instanceOf(Date), + showMultiDayTimes: _propTypes.default.bool, + rtl: _propTypes.default.bool, + resizable: _propTypes.default.bool, + width: _propTypes.default.number, + accessors: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + localizer: _propTypes.default.object.isRequired, + selected: _propTypes.default.object, + selectable: _propTypes.default.oneOf([true, false, 'ignoreEvents']), + longPressThreshold: _propTypes.default.number, + onNavigate: _propTypes.default.func, + onSelectSlot: _propTypes.default.func, + onSelectEnd: _propTypes.default.func, + onSelectStart: _propTypes.default.func, + onSelectEvent: _propTypes.default.func, + onDoubleClickEvent: _propTypes.default.func, + onKeyPressEvent: _propTypes.default.func, + onDrillDown: _propTypes.default.func, + getDrilldownView: _propTypes.default.func.isRequired, + dayLayoutAlgorithm: _propTypes2.DayLayoutAlgorithmPropType, + } + : {} +TimeGrid.defaultProps = { + step: 30, + timeslots: 2, + min: dates.startOf(new Date(), 'day'), + max: dates.endOf(new Date(), 'day'), + scrollToTime: dates.startOf(new Date(), 'day'), +} +module.exports = exports['default'] diff --git a/lib/TimeGridEvent.js b/lib/TimeGridEvent.js new file mode 100644 index 000000000..908c4791a --- /dev/null +++ b/lib/TimeGridEvent.js @@ -0,0 +1,135 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends4 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _clsx = _interopRequireDefault(require('clsx')) + +var _react = _interopRequireDefault(require('react')) + +function stringifyPercent(v) { + return typeof v === 'string' ? v : v + '%' +} +/* eslint-disable react/prop-types */ + +function TimeGridEvent(props) { + var _extends2, _extends3 + + var style = props.style, + className = props.className, + event = props.event, + accessors = props.accessors, + rtl = props.rtl, + selected = props.selected, + label = props.label, + continuesEarlier = props.continuesEarlier, + continuesLater = props.continuesLater, + getters = props.getters, + onClick = props.onClick, + onDoubleClick = props.onDoubleClick, + isBackgroundEvent = props.isBackgroundEvent, + onKeyPress = props.onKeyPress, + _props$components = props.components, + Event = _props$components.event, + EventWrapper = _props$components.eventWrapper + var title = accessors.title(event) + var tooltip = accessors.tooltip(event) + var end = accessors.end(event) + var start = accessors.start(event) + var userProps = getters.eventProp(event, start, end, selected) + var height = style.height, + top = style.top, + width = style.width, + xOffset = style.xOffset + var inner = [ + _react.default.createElement( + 'div', + { + key: '1', + className: 'rbc-event-label', + }, + label + ), + _react.default.createElement( + 'div', + { + key: '2', + className: 'rbc-event-content', + }, + Event + ? _react.default.createElement(Event, { + event: event, + title: title, + }) + : title + ), + ] + var eventStyle = isBackgroundEvent + ? (0, _extends4.default)( + {}, + userProps.style, + ((_extends2 = { + top: stringifyPercent(top), + height: stringifyPercent(height), + // Adding 10px to take events container right margin into account + width: 'calc(' + width + ' + 10px)', + }), + (_extends2[rtl ? 'right' : 'left'] = stringifyPercent( + Math.max(0, xOffset) + )), + _extends2) + ) + : (0, _extends4.default)( + {}, + userProps.style, + ((_extends3 = { + top: stringifyPercent(top), + width: stringifyPercent(width), + height: stringifyPercent(height), + }), + (_extends3[rtl ? 'right' : 'left'] = stringifyPercent(xOffset)), + _extends3) + ) + return _react.default.createElement( + EventWrapper, + (0, _extends4.default)( + { + type: 'time', + }, + props + ), + _react.default.createElement( + 'div', + { + onClick: onClick, + onDoubleClick: onDoubleClick, + style: eventStyle, + onKeyPress: onKeyPress, + title: tooltip + ? (typeof label === 'string' ? label + ': ' : '') + tooltip + : undefined, + className: (0, _clsx.default)( + isBackgroundEvent ? 'rbc-background-event' : 'rbc-event', + className, + userProps.className, + { + 'rbc-selected': selected, + 'rbc-event-continues-earlier': continuesEarlier, + 'rbc-event-continues-later': continuesLater, + } + ), + }, + inner + ) + ) +} + +var _default = TimeGridEvent +exports.default = _default +module.exports = exports['default'] diff --git a/lib/TimeGridHeader.js b/lib/TimeGridHeader.js new file mode 100644 index 000000000..b276b7143 --- /dev/null +++ b/lib/TimeGridHeader.js @@ -0,0 +1,313 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _clsx = _interopRequireDefault(require('clsx')) + +var _scrollbarSize = _interopRequireDefault( + require('dom-helpers/scrollbarSize') +) + +var _react = _interopRequireDefault(require('react')) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var _DateContentRow = _interopRequireDefault(require('./DateContentRow')) + +var _Header = _interopRequireDefault(require('./Header')) + +var _ResourceHeader = _interopRequireDefault(require('./ResourceHeader')) + +var _helpers = require('./utils/helpers') + +var TimeGridHeader = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(TimeGridHeader, _React$Component) + + function TimeGridHeader() { + 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.handleHeaderClick = function(date, view, e) { + e.preventDefault() + ;(0, _helpers.notify)(_this.props.onDrillDown, [date, view]) + } + + _this.renderRow = function(resource) { + var _this$props = _this.props, + events = _this$props.events, + rtl = _this$props.rtl, + selectable = _this$props.selectable, + getNow = _this$props.getNow, + range = _this$props.range, + getters = _this$props.getters, + localizer = _this$props.localizer, + accessors = _this$props.accessors, + components = _this$props.components, + resizable = _this$props.resizable + var resourceId = accessors.resourceId(resource) + var eventsToDisplay = resource + ? events.filter(function(event) { + return accessors.resource(event) === resourceId + }) + : events + return _react.default.createElement(_DateContentRow.default, { + isAllDay: true, + rtl: rtl, + getNow: getNow, + minRows: 2, + range: range, + events: eventsToDisplay, + resourceId: resourceId, + className: 'rbc-allday-cell', + selectable: selectable, + selected: _this.props.selected, + components: components, + accessors: accessors, + getters: getters, + localizer: localizer, + onSelect: _this.props.onSelectEvent, + onDoubleClick: _this.props.onDoubleClickEvent, + onKeyPress: _this.props.onKeyPressEvent, + onSelectSlot: _this.props.onSelectSlot, + longPressThreshold: _this.props.longPressThreshold, + resizable: resizable, + }) + } + + return _this + } + + var _proto = TimeGridHeader.prototype + + _proto.renderHeaderCells = function renderHeaderCells(range) { + var _this2 = this + + var _this$props2 = this.props, + localizer = _this$props2.localizer, + getDrilldownView = _this$props2.getDrilldownView, + getNow = _this$props2.getNow, + dayProp = _this$props2.getters.dayProp, + _this$props2$componen = _this$props2.components.header, + HeaderComponent = + _this$props2$componen === void 0 + ? _Header.default + : _this$props2$componen + var today = getNow() + return range.map(function(date, i) { + var drilldownView = getDrilldownView(date) + var label = localizer.format(date, 'dayFormat') + + var _dayProp = dayProp(date), + className = _dayProp.className, + style = _dayProp.style + + var header = _react.default.createElement(HeaderComponent, { + date: date, + label: label, + localizer: localizer, + }) + + return _react.default.createElement( + 'div', + { + key: i, + style: style, + className: (0, _clsx.default)( + 'rbc-header', + className, + dates.eq(date, today, 'day') && 'rbc-today' + ), + }, + drilldownView + ? _react.default.createElement( + 'a', + { + href: '#', + onClick: function onClick(e) { + return _this2.handleHeaderClick(date, drilldownView, e) + }, + }, + header + ) + : _react.default.createElement('span', null, header) + ) + }) + } + + _proto.render = function render() { + var _this3 = this + + var _this$props3 = this.props, + width = _this$props3.width, + rtl = _this$props3.rtl, + resources = _this$props3.resources, + range = _this$props3.range, + events = _this$props3.events, + getNow = _this$props3.getNow, + accessors = _this$props3.accessors, + selectable = _this$props3.selectable, + components = _this$props3.components, + getters = _this$props3.getters, + scrollRef = _this$props3.scrollRef, + localizer = _this$props3.localizer, + isOverflowing = _this$props3.isOverflowing, + _this$props3$componen = _this$props3.components, + TimeGutterHeader = _this$props3$componen.timeGutterHeader, + _this$props3$componen2 = _this$props3$componen.resourceHeader, + ResourceHeaderComponent = + _this$props3$componen2 === void 0 + ? _ResourceHeader.default + : _this$props3$componen2, + resizable = _this$props3.resizable + var style = {} + + if (isOverflowing) { + style[rtl ? 'marginLeft' : 'marginRight'] = + (0, _scrollbarSize.default)() + 'px' + } + + var groupedEvents = resources.groupEvents(events) + return _react.default.createElement( + 'div', + { + style: style, + ref: scrollRef, + className: (0, _clsx.default)( + 'rbc-time-header', + isOverflowing && 'rbc-overflowing' + ), + }, + _react.default.createElement( + 'div', + { + className: 'rbc-label rbc-time-header-gutter', + style: { + width: width, + minWidth: width, + maxWidth: width, + }, + }, + TimeGutterHeader && + _react.default.createElement(TimeGutterHeader, null) + ), + resources.map(function(_ref, idx) { + var id = _ref[0], + resource = _ref[1] + return _react.default.createElement( + 'div', + { + className: 'rbc-time-header-content', + key: id || idx, + }, + resource && + _react.default.createElement( + 'div', + { + className: 'rbc-row rbc-row-resource', + key: 'resource_' + idx, + }, + _react.default.createElement( + 'div', + { + className: 'rbc-header', + }, + _react.default.createElement(ResourceHeaderComponent, { + index: idx, + label: accessors.resourceTitle(resource), + resource: resource, + }) + ) + ), + _react.default.createElement( + 'div', + { + className: + 'rbc-row rbc-time-header-cell' + + (range.length <= 1 ? ' rbc-time-header-cell-single-day' : ''), + }, + _this3.renderHeaderCells(range) + ), + _react.default.createElement(_DateContentRow.default, { + isAllDay: true, + rtl: rtl, + getNow: getNow, + minRows: 2, + range: range, + events: groupedEvents.get(id) || [], + resourceId: resource && id, + className: 'rbc-allday-cell', + selectable: selectable, + selected: _this3.props.selected, + components: components, + accessors: accessors, + getters: getters, + localizer: localizer, + onSelect: _this3.props.onSelectEvent, + onDoubleClick: _this3.props.onDoubleClickEvent, + onKeyPress: _this3.props.onKeyPressEvent, + onSelectSlot: _this3.props.onSelectSlot, + longPressThreshold: _this3.props.longPressThreshold, + resizable: resizable, + }) + ) + }) + ) + } + + return TimeGridHeader + })(_react.default.Component) + +TimeGridHeader.propTypes = + process.env.NODE_ENV !== 'production' + ? { + range: _propTypes.default.array.isRequired, + events: _propTypes.default.array.isRequired, + resources: _propTypes.default.object, + getNow: _propTypes.default.func.isRequired, + isOverflowing: _propTypes.default.bool, + rtl: _propTypes.default.bool, + resizable: _propTypes.default.bool, + width: _propTypes.default.number, + localizer: _propTypes.default.object.isRequired, + accessors: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + selected: _propTypes.default.object, + selectable: _propTypes.default.oneOf([true, false, 'ignoreEvents']), + longPressThreshold: _propTypes.default.number, + onSelectSlot: _propTypes.default.func, + onSelectEvent: _propTypes.default.func, + onDoubleClickEvent: _propTypes.default.func, + onKeyPressEvent: _propTypes.default.func, + onDrillDown: _propTypes.default.func, + getDrilldownView: _propTypes.default.func.isRequired, + scrollRef: _propTypes.default.any, + } + : {} +var _default = TimeGridHeader +exports.default = _default +module.exports = exports['default'] diff --git a/lib/TimeGutter.js b/lib/TimeGutter.js new file mode 100644 index 000000000..367aeed44 --- /dev/null +++ b/lib/TimeGutter.js @@ -0,0 +1,133 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _clsx = _interopRequireDefault(require('clsx')) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireWildcard(require('react')) + +var TimeSlotUtils = _interopRequireWildcard(require('./utils/TimeSlots')) + +var _TimeSlotGroup = _interopRequireDefault(require('./TimeSlotGroup')) + +var TimeGutter = + /*#__PURE__*/ + (function(_Component) { + ;(0, _inheritsLoose2.default)(TimeGutter, _Component) + + function TimeGutter() { + var _this + + for ( + var _len = arguments.length, args = new Array(_len), _key = 0; + _key < _len; + _key++ + ) { + args[_key] = arguments[_key] + } + + _this = _Component.call.apply(_Component, [this].concat(args)) || this + + _this.renderSlot = function(value, idx) { + if (idx !== 0) return null + var _this$props = _this.props, + localizer = _this$props.localizer, + getNow = _this$props.getNow + + var isNow = _this.slotMetrics.dateIsInGroup(getNow(), idx) + + return _react.default.createElement( + 'span', + { + className: (0, _clsx.default)('rbc-label', isNow && 'rbc-now'), + }, + localizer.format(value, 'timeGutterFormat') + ) + } + + var _this$props2 = _this.props, + min = _this$props2.min, + max = _this$props2.max, + timeslots = _this$props2.timeslots, + step = _this$props2.step + _this.slotMetrics = TimeSlotUtils.getSlotMetrics({ + min: min, + max: max, + timeslots: timeslots, + step: step, + }) + return _this + } + + var _proto = TimeGutter.prototype + + _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps( + nextProps + ) { + var min = nextProps.min, + max = nextProps.max, + timeslots = nextProps.timeslots, + step = nextProps.step + this.slotMetrics = this.slotMetrics.update({ + min: min, + max: max, + timeslots: timeslots, + step: step, + }) + } + + _proto.render = function render() { + var _this2 = this + + var _this$props3 = this.props, + resource = _this$props3.resource, + components = _this$props3.components, + getters = _this$props3.getters + return _react.default.createElement( + 'div', + { + className: 'rbc-time-gutter rbc-time-column', + }, + this.slotMetrics.groups.map(function(grp, idx) { + return _react.default.createElement(_TimeSlotGroup.default, { + key: idx, + group: grp, + resource: resource, + components: components, + renderSlot: _this2.renderSlot, + getters: getters, + }) + }) + ) + } + + return TimeGutter + })(_react.Component) + +exports.default = TimeGutter +TimeGutter.propTypes = + process.env.NODE_ENV !== 'production' + ? { + min: _propTypes.default.instanceOf(Date).isRequired, + max: _propTypes.default.instanceOf(Date).isRequired, + timeslots: _propTypes.default.number.isRequired, + step: _propTypes.default.number.isRequired, + getNow: _propTypes.default.func.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object, + localizer: _propTypes.default.object.isRequired, + resource: _propTypes.default.string, + } + : {} +module.exports = exports['default'] diff --git a/lib/TimeSlotGroup.js b/lib/TimeSlotGroup.js new file mode 100644 index 000000000..7eeffcfbe --- /dev/null +++ b/lib/TimeSlotGroup.js @@ -0,0 +1,98 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _clsx = _interopRequireDefault(require('clsx')) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireWildcard(require('react')) + +var _BackgroundWrapper = _interopRequireDefault(require('./BackgroundWrapper')) + +var TimeSlotGroup = + /*#__PURE__*/ + (function(_Component) { + ;(0, _inheritsLoose2.default)(TimeSlotGroup, _Component) + + function TimeSlotGroup() { + return _Component.apply(this, arguments) || this + } + + var _proto = TimeSlotGroup.prototype + + _proto.render = function render() { + var _this$props = this.props, + renderSlot = _this$props.renderSlot, + resource = _this$props.resource, + group = _this$props.group, + getters = _this$props.getters, + _this$props$component = _this$props.components + _this$props$component = + _this$props$component === void 0 ? {} : _this$props$component + var _this$props$component2 = _this$props$component.timeSlotWrapper, + Wrapper = + _this$props$component2 === void 0 + ? _BackgroundWrapper.default + : _this$props$component2 + var groupProps = getters ? getters.slotGroupProp() : {} + return _react.default.createElement( + 'div', + (0, _extends2.default)( + { + className: 'rbc-timeslot-group', + }, + groupProps + ), + group.map(function(value, idx) { + var slotProps = getters ? getters.slotProp(value, resource) : {} + return _react.default.createElement( + Wrapper, + { + key: idx, + value: value, + resource: resource, + }, + _react.default.createElement( + 'div', + (0, _extends2.default)({}, slotProps, { + className: (0, _clsx.default)( + 'rbc-time-slot', + slotProps.className + ), + }), + renderSlot && renderSlot(value, idx) + ) + ) + }) + ) + } + + return TimeSlotGroup + })(_react.Component) + +exports.default = TimeSlotGroup +TimeSlotGroup.propTypes = + process.env.NODE_ENV !== 'production' + ? { + renderSlot: _propTypes.default.func, + group: _propTypes.default.array.isRequired, + resource: _propTypes.default.any, + components: _propTypes.default.object, + getters: _propTypes.default.object, + } + : {} +module.exports = exports['default'] diff --git a/lib/Toolbar.js b/lib/Toolbar.js new file mode 100644 index 000000000..3ca3613bc --- /dev/null +++ b/lib/Toolbar.js @@ -0,0 +1,149 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _clsx = _interopRequireDefault(require('clsx')) + +var _constants = require('./utils/constants') + +var Toolbar = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(Toolbar, _React$Component) + + function Toolbar() { + 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.navigate = function(action) { + _this.props.onNavigate(action) + } + + _this.view = function(view) { + _this.props.onView(view) + } + + return _this + } + + var _proto = Toolbar.prototype + + _proto.render = function render() { + var _this$props = this.props, + messages = _this$props.localizer.messages, + label = _this$props.label + return _react.default.createElement( + 'div', + { + className: 'rbc-toolbar', + }, + _react.default.createElement( + 'span', + { + className: 'rbc-btn-group', + }, + _react.default.createElement( + 'button', + { + type: 'button', + onClick: this.navigate.bind(null, _constants.navigate.TODAY), + }, + messages.today + ), + _react.default.createElement( + 'button', + { + type: 'button', + onClick: this.navigate.bind(null, _constants.navigate.PREVIOUS), + }, + messages.previous + ), + _react.default.createElement( + 'button', + { + type: 'button', + onClick: this.navigate.bind(null, _constants.navigate.NEXT), + }, + messages.next + ) + ), + _react.default.createElement( + 'span', + { + className: 'rbc-toolbar-label', + }, + label + ), + _react.default.createElement( + 'span', + { + className: 'rbc-btn-group', + }, + this.viewNamesGroup(messages) + ) + ) + } + + _proto.viewNamesGroup = 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 _react.default.createElement( + 'button', + { + type: 'button', + key: name, + className: (0, _clsx.default)({ + 'rbc-active': view === name, + }), + onClick: _this2.view.bind(null, name), + }, + messages[name] + ) + }) + } + } + + return Toolbar + })(_react.default.Component) + +Toolbar.propTypes = + process.env.NODE_ENV !== 'production' + ? { + view: _propTypes.default.string.isRequired, + views: _propTypes.default.arrayOf(_propTypes.default.string).isRequired, + label: _propTypes.default.node.isRequired, + localizer: _propTypes.default.object, + onNavigate: _propTypes.default.func.isRequired, + onView: _propTypes.default.func.isRequired, + } + : {} +var _default = Toolbar +exports.default = _default +module.exports = exports['default'] diff --git a/lib/Views.js b/lib/Views.js new file mode 100644 index 000000000..7a136fbf5 --- /dev/null +++ b/lib/Views.js @@ -0,0 +1,31 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _constants = require('./utils/constants') + +var _Month = _interopRequireDefault(require('./Month')) + +var _Day = _interopRequireDefault(require('./Day')) + +var _Week = _interopRequireDefault(require('./Week')) + +var _WorkWeek = _interopRequireDefault(require('./WorkWeek')) + +var _Agenda = _interopRequireDefault(require('./Agenda')) + +var _VIEWS + +var VIEWS = ((_VIEWS = {}), +(_VIEWS[_constants.views.MONTH] = _Month.default), +(_VIEWS[_constants.views.WEEK] = _Week.default), +(_VIEWS[_constants.views.WORK_WEEK] = _WorkWeek.default), +(_VIEWS[_constants.views.DAY] = _Day.default), +(_VIEWS[_constants.views.AGENDA] = _Agenda.default), +_VIEWS) +var _default = VIEWS +exports.default = _default +module.exports = exports['default'] diff --git a/lib/Week.js b/lib/Week.js new file mode 100644 index 000000000..6e4adef08 --- /dev/null +++ b/lib/Week.js @@ -0,0 +1,111 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var dates = _interopRequireWildcard(require('./utils/dates')) + +var _constants = require('./utils/constants') + +var _TimeGrid = _interopRequireDefault(require('./TimeGrid')) + +var Week = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(Week, _React$Component) + + function Week() { + return _React$Component.apply(this, arguments) || this + } + + var _proto = Week.prototype + + _proto.render = function render() { + var _this$props = this.props, + date = _this$props.date, + props = (0, _objectWithoutPropertiesLoose2.default)(_this$props, [ + 'date', + ]) + var range = Week.range(date, this.props) + return _react.default.createElement( + _TimeGrid.default, + (0, _extends2.default)({}, props, { + range: range, + eventOffset: 15, + }) + ) + } + + return Week + })(_react.default.Component) + +Week.propTypes = + process.env.NODE_ENV !== 'production' + ? { + date: _propTypes.default.instanceOf(Date).isRequired, + } + : {} +Week.defaultProps = _TimeGrid.default.defaultProps + +Week.navigate = function(date, action) { + switch (action) { + case _constants.navigate.PREVIOUS: + return dates.add(date, -1, 'week') + + case _constants.navigate.NEXT: + return dates.add(date, 1, 'week') + + default: + return date + } +} + +Week.range = function(date, _ref) { + var localizer = _ref.localizer + var firstOfWeek = localizer.startOfWeek() + var start = dates.startOf(date, 'week', firstOfWeek) + var end = dates.endOf(date, 'week', firstOfWeek) + return dates.range(start, end) +} + +Week.title = function(date, _ref2) { + var localizer = _ref2.localizer + + var _Week$range = Week.range(date, { + localizer: localizer, + }), + start = _Week$range[0], + rest = _Week$range.slice(1) + + return localizer.format( + { + start: start, + end: rest.pop(), + }, + 'dayRangeHeaderFormat' + ) +} + +var _default = Week +exports.default = _default +module.exports = exports['default'] diff --git a/lib/WorkWeek.js b/lib/WorkWeek.js new file mode 100644 index 000000000..7c6b55dab --- /dev/null +++ b/lib/WorkWeek.js @@ -0,0 +1,94 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _Week = _interopRequireDefault(require('./Week')) + +var _TimeGrid = _interopRequireDefault(require('./TimeGrid')) + +function workWeekRange(date, options) { + return _Week.default.range(date, options).filter(function(d) { + return [6, 0].indexOf(d.getDay()) === -1 + }) +} + +var WorkWeek = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(WorkWeek, _React$Component) + + function WorkWeek() { + return _React$Component.apply(this, arguments) || this + } + + var _proto = WorkWeek.prototype + + _proto.render = function render() { + var _this$props = this.props, + date = _this$props.date, + props = (0, _objectWithoutPropertiesLoose2.default)(_this$props, [ + 'date', + ]) + var range = workWeekRange(date, this.props) + return _react.default.createElement( + _TimeGrid.default, + (0, _extends2.default)({}, props, { + range: range, + eventOffset: 15, + }) + ) + } + + return WorkWeek + })(_react.default.Component) + +WorkWeek.propTypes = + process.env.NODE_ENV !== 'production' + ? { + date: _propTypes.default.instanceOf(Date).isRequired, + } + : {} +WorkWeek.defaultProps = _TimeGrid.default.defaultProps +WorkWeek.range = workWeekRange +WorkWeek.navigate = _Week.default.navigate + +WorkWeek.title = function(date, _ref) { + var localizer = _ref.localizer + + var _workWeekRange = workWeekRange(date, { + localizer: localizer, + }), + start = _workWeekRange[0], + rest = _workWeekRange.slice(1) + + return localizer.format( + { + start: start, + end: rest.pop(), + }, + 'dayRangeHeaderFormat' + ) +} + +var _default = WorkWeek +exports.default = _default +module.exports = exports['default'] diff --git a/lib/addons/dragAndDrop/DnDContext.js b/lib/addons/dragAndDrop/DnDContext.js new file mode 100644 index 000000000..0c4149e80 --- /dev/null +++ b/lib/addons/dragAndDrop/DnDContext.js @@ -0,0 +1,12 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.DnDContext = void 0 + +var _react = _interopRequireDefault(require('react')) + +var DnDContext = _react.default.createContext() + +exports.DnDContext = DnDContext diff --git a/lib/addons/dragAndDrop/EventContainerWrapper.js b/lib/addons/dragAndDrop/EventContainerWrapper.js new file mode 100644 index 000000000..0cb003447 --- /dev/null +++ b/lib/addons/dragAndDrop/EventContainerWrapper.js @@ -0,0 +1,351 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var dates = _interopRequireWildcard(require('../../utils/dates')) + +var _DnDContext = require('./DnDContext') + +var _Selection = _interopRequireWildcard(require('../../Selection')) + +var _TimeGridEvent = _interopRequireDefault(require('../../TimeGridEvent')) + +var _common = require('./common') + +var _NoopWrapper = _interopRequireDefault(require('../../NoopWrapper')) + +var EventContainerWrapper = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(EventContainerWrapper, _React$Component) + + function EventContainerWrapper() { + 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.handleMove = function(point, bounds) { + if (!(0, _common.pointInColumn)(bounds, point)) return _this.reset() + var event = _this.context.draggable.dragAndDropAction.event + var _this$props = _this.props, + accessors = _this$props.accessors, + slotMetrics = _this$props.slotMetrics + var newSlot = slotMetrics.closestSlotFromPoint( + { + y: point.y - _this.eventOffsetTop, + x: point.x, + }, + bounds + ) + + var _eventTimes = (0, _common.eventTimes)(event, accessors), + duration = _eventTimes.duration + + var newEnd = dates.add(newSlot, duration, 'milliseconds') + + _this.update(event, slotMetrics.getRange(newSlot, newEnd, false, true)) + } + + _this.handleDropFromOutside = function(point, boundaryBox) { + var _this$props2 = _this.props, + slotMetrics = _this$props2.slotMetrics, + resource = _this$props2.resource + var start = slotMetrics.closestSlotFromPoint( + { + y: point.y, + x: point.x, + }, + boundaryBox + ) + + _this.context.draggable.onDropFromOutside({ + start: start, + end: slotMetrics.nextSlot(start), + allDay: false, + resource: resource, + }) + } + + _this._selectable = function() { + var wrapper = _this.ref.current + var node = wrapper.children[0] + var isBeingDragged = false + var selector = (_this._selector = new _Selection.default(function() { + return wrapper.closest('.rbc-time-view') + })) + selector.on('beforeSelect', function(point) { + var dragAndDropAction = _this.context.draggable.dragAndDropAction + if (!dragAndDropAction.action) return false + + if (dragAndDropAction.action === 'resize') { + return (0, _common.pointInColumn)( + (0, _Selection.getBoundsForNode)(node), + point + ) + } + + var eventNode = (0, _Selection.getEventNodeFromPoint)(node, point) + if (!eventNode) return false // eventOffsetTop is distance from the top of the event to the initial + // mouseDown position. We need this later to compute the new top of the + // event during move operations, since the final location is really a + // delta from this point. note: if we want to DRY this with WeekWrapper, + // probably better just to capture the mouseDown point here and do the + // placement computation in handleMove()... + + _this.eventOffsetTop = + point.y - (0, _Selection.getBoundsForNode)(eventNode).top + }) + selector.on('selecting', function(box) { + var bounds = (0, _Selection.getBoundsForNode)(node) + var dragAndDropAction = _this.context.draggable.dragAndDropAction + if (dragAndDropAction.action === 'move') _this.handleMove(box, bounds) + if (dragAndDropAction.action === 'resize') + _this.handleResize(box, bounds) + }) + selector.on('dropFromOutside', function(point) { + if (!_this.context.draggable.onDropFromOutside) return + var bounds = (0, _Selection.getBoundsForNode)(node) + if (!(0, _common.pointInColumn)(bounds, point)) return + + _this.handleDropFromOutside(point, bounds) + }) + selector.on('dragOver', function(point) { + if (!_this.context.draggable.dragFromOutsideItem) return + var bounds = (0, _Selection.getBoundsForNode)(node) + + _this.handleDropFromOutside(point, bounds) + }) + selector.on('selectStart', function() { + isBeingDragged = true + + _this.context.draggable.onStart() + }) + selector.on('select', function(point) { + var bounds = (0, _Selection.getBoundsForNode)(node) + isBeingDragged = false + if (!_this.state.event || !(0, _common.pointInColumn)(bounds, point)) + return + + _this.handleInteractionEnd() + }) + selector.on('click', function() { + if (isBeingDragged) _this.reset() + + _this.context.draggable.onEnd(null) + }) + selector.on('reset', function() { + _this.reset() + + _this.context.draggable.onEnd(null) + }) + } + + _this.handleInteractionEnd = function() { + var resource = _this.props.resource + var event = _this.state.event + + _this.reset() + + _this.context.draggable.onEnd({ + start: event.start, + end: event.end, + resourceId: resource, + }) + } + + _this._teardownSelectable = function() { + if (!_this._selector) return + + _this._selector.teardown() + + _this._selector = null + } + + _this.state = {} + _this.ref = _react.default.createRef() + return _this + } + + var _proto = EventContainerWrapper.prototype + + _proto.componentDidMount = function componentDidMount() { + this._selectable() + } + + _proto.componentWillUnmount = function componentWillUnmount() { + this._teardownSelectable() + } + + _proto.reset = function reset() { + if (this.state.event) + this.setState({ + event: null, + top: null, + height: null, + }) + } + + _proto.update = function update(event, _ref) { + var startDate = _ref.startDate, + endDate = _ref.endDate, + top = _ref.top, + height = _ref.height + var lastEvent = this.state.event + + if ( + lastEvent && + startDate === lastEvent.start && + endDate === lastEvent.end + ) { + return + } + + this.setState({ + top: top, + height: height, + event: (0, _extends2.default)({}, event, { + start: startDate, + end: endDate, + }), + }) + } + + _proto.handleResize = function handleResize(point, bounds) { + var _this$props3 = this.props, + accessors = _this$props3.accessors, + slotMetrics = _this$props3.slotMetrics + var _this$context$draggab = this.context.draggable.dragAndDropAction, + event = _this$context$draggab.event, + direction = _this$context$draggab.direction + var newTime = slotMetrics.closestSlotFromPoint(point, bounds) + + var _eventTimes2 = (0, _common.eventTimes)(event, accessors), + start = _eventTimes2.start, + end = _eventTimes2.end + + if (direction === 'UP') { + start = dates.min(newTime, slotMetrics.closestSlotFromDate(end, -1)) + } else if (direction === 'DOWN') { + end = dates.max(newTime, slotMetrics.closestSlotFromDate(start)) + } + + this.update(event, slotMetrics.getRange(start, end)) + } + + _proto.renderContent = function renderContent() { + var _this$props4 = this.props, + children = _this$props4.children, + accessors = _this$props4.accessors, + components = _this$props4.components, + getters = _this$props4.getters, + slotMetrics = _this$props4.slotMetrics, + localizer = _this$props4.localizer + var _this$state = this.state, + event = _this$state.event, + top = _this$state.top, + height = _this$state.height + if (!event) return children + var events = children.props.children + var start = event.start, + end = event.end + var label + var format = 'eventTimeRangeFormat' + var startsBeforeDay = slotMetrics.startsBeforeDay(start) + var startsAfterDay = slotMetrics.startsAfterDay(end) + if (startsBeforeDay) format = 'eventTimeRangeEndFormat' + else if (startsAfterDay) format = 'eventTimeRangeStartFormat' + if (startsBeforeDay && startsAfterDay) label = localizer.messages.allDay + else + label = localizer.format( + { + start: start, + end: end, + }, + format + ) + return _react.default.cloneElement(children, { + children: _react.default.createElement( + _react.default.Fragment, + null, + events, + event && + _react.default.createElement(_TimeGridEvent.default, { + event: event, + label: label, + className: 'rbc-addons-dnd-drag-preview', + style: { + top: top, + height: height, + width: 100, + }, + getters: getters, + components: (0, _extends2.default)({}, components, { + eventWrapper: _NoopWrapper.default, + }), + accessors: (0, _extends2.default)( + {}, + accessors, + _common.dragAccessors + ), + continuesEarlier: startsBeforeDay, + continuesLater: startsAfterDay, + }) + ), + }) + } + + _proto.render = function render() { + return _react.default.createElement( + 'div', + { + ref: this.ref, + }, + this.renderContent() + ) + } + + return EventContainerWrapper + })(_react.default.Component) + +EventContainerWrapper.contextType = _DnDContext.DnDContext +EventContainerWrapper.propTypes = + process.env.NODE_ENV !== 'production' + ? { + accessors: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + localizer: _propTypes.default.object.isRequired, + slotMetrics: _propTypes.default.object.isRequired, + resource: _propTypes.default.any, + } + : {} +var _default = EventContainerWrapper +exports.default = _default +module.exports = exports['default'] diff --git a/lib/addons/dragAndDrop/EventWrapper.js b/lib/addons/dragAndDrop/EventWrapper.js new file mode 100644 index 000000000..3257ffb5e --- /dev/null +++ b/lib/addons/dragAndDrop/EventWrapper.js @@ -0,0 +1,237 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _clsx = _interopRequireDefault(require('clsx')) + +var _accessors = require('../../utils/accessors') + +var _DnDContext = require('./DnDContext') + +var EventWrapper = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(EventWrapper, _React$Component) + + function EventWrapper() { + 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.handleResizeUp = function(e) { + if (e.button !== 0) return + + _this.context.draggable.onBeginAction(_this.props.event, 'resize', 'UP') + } + + _this.handleResizeDown = function(e) { + if (e.button !== 0) return + + _this.context.draggable.onBeginAction( + _this.props.event, + 'resize', + 'DOWN' + ) + } + + _this.handleResizeLeft = function(e) { + if (e.button !== 0) return + + _this.context.draggable.onBeginAction( + _this.props.event, + 'resize', + 'LEFT' + ) + } + + _this.handleResizeRight = function(e) { + if (e.button !== 0) return + + _this.context.draggable.onBeginAction( + _this.props.event, + 'resize', + 'RIGHT' + ) + } + + _this.handleStartDragging = function(e) { + if (e.button !== 0) return // hack: because of the way the anchors are arranged in the DOM, resize + // anchor events will bubble up to the move anchor listener. Don't start + // move operations when we're on a resize anchor. + + var isResizeHandle = e.target.className.includes( + 'rbc-addons-dnd-resize' + ) + if (!isResizeHandle) + _this.context.draggable.onBeginAction(_this.props.event, 'move') + } + + return _this + } + + var _proto = EventWrapper.prototype + + _proto.renderAnchor = function renderAnchor(direction) { + var cls = direction === 'Up' || direction === 'Down' ? 'ns' : 'ew' + return _react.default.createElement( + 'div', + { + className: 'rbc-addons-dnd-resize-' + cls + '-anchor', + onMouseDown: this['handleResize' + direction], + }, + _react.default.createElement('div', { + className: 'rbc-addons-dnd-resize-' + cls + '-icon', + }) + ) + } + + _proto.render = function render() { + var _this$props = this.props, + event = _this$props.event, + type = _this$props.type, + continuesPrior = _this$props.continuesPrior, + continuesAfter = _this$props.continuesAfter, + resizable = _this$props.resizable + var children = this.props.children + if (event.__isPreview) + return _react.default.cloneElement(children, { + className: (0, _clsx.default)( + children.props.className, + 'rbc-addons-dnd-drag-preview' + ), + }) + var draggable = this.context.draggable + var draggableAccessor = draggable.draggableAccessor, + resizableAccessor = draggable.resizableAccessor + var isDraggable = draggableAccessor + ? !!(0, _accessors.accessor)(event, draggableAccessor) + : true + /* Event is not draggable, no need to wrap it */ + + if (!isDraggable) { + return children + } + /* + * The resizability of events depends on whether they are + * allDay events and how they are displayed. + * + * 1. If the event is being shown in an event row (because + * it is an allDay event shown in the header row or because as + * in month view the view is showing all events as rows) then we + * allow east-west resizing. + * + * 2. Otherwise the event is being displayed + * normally, we can drag it north-south to resize the times. + * + * See `DropWrappers` for handling of the drop of such events. + * + * Notwithstanding the above, we never show drag anchors for + * events which continue beyond current component. This happens + * in the middle of events when showMultiDay is true, and to + * events at the edges of the calendar's min/max location. + */ + + var isResizable = + resizable && + (resizableAccessor + ? !!(0, _accessors.accessor)(event, resizableAccessor) + : true) + + if (isResizable || isDraggable) { + /* + * props.children is the singular component. + * BigCalendar positions the Event abolutely and we + * need the anchors to be part of that positioning. + * So we insert the anchors inside the Event's children + * rather than wrap the Event here as the latter approach + * would lose the positioning. + */ + var newProps = { + onMouseDown: this.handleStartDragging, + onTouchStart: this.handleStartDragging, + } + + if (isResizable) { + // replace original event child with anchor-embellished child + var StartAnchor = null + var EndAnchor = null + + if (type === 'date') { + StartAnchor = !continuesPrior && this.renderAnchor('Left') + EndAnchor = !continuesAfter && this.renderAnchor('Right') + } else { + StartAnchor = !continuesPrior && this.renderAnchor('Up') + EndAnchor = !continuesAfter && this.renderAnchor('Down') + } + + newProps.children = _react.default.createElement( + 'div', + { + className: 'rbc-addons-dnd-resizable', + }, + StartAnchor, + children.props.children, + EndAnchor + ) + } + + if ( + draggable.dragAndDropAction.interacting && // if an event is being dragged right now + draggable.dragAndDropAction.event === event // and it's the current event + ) { + // add a new class to it + newProps.className = (0, _clsx.default)( + children.props.className, + 'rbc-addons-dnd-dragged-event' + ) + } + + children = _react.default.cloneElement(children, newProps) + } + + return children + } + + return EventWrapper + })(_react.default.Component) + +EventWrapper.contextType = _DnDContext.DnDContext +EventWrapper.propTypes = + process.env.NODE_ENV !== 'production' + ? { + type: _propTypes.default.oneOf(['date', 'time']), + event: _propTypes.default.object.isRequired, + draggable: _propTypes.default.bool, + allDay: _propTypes.default.bool, + isRow: _propTypes.default.bool, + continuesPrior: _propTypes.default.bool, + continuesAfter: _propTypes.default.bool, + isDragging: _propTypes.default.bool, + isResizing: _propTypes.default.bool, + resizable: _propTypes.default.bool, + } + : {} +var _default = EventWrapper +exports.default = _default +module.exports = exports['default'] diff --git a/lib/addons/dragAndDrop/WeekWrapper.js b/lib/addons/dragAndDrop/WeekWrapper.js new file mode 100644 index 000000000..cb15cff47 --- /dev/null +++ b/lib/addons/dragAndDrop/WeekWrapper.js @@ -0,0 +1,370 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _EventRow = _interopRequireDefault(require('../../EventRow')) + +var _Selection = _interopRequireWildcard(require('../../Selection')) + +var dates = _interopRequireWildcard(require('../../utils/dates')) + +var _eventLevels = require('../../utils/eventLevels') + +var _selection = require('../../utils/selection') + +var _common = require('./common') + +var _DnDContext = require('./DnDContext') + +var WeekWrapper = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(WeekWrapper, _React$Component) + + function WeekWrapper() { + 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.handleMove = function(point, bounds, draggedEvent) { + if (!(0, _selection.pointInBox)(bounds, point)) return _this.reset() + var event = + _this.context.draggable.dragAndDropAction.event || draggedEvent + var _this$props = _this.props, + accessors = _this$props.accessors, + slotMetrics = _this$props.slotMetrics, + rtl = _this$props.rtl + var slot = (0, _selection.getSlotAtX)( + bounds, + point.x - _this.eventOffsetLeft, + rtl, + slotMetrics.slots + ) + var date = slotMetrics.getDateForSlot(slot) // Adjust the dates, but maintain the times when moving + + var _eventTimes = (0, _common.eventTimes)(event, accessors), + start = _eventTimes.start, + duration = _eventTimes.duration + + start = dates.merge(date, start) + var end = dates.add(start, duration, 'milliseconds') // LATER: when dragging a multi-row event, only the first row is animating + + _this.update(event, start, end) + } + + _this.handleDropFromOutside = function(point, bounds) { + if (!_this.context.draggable.onDropFromOutside) return + var _this$props2 = _this.props, + slotMetrics = _this$props2.slotMetrics, + rtl = _this$props2.rtl + var slot = (0, _selection.getSlotAtX)( + bounds, + point.x, + rtl, + slotMetrics.slots + ) + var start = slotMetrics.getDateForSlot(slot) + + _this.context.draggable.onDropFromOutside({ + start: start, + end: dates.add(start, 1, 'day'), + allDay: false, + }) + } + + _this.handleDragOverFromOutside = function(point, node) { + if (!_this.context.draggable.dragFromOutsideItem) return + + _this.handleMove( + point, + node, + _this.context.draggable.dragFromOutsideItem() + ) + } + + _this._selectable = function() { + var node = _this.ref.current.closest('.rbc-month-row, .rbc-allday-cell') + + var container = node.closest('.rbc-month-view, .rbc-time-view') + var selector = (_this._selector = new _Selection.default(function() { + return container + })) + selector.on('beforeSelect', function(point) { + var isAllDay = _this.props.isAllDay + var action = _this.context.draggable.dragAndDropAction.action + var eventNode = (0, _Selection.getEventNodeFromPoint)(node, point) // eventOffsetLeft is distance from the left of the event to the initial + // mouseDown position. We need this later to compute the new top of the + // event during move operations, since the final location is really a + // delta from this point. note: if we want to DRY this with + // EventContainerWrapper, probably better just to capture the mouseDown + // point here and do the placement computation in handleMove()... + + _this.eventOffsetLeft = + point.x - (0, _Selection.getBoundsForNode)(eventNode).left + var isInBox = (0, _selection.pointInBox)( + (0, _Selection.getBoundsForNode)(node), + point + ) + return ( + action === 'move' || (action === 'resize' && (!isAllDay || isInBox)) + ) + }) + selector.on('selecting', function(box) { + var bounds = (0, _Selection.getBoundsForNode)(node) + var dragAndDropAction = _this.context.draggable.dragAndDropAction + if (dragAndDropAction.action === 'move') _this.handleMove(box, bounds) + if (dragAndDropAction.action === 'resize') + _this.handleResize(box, bounds) + }) + selector.on('selectStart', function() { + return _this.context.draggable.onStart() + }) + selector.on('select', function(point) { + var bounds = (0, _Selection.getBoundsForNode)(node) + if (!_this.state.segment) return + + if (!(0, _selection.pointInBox)(bounds, point)) { + _this.reset() + } else { + _this.handleInteractionEnd() + } + }) + selector.on('dropFromOutside', function(point) { + if (!_this.context.draggable.onDropFromOutside) return + var bounds = (0, _Selection.getBoundsForNode)(node) + if (!(0, _selection.pointInBox)(bounds, point)) return + + _this.handleDropFromOutside(point, bounds) + }) + selector.on('dragOverFromOutside', function(point) { + if (!_this.context.draggable.dragFromOutsideItem) return + var bounds = (0, _Selection.getBoundsForNode)(node) + + _this.handleDragOverFromOutside(point, bounds) + }) + selector.on('click', function() { + return _this.context.draggable.onEnd(null) + }) + selector.on('reset', function() { + _this.reset() + + _this.context.draggable.onEnd(null) + }) + } + + _this.handleInteractionEnd = function() { + var _this$props3 = _this.props, + resourceId = _this$props3.resourceId, + isAllDay = _this$props3.isAllDay + var event = _this.state.segment.event + + _this.reset() + + _this.context.draggable.onEnd({ + start: event.start, + end: event.end, + resourceId: resourceId, + isAllDay: isAllDay, + }) + } + + _this._teardownSelectable = function() { + if (!_this._selector) return + + _this._selector.teardown() + + _this._selector = null + } + + _this.state = {} + _this.ref = _react.default.createRef() + return _this + } + + var _proto = WeekWrapper.prototype + + _proto.componentDidMount = function componentDidMount() { + this._selectable() + } + + _proto.componentWillUnmount = function componentWillUnmount() { + this._teardownSelectable() + } + + _proto.reset = function reset() { + if (this.state.segment) + this.setState({ + segment: null, + }) + } + + _proto.update = function update(event, start, end) { + var segment = (0, _eventLevels.eventSegments)( + (0, _extends2.default)({}, event, { + end: end, + start: start, + __isPreview: true, + }), + this.props.slotMetrics.range, + _common.dragAccessors + ) + var lastSegment = this.state.segment + + if ( + lastSegment && + segment.span === lastSegment.span && + segment.left === lastSegment.left && + segment.right === lastSegment.right + ) { + return + } + + this.setState({ + segment: segment, + }) + } + + _proto.handleResize = function handleResize(point, bounds) { + var _this$context$draggab = this.context.draggable.dragAndDropAction, + event = _this$context$draggab.event, + direction = _this$context$draggab.direction + var _this$props4 = this.props, + accessors = _this$props4.accessors, + slotMetrics = _this$props4.slotMetrics, + rtl = _this$props4.rtl + + var _eventTimes2 = (0, _common.eventTimes)(event, accessors), + start = _eventTimes2.start, + end = _eventTimes2.end + + var slot = (0, _selection.getSlotAtX)( + bounds, + point.x, + rtl, + slotMetrics.slots + ) + var date = slotMetrics.getDateForSlot(slot) + var cursorInRow = (0, _selection.pointInBox)(bounds, point) + + if (direction === 'RIGHT') { + if (cursorInRow) { + if (slotMetrics.last < start) return this.reset() + end = dates.add(date, 1, 'day') + } else if ( + dates.inRange(start, slotMetrics.first, slotMetrics.last) || + (bounds.bottom < point.y && +slotMetrics.first > +start) + ) { + end = dates.add(slotMetrics.last, 1, 'milliseconds') + } else { + this.setState({ + segment: null, + }) + return + } + + var originalEnd = accessors.end(event) + end = dates.merge(end, originalEnd) + + if (dates.lt(end, start)) { + end = originalEnd + } + } else if (direction === 'LEFT') { + if (cursorInRow) { + if (slotMetrics.first > end) return this.reset() + start = date + } else if ( + dates.inRange(end, slotMetrics.first, slotMetrics.last) || + (bounds.top > point.y && dates.lt(slotMetrics.last, end)) + ) { + start = dates.add(slotMetrics.first, -1, 'milliseconds') + } else { + this.reset() + return + } + + var originalStart = accessors.start(event) + start = dates.merge(start, originalStart) + + if (dates.gt(start, end)) { + start = originalStart + } + } + + this.update(event, start, end) + } + + _proto.render = function render() { + var _this$props5 = this.props, + children = _this$props5.children, + accessors = _this$props5.accessors + var segment = this.state.segment + return _react.default.createElement( + 'div', + { + ref: this.ref, + className: 'rbc-addons-dnd-row-body', + }, + children, + segment && + _react.default.createElement( + _EventRow.default, + (0, _extends2.default)({}, this.props, { + selected: null, + className: 'rbc-addons-dnd-drag-row', + segments: [segment], + accessors: (0, _extends2.default)( + {}, + accessors, + _common.dragAccessors + ), + }) + ) + ) + } + + return WeekWrapper + })(_react.default.Component) + +WeekWrapper.contextType = _DnDContext.DnDContext +WeekWrapper.propTypes = + process.env.NODE_ENV !== 'production' + ? { + isAllDay: _propTypes.default.bool, + slotMetrics: _propTypes.default.object.isRequired, + accessors: _propTypes.default.object.isRequired, + getters: _propTypes.default.object.isRequired, + components: _propTypes.default.object.isRequired, + resourceId: _propTypes.default.any, + rtl: _propTypes.default.bool, + } + : {} +var _default = WeekWrapper +exports.default = _default +module.exports = exports['default'] diff --git a/lib/addons/dragAndDrop/common.js b/lib/addons/dragAndDrop/common.js new file mode 100644 index 000000000..b95206e9e --- /dev/null +++ b/lib/addons/dragAndDrop/common.js @@ -0,0 +1,96 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.mergeComponents = mergeComponents +exports.pointInColumn = pointInColumn +exports.eventTimes = eventTimes +exports.dragAccessors = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _accessors = require('../../utils/accessors') + +var _react = require('react') + +var dates = _interopRequireWildcard(require('../../utils/dates')) + +var dragAccessors = { + start: (0, _accessors.wrapAccessor)(function(e) { + return e.start + }), + end: (0, _accessors.wrapAccessor)(function(e) { + return e.end + }), +} +exports.dragAccessors = dragAccessors + +function nest() { + for ( + var _len = arguments.length, Components = new Array(_len), _key = 0; + _key < _len; + _key++ + ) { + Components[_key] = arguments[_key] + } + + var factories = Components.filter(Boolean).map(_react.createFactory) + + var Nest = function Nest(_ref) { + var children = _ref.children, + props = (0, _objectWithoutPropertiesLoose2.default)(_ref, ['children']) + return factories.reduceRight(function(child, factory) { + return factory(props, child) + }, children) + } + + return Nest +} + +function mergeComponents(components, addons) { + if (components === void 0) { + components = {} + } + + var keys = Object.keys(addons) + var result = (0, _extends2.default)({}, components) + keys.forEach(function(key) { + result[key] = components[key] + ? nest(components[key], addons[key]) + : addons[key] + }) + return result +} + +function pointInColumn(bounds, point) { + var left = bounds.left, + right = bounds.right, + top = bounds.top + var x = point.x, + y = point.y + return x < right + 10 && x > left && y > top +} + +function eventTimes(event, accessors) { + var start = accessors.start(event) + var end = accessors.end(event) + var isZeroDuration = + dates.eq(start, end, 'minutes') && start.getMinutes() === 0 // make zero duration midnight events at least one day long + + if (isZeroDuration) end = dates.add(end, 1, 'day') + var duration = dates.diff(end, start, 'milliseconds') + return { + start: start, + end: end, + duration: duration, + } +} diff --git a/lib/addons/dragAndDrop/index.js b/lib/addons/dragAndDrop/index.js new file mode 100644 index 000000000..8a7a4efdc --- /dev/null +++ b/lib/addons/dragAndDrop/index.js @@ -0,0 +1,12 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _withDragAndDrop = _interopRequireDefault(require('./withDragAndDrop')) + +var _default = _withDragAndDrop.default +exports.default = _default +module.exports = exports['default'] diff --git a/lib/addons/dragAndDrop/styles.css b/lib/addons/dragAndDrop/styles.css new file mode 100644 index 000000000..256d158bb --- /dev/null +++ b/lib/addons/dragAndDrop/styles.css @@ -0,0 +1,80 @@ +.rbc-addons-dnd .rbc-addons-dnd-row-body { + position: relative; +} + +.rbc-addons-dnd .rbc-addons-dnd-drag-row { + position: absolute; + top: 0; + left: 0; + right: 0; +} + +.rbc-addons-dnd .rbc-addons-dnd-over { + background-color: rgba(0, 0, 0, 0.3); +} + +.rbc-addons-dnd .rbc-event { + transition: opacity 150ms; +} +.rbc-addons-dnd .rbc-event:hover .rbc-addons-dnd-resize-ns-icon, +.rbc-addons-dnd .rbc-event:hover .rbc-addons-dnd-resize-ew-icon { + display: block; +} + +.rbc-addons-dnd .rbc-addons-dnd-dragged-event { + opacity: 0; +} + +.rbc-addons-dnd.rbc-addons-dnd-is-dragging + .rbc-event:not(.rbc-addons-dnd-dragged-event):not(.rbc-addons-dnd-drag-preview) { + opacity: 0.5; +} + +.rbc-addons-dnd .rbc-addons-dnd-resizable { + position: relative; + width: 100%; + height: 100%; +} + +.rbc-addons-dnd .rbc-addons-dnd-resize-ns-anchor { + width: 100%; + text-align: center; + position: absolute; +} +.rbc-addons-dnd .rbc-addons-dnd-resize-ns-anchor:first-child { + top: 0; +} +.rbc-addons-dnd .rbc-addons-dnd-resize-ns-anchor:last-child { + bottom: 0; +} +.rbc-addons-dnd + .rbc-addons-dnd-resize-ns-anchor + .rbc-addons-dnd-resize-ns-icon { + display: none; + border-top: 3px double; + margin: 0 auto; + width: 10px; + cursor: ns-resize; +} + +.rbc-addons-dnd .rbc-addons-dnd-resize-ew-anchor { + position: absolute; + top: 4px; + bottom: 0; +} +.rbc-addons-dnd .rbc-addons-dnd-resize-ew-anchor:first-child { + left: 0; +} +.rbc-addons-dnd .rbc-addons-dnd-resize-ew-anchor:last-child { + right: 0; +} +.rbc-addons-dnd + .rbc-addons-dnd-resize-ew-anchor + .rbc-addons-dnd-resize-ew-icon { + display: none; + border-left: 3px double; + margin-top: auto; + margin-bottom: auto; + height: 10px; + cursor: ew-resize; +} diff --git a/lib/addons/dragAndDrop/styles.scss b/lib/addons/dragAndDrop/styles.scss new file mode 100644 index 000000000..ab6c94bb6 --- /dev/null +++ b/lib/addons/dragAndDrop/styles.scss @@ -0,0 +1,78 @@ +@import '../../sass/variables'; + +.rbc-addons-dnd { + .rbc-addons-dnd-row-body { + position: relative; + } + .rbc-addons-dnd-drag-row { + position: absolute; + top: 0; + left: 0; + right: 0; + } + + + .rbc-addons-dnd-over { + background-color: rgba( + red($date-selection-bg-color), + green($date-selection-bg-color), + blue($date-selection-bg-color), + .3 + ); + } + + .rbc-event { + transition: opacity 150ms; + + &:hover { + .rbc-addons-dnd-resize-ns-icon, .rbc-addons-dnd-resize-ew-icon { display: block; } + } + } + + .rbc-addons-dnd-dragged-event { + opacity: 0; + } + + &.rbc-addons-dnd-is-dragging .rbc-event:not(.rbc-addons-dnd-dragged-event):not(.rbc-addons-dnd-drag-preview) { + opacity: .50; + } + + .rbc-addons-dnd-resizable { + position: relative; + width: 100%; + height: 100%; + } + + .rbc-addons-dnd-resize-ns-anchor { + width: 100%; + text-align: center; + position: absolute; + &:first-child { top: 0; } + &:last-child { bottom: 0; } + + .rbc-addons-dnd-resize-ns-icon { + display: none; + border-top: 3px double; + margin: 0 auto; + width: 10px; + cursor: ns-resize; + } + } + + .rbc-addons-dnd-resize-ew-anchor { + position: absolute; + top: 4px; + bottom: 0; + &:first-child { left: 0; } + &:last-child { right: 0; } + + .rbc-addons-dnd-resize-ew-icon { + display: none; + border-left: 3px double; + margin-top: auto; + margin-bottom: auto; + height: 10px; + cursor: ew-resize; + } + } +} diff --git a/lib/addons/dragAndDrop/withDragAndDrop.js b/lib/addons/dragAndDrop/withDragAndDrop.js new file mode 100644 index 000000000..f73f99987 --- /dev/null +++ b/lib/addons/dragAndDrop/withDragAndDrop.js @@ -0,0 +1,208 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = withDragAndDrop + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _inheritsLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/inheritsLoose') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var _clsx = _interopRequireDefault(require('clsx')) + +var _propTypes2 = require('../../utils/propTypes') + +var _EventWrapper = _interopRequireDefault(require('./EventWrapper')) + +var _EventContainerWrapper = _interopRequireDefault( + require('./EventContainerWrapper') +) + +var _WeekWrapper = _interopRequireDefault(require('./WeekWrapper')) + +var _common = require('./common') + +var _DnDContext = require('./DnDContext') + +function withDragAndDrop(Calendar) { + var DragAndDropCalendar = + /*#__PURE__*/ + (function(_React$Component) { + ;(0, _inheritsLoose2.default)(DragAndDropCalendar, _React$Component) + + function DragAndDropCalendar() { + 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.defaultOnDragOver = function(event) { + event.preventDefault() + } + + _this.handleBeginAction = function(event, action, direction) { + _this.setState({ + event: event, + action: action, + direction: direction, + }) + + var onDragStart = _this.props.onDragStart + if (onDragStart) + onDragStart({ + event: event, + action: action, + direction: direction, + }) + } + + _this.handleInteractionStart = function() { + if (_this.state.interacting === false) + _this.setState({ + interacting: true, + }) + } + + _this.handleInteractionEnd = function(interactionInfo) { + var _this$state = _this.state, + action = _this$state.action, + event = _this$state.event + if (!action) return + + _this.setState({ + action: null, + event: null, + interacting: false, + direction: null, + }) + + if (interactionInfo == null) return + interactionInfo.event = event + var _this$props = _this.props, + onEventDrop = _this$props.onEventDrop, + onEventResize = _this$props.onEventResize + if (action === 'move' && onEventDrop) onEventDrop(interactionInfo) + if (action === 'resize' && onEventResize) + onEventResize(interactionInfo) + } + + var components = _this.props.components + _this.components = (0, _common.mergeComponents)(components, { + eventWrapper: _EventWrapper.default, + eventContainerWrapper: _EventContainerWrapper.default, + weekWrapper: _WeekWrapper.default, + }) + _this.state = { + interacting: false, + } + return _this + } + + var _proto = DragAndDropCalendar.prototype + + _proto.getDnDContextValue = function getDnDContextValue() { + return { + draggable: { + onStart: this.handleInteractionStart, + onEnd: this.handleInteractionEnd, + onBeginAction: this.handleBeginAction, + onDropFromOutside: this.props.onDropFromOutside, + dragFromOutsideItem: this.props.dragFromOutsideItem, + draggableAccessor: this.props.draggableAccessor, + resizableAccessor: this.props.resizableAccessor, + dragAndDropAction: this.state, + }, + } + } + + _proto.render = function render() { + var _this$props2 = this.props, + selectable = _this$props2.selectable, + elementProps = _this$props2.elementProps, + props = (0, _objectWithoutPropertiesLoose2.default)(_this$props2, [ + 'selectable', + 'elementProps', + ]) + var interacting = this.state.interacting + delete props.onEventDrop + delete props.onEventResize + props.selectable = selectable ? 'ignoreEvents' : false + var elementPropsWithDropFromOutside = this.props.onDropFromOutside + ? (0, _extends2.default)({}, elementProps, { + onDragOver: this.props.onDragOver || this.defaultOnDragOver, + }) + : elementProps + props.className = (0, _clsx.default)( + props.className, + 'rbc-addons-dnd', + !!interacting && 'rbc-addons-dnd-is-dragging' + ) + var context = this.getDnDContextValue() + return _react.default.createElement( + _DnDContext.DnDContext.Provider, + { + value: context, + }, + _react.default.createElement( + Calendar, + (0, _extends2.default)({}, props, { + elementProps: elementPropsWithDropFromOutside, + components: this.components, + }) + ) + ) + } + + return DragAndDropCalendar + })(_react.default.Component) + + DragAndDropCalendar.defaultProps = (0, _extends2.default)( + {}, + Calendar.defaultProps, + { + draggableAccessor: null, + resizableAccessor: null, + resizable: true, + } + ) + DragAndDropCalendar.propTypes = + process.env.NODE_ENV !== 'production' + ? (0, _extends2.default)({}, Calendar.propTypes, { + onEventDrop: _propTypes.default.func, + onEventResize: _propTypes.default.func, + onDragStart: _propTypes.default.func, + onDragOver: _propTypes.default.func, + onDropFromOutside: _propTypes.default.func, + dragFromOutsideItem: _propTypes.default.func, + draggableAccessor: _propTypes2.accessor, + resizableAccessor: _propTypes2.accessor, + selectable: _propTypes.default.oneOf([true, false, 'ignoreEvents']), + resizable: _propTypes.default.bool, + }) + : {} + return DragAndDropCalendar +} + +module.exports = exports['default'] diff --git a/lib/css/react-big-calendar.css b/lib/css/react-big-calendar.css new file mode 100644 index 000000000..0d8d520a9 --- /dev/null +++ b/lib/css/react-big-calendar.css @@ -0,0 +1,673 @@ +@charset "UTF-8"; +.rbc-btn { + color: inherit; + font: inherit; + margin: 0; +} + +button.rbc-btn { + overflow: visible; + text-transform: none; + -webkit-appearance: button; + cursor: pointer; +} + +button[disabled].rbc-btn { + cursor: not-allowed; +} + +button.rbc-input::-moz-focus-inner { + border: 0; + padding: 0; +} + +.rbc-calendar { + box-sizing: border-box; + height: 100%; + display: flex; + flex-direction: column; + align-items: stretch; +} + +.rbc-calendar *, +.rbc-calendar *:before, +.rbc-calendar *:after { + box-sizing: inherit; +} + +.rbc-abs-full, +.rbc-row-bg { + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.rbc-ellipsis, +.rbc-event-label, +.rbc-row-segment .rbc-event-content, +.rbc-show-more { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.rbc-rtl { + direction: rtl; +} + +.rbc-off-range { + color: #999999; +} + +.rbc-off-range-bg { + background: #e6e6e6; +} + +.rbc-header { + overflow: hidden; + flex: 1 0 0%; + text-overflow: ellipsis; + white-space: nowrap; + padding: 0 3px; + text-align: center; + vertical-align: middle; + font-weight: bold; + font-size: 90%; + min-height: 0; + border-bottom: 1px solid #ddd; +} +.rbc-header + .rbc-header { + border-left: 1px solid #ddd; +} +.rbc-rtl .rbc-header + .rbc-header { + border-left-width: 0; + border-right: 1px solid #ddd; +} +.rbc-header > a, +.rbc-header > a:active, +.rbc-header > a:visited { + color: inherit; + text-decoration: none; +} + +.rbc-row-content { + position: relative; + user-select: none; + -webkit-user-select: none; + z-index: 4; +} + +.rbc-row-content-scrollable { + display: flex; + flex-direction: column; + height: 100%; +} +.rbc-row-content-scrollable .rbc-row-content-scroll-container { + height: 100%; + overflow-y: scroll; + /* Hide scrollbar for Chrome, Safari and Opera */ + -ms-overflow-style: none; + /* IE and Edge */ + scrollbar-width: none; + /* Firefox */ +} +.rbc-row-content-scrollable + .rbc-row-content-scroll-container::-webkit-scrollbar { + display: none; +} + +.rbc-today { + background-color: #eaf6ff; +} + +.rbc-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + margin-bottom: 10px; + font-size: 16px; +} +.rbc-toolbar .rbc-toolbar-label { + flex-grow: 1; + padding: 0 10px; + text-align: center; +} +.rbc-toolbar button { + color: #373a3c; + display: inline-block; + margin: 0; + text-align: center; + vertical-align: middle; + background: none; + background-image: none; + border: 1px solid #ccc; + padding: 0.375rem 1rem; + border-radius: 4px; + line-height: normal; + white-space: nowrap; +} +.rbc-toolbar button:active, +.rbc-toolbar button.rbc-active { + background-image: none; + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + background-color: #e6e6e6; + border-color: #adadad; +} +.rbc-toolbar button:active:hover, +.rbc-toolbar button:active:focus, +.rbc-toolbar button.rbc-active:hover, +.rbc-toolbar button.rbc-active:focus { + color: #373a3c; + background-color: #d4d4d4; + border-color: #8c8c8c; +} +.rbc-toolbar button:focus { + color: #373a3c; + background-color: #e6e6e6; + border-color: #adadad; +} +.rbc-toolbar button:hover { + color: #373a3c; + background-color: #e6e6e6; + border-color: #adadad; +} + +.rbc-btn-group { + display: inline-block; + white-space: nowrap; +} +.rbc-btn-group > button:first-child:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.rbc-btn-group > button:last-child:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.rbc-rtl .rbc-btn-group > button:first-child:not(:last-child) { + border-radius: 4px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.rbc-rtl .rbc-btn-group > button:last-child:not(:first-child) { + border-radius: 4px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.rbc-btn-group > button:not(:first-child):not(:last-child) { + border-radius: 0; +} +.rbc-btn-group button + button { + margin-left: -1px; +} +.rbc-rtl .rbc-btn-group button + button { + margin-left: 0; + margin-right: -1px; +} +.rbc-btn-group + .rbc-btn-group, +.rbc-btn-group + button { + margin-left: 10px; +} + +.rbc-event, +.rbc-day-slot .rbc-background-event { + border: none; + box-sizing: border-box; + box-shadow: none; + margin: 0; + padding: 2px 5px; + background-color: #3174ad; + border-radius: 5px; + color: #fff; + cursor: pointer; + width: 100%; + text-align: left; +} +.rbc-slot-selecting .rbc-event, +.rbc-slot-selecting .rbc-day-slot .rbc-background-event, +.rbc-day-slot .rbc-slot-selecting .rbc-background-event { + cursor: inherit; + pointer-events: none; +} +.rbc-event.rbc-selected, +.rbc-day-slot .rbc-selected.rbc-background-event { + background-color: #265985; +} +.rbc-event:focus, +.rbc-day-slot .rbc-background-event:focus { + outline: 5px auto #3b99fc; +} + +.rbc-event-label { + font-size: 80%; +} + +.rbc-event-overlaps { + box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5); +} + +.rbc-event-continues-prior { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.rbc-event-continues-after { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.rbc-event-continues-earlier { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.rbc-event-continues-later { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.rbc-row { + display: flex; + flex-direction: row; +} + +.rbc-row-segment { + padding: 0 1px 1px 1px; +} + +.rbc-selected-cell { + background-color: rgba(0, 0, 0, 0.1); +} + +.rbc-show-more { + background-color: rgba(255, 255, 255, 0.3); + z-index: 4; + font-weight: bold; + font-size: 85%; + height: auto; + line-height: normal; +} + +.rbc-month-view { + position: relative; + border: 1px solid #ddd; + display: flex; + flex-direction: column; + flex: 1 0 0; + width: 100%; + user-select: none; + -webkit-user-select: none; + height: 100%; +} + +.rbc-month-header { + display: flex; + flex-direction: row; +} + +.rbc-month-row { + display: flex; + position: relative; + flex-direction: column; + flex: 1 0 0; + flex-basis: 0px; + overflow: hidden; + height: 100%; +} +.rbc-month-row + .rbc-month-row { + border-top: 1px solid #ddd; +} + +.rbc-date-cell { + flex: 1 1 0; + min-width: 0; + padding-right: 5px; + text-align: right; +} +.rbc-date-cell.rbc-now { + font-weight: bold; +} +.rbc-date-cell > a, +.rbc-date-cell > a:active, +.rbc-date-cell > a:visited { + color: inherit; + text-decoration: none; +} + +.rbc-row-bg { + display: flex; + flex-direction: row; + flex: 1 0 0; + overflow: hidden; +} + +.rbc-day-bg { + flex: 1 0 0%; +} +.rbc-day-bg + .rbc-day-bg { + border-left: 1px solid #ddd; +} +.rbc-rtl .rbc-day-bg + .rbc-day-bg { + border-left-width: 0; + border-right: 1px solid #ddd; +} + +.rbc-overlay { + position: absolute; + z-index: 5; + border: 1px solid #e5e5e5; + background-color: #fff; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.25); + padding: 10px; +} +.rbc-overlay > * + * { + margin-top: 1px; +} + +.rbc-overlay-header { + border-bottom: 1px solid #e5e5e5; + margin: -10px -10px 5px -10px; + padding: 2px 10px; +} + +.rbc-agenda-view { + display: flex; + flex-direction: column; + flex: 1 0 0; + overflow: auto; +} +.rbc-agenda-view table.rbc-agenda-table { + width: 100%; + border: 1px solid #ddd; + border-spacing: 0; + border-collapse: collapse; +} +.rbc-agenda-view table.rbc-agenda-table tbody > tr > td { + padding: 5px 10px; + vertical-align: top; +} +.rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell { + padding-left: 15px; + padding-right: 15px; + text-transform: lowercase; +} +.rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td { + border-left: 1px solid #ddd; +} +.rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td { + border-left-width: 0; + border-right: 1px solid #ddd; +} +.rbc-agenda-view table.rbc-agenda-table tbody > tr + tr { + border-top: 1px solid #ddd; +} +.rbc-agenda-view table.rbc-agenda-table thead > tr > th { + padding: 3px 5px; + text-align: left; + border-bottom: 1px solid #ddd; +} +.rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th { + text-align: right; +} + +.rbc-agenda-time-cell { + text-transform: lowercase; +} +.rbc-agenda-time-cell .rbc-continues-after:after { + content: ' »'; +} +.rbc-agenda-time-cell .rbc-continues-prior:before { + content: '« '; +} + +.rbc-agenda-date-cell, +.rbc-agenda-time-cell { + white-space: nowrap; +} + +.rbc-agenda-event-cell { + width: 100%; +} + +.rbc-time-column { + display: flex; + flex-direction: column; + min-height: 100%; +} +.rbc-time-column .rbc-timeslot-group { + flex: 1; +} + +.rbc-timeslot-group { + border-bottom: 1px solid #ddd; + min-height: 40px; + display: flex; + flex-flow: column nowrap; +} + +.rbc-time-gutter, +.rbc-header-gutter { + flex: none; +} + +.rbc-label { + padding: 0 5px; +} + +.rbc-day-slot { + position: relative; +} +.rbc-day-slot .rbc-events-container { + bottom: 0; + left: 0; + position: absolute; + right: 0; + margin-right: 10px; + top: 0; +} +.rbc-day-slot .rbc-events-container.rbc-rtl { + left: 10px; + right: 0; +} +.rbc-day-slot .rbc-event, +.rbc-day-slot .rbc-background-event { + border: 1px solid #265985; + display: flex; + max-height: 100%; + min-height: 20px; + flex-flow: column wrap; + align-items: flex-start; + overflow: hidden; + position: absolute; +} +.rbc-day-slot .rbc-background-event { + opacity: 0.75; +} +.rbc-day-slot .rbc-event-label { + flex: none; + padding-right: 5px; + width: auto; +} +.rbc-day-slot .rbc-event-content { + width: 100%; + flex: 1 1 0; + word-wrap: break-word; + line-height: 1; + height: 100%; + min-height: 1em; +} +.rbc-day-slot .rbc-time-slot { + border-top: 1px solid #f7f7f7; +} + +.rbc-time-view-resources .rbc-time-gutter, +.rbc-time-view-resources .rbc-time-header-gutter { + position: sticky; + left: 0; + background-color: white; + border-right: 1px solid #ddd; + z-index: 10; + margin-right: -1px; +} + +.rbc-time-view-resources .rbc-time-header { + overflow: hidden; +} + +.rbc-time-view-resources .rbc-time-header-content { + min-width: auto; + flex: 1 0 0; + flex-basis: 0px; +} + +.rbc-time-view-resources .rbc-time-header-cell-single-day { + display: none; +} + +.rbc-time-view-resources .rbc-day-slot { + min-width: 140px; +} + +.rbc-time-view-resources .rbc-header, +.rbc-time-view-resources .rbc-day-bg { + width: 140px; + flex: 1 1 0; + flex-basis: 0 px; +} + +.rbc-time-header-content + .rbc-time-header-content { + margin-left: -1px; +} + +.rbc-time-slot { + flex: 1 0 0; +} +.rbc-time-slot.rbc-now { + font-weight: bold; +} + +.rbc-day-header { + text-align: center; +} + +.rbc-slot-selection { + z-index: 10; + position: absolute; + background-color: rgba(0, 0, 0, 0.5); + color: white; + font-size: 75%; + width: 100%; + padding: 3px; +} + +.rbc-slot-selecting { + cursor: move; +} + +.rbc-time-view { + display: flex; + flex-direction: column; + flex: 1; + width: 100%; + border: 1px solid #ddd; + min-height: 0; +} +.rbc-time-view .rbc-time-gutter { + white-space: nowrap; +} +.rbc-time-view .rbc-allday-cell { + box-sizing: content-box; + width: 100%; + height: 100%; + position: relative; +} +.rbc-time-view .rbc-allday-cell + .rbc-allday-cell { + border-left: 1px solid #ddd; +} +.rbc-time-view .rbc-allday-events { + position: relative; + z-index: 4; +} +.rbc-time-view .rbc-row { + box-sizing: border-box; + min-height: 20px; +} + +.rbc-time-header { + display: flex; + flex: 0 0 auto; + flex-direction: row; +} +.rbc-time-header.rbc-overflowing { + border-right: 1px solid #ddd; +} +.rbc-rtl .rbc-time-header.rbc-overflowing { + border-right-width: 0; + border-left: 1px solid #ddd; +} +.rbc-time-header > .rbc-row:first-child { + border-bottom: 1px solid #ddd; +} +.rbc-time-header > .rbc-row.rbc-row-resource { + border-bottom: 1px solid #ddd; +} + +.rbc-time-header-cell-single-day { + display: none; +} + +.rbc-time-header-content { + flex: 1; + display: flex; + min-width: 0; + flex-direction: column; + border-left: 1px solid #ddd; +} +.rbc-rtl .rbc-time-header-content { + border-left-width: 0; + border-right: 1px solid #ddd; +} +.rbc-time-header-content > .rbc-row.rbc-row-resource { + border-bottom: 1px solid #ddd; + flex-shrink: 0; +} + +.rbc-time-content { + display: flex; + flex: 1 0 0%; + align-items: flex-start; + width: 100%; + border-top: 2px solid #ddd; + overflow-y: auto; + position: relative; +} +.rbc-time-content > .rbc-time-gutter { + flex: none; +} +.rbc-time-content > * + * > * { + border-left: 1px solid #ddd; +} +.rbc-rtl .rbc-time-content > * + * > * { + border-left-width: 0; + border-right: 1px solid #ddd; +} +.rbc-time-content > .rbc-day-slot { + width: 100%; + user-select: none; + -webkit-user-select: none; +} + +.rbc-current-time-indicator { + position: absolute; + z-index: 3; + left: 0; + right: 0; + height: 1px; + background-color: #74ad31; + pointer-events: none; +} diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 000000000..b7f74d242 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,45 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.Navigate = exports.Views = exports.DateLocalizer = exports.move = exports.dateFnsLocalizer = exports.globalizeLocalizer = exports.momentLocalizer = exports.Calendar = exports.components = void 0 + +var _EventWrapper = _interopRequireDefault(require('./EventWrapper')) + +var _BackgroundWrapper = _interopRequireDefault(require('./BackgroundWrapper')) + +var _Calendar = _interopRequireDefault(require('./Calendar')) + +exports.Calendar = _Calendar.default + +var _localizer = require('./localizer') + +exports.DateLocalizer = _localizer.DateLocalizer + +var _moment = _interopRequireDefault(require('./localizers/moment')) + +exports.momentLocalizer = _moment.default + +var _globalize = _interopRequireDefault(require('./localizers/globalize')) + +exports.globalizeLocalizer = _globalize.default + +var _dateFns = _interopRequireDefault(require('./localizers/date-fns')) + +exports.dateFnsLocalizer = _dateFns.default + +var _move = _interopRequireDefault(require('./utils/move')) + +exports.move = _move.default + +var _constants = require('./utils/constants') + +exports.Views = _constants.views +exports.Navigate = _constants.navigate +var components = { + eventWrapper: _EventWrapper.default, + timeSlotWrapper: _BackgroundWrapper.default, + dateCellWrapper: _BackgroundWrapper.default, +} +exports.components = components diff --git a/lib/localizer.js b/lib/localizer.js new file mode 100644 index 000000000..60cd0b74a --- /dev/null +++ b/lib/localizer.js @@ -0,0 +1,87 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.mergeWithDefaults = mergeWithDefaults +exports.DateLocalizer = void 0 + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _invariant = _interopRequireDefault(require('invariant')) + +var localePropType = _propTypes.default.oneOfType([ + _propTypes.default.string, + _propTypes.default.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' + ? (0, _invariant.default)( + 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' + ? (0, _invariant.default)( + false, + 'date localizer `format(..)` must be a function' + ) + : invariant(false) + : void 0 + !(typeof spec.firstOfWeek === 'function') + ? process.env.NODE_ENV !== 'production' + ? (0, _invariant.default)( + 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)) + } +} + +exports.DateLocalizer = DateLocalizer + +function mergeWithDefaults(localizer, culture, formatOverrides, messages) { + var formats = (0, _extends2.default)({}, localizer.formats, formatOverrides) + return (0, _extends2.default)({}, localizer, { + messages: messages, + startOfWeek: function startOfWeek() { + return localizer.startOfWeek(culture) + }, + format: function format(value, _format2) { + return localizer.format(value, formats[_format2] || _format2, culture) + }, + }) +} diff --git a/lib/localizers/date-fns.js b/lib/localizers/date-fns.js new file mode 100644 index 000000000..4c024b074 --- /dev/null +++ b/lib/localizers/date-fns.js @@ -0,0 +1,98 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +exports.__esModule = true +exports.default = exports.formats = void 0 + +var dates = _interopRequireWildcard(require('../utils/dates')) + +var _localizer = require('../localizer') + +var dateRangeFormat = function dateRangeFormat(_ref, culture, local) { + var start = _ref.start, + end = _ref.end + return ( + local.format(start, 'P', culture) + + ' \u2013 ' + + local.format(end, 'P', culture) + ) +} + +var timeRangeFormat = function timeRangeFormat(_ref2, culture, local) { + var start = _ref2.start, + end = _ref2.end + return ( + local.format(start, 'p', culture) + + ' \u2013 ' + + local.format(end, 'p', culture) + ) +} + +var timeRangeStartFormat = function timeRangeStartFormat( + _ref3, + culture, + local +) { + var start = _ref3.start + return local.format(start, 'h:mma', culture) + ' \u2013 ' +} + +var timeRangeEndFormat = function timeRangeEndFormat(_ref4, culture, local) { + var end = _ref4.end + return ' \u2013 ' + local.format(end, 'h:mma', culture) +} + +var weekRangeFormat = function weekRangeFormat(_ref5, culture, local) { + var start = _ref5.start, + end = _ref5.end + return ( + local.format(start, 'MMMM dd', culture) + + ' \u2013 ' + + local.format(end, dates.eq(start, end, 'month') ? 'dd' : 'MMMM dd', culture) + ) +} + +var formats = { + dateFormat: 'dd', + dayFormat: 'dd eee', + weekdayFormat: 'cccc', + selectRangeFormat: timeRangeFormat, + eventTimeRangeFormat: timeRangeFormat, + eventTimeRangeStartFormat: timeRangeStartFormat, + eventTimeRangeEndFormat: timeRangeEndFormat, + timeGutterFormat: 'p', + monthHeaderFormat: 'MMMM yyyy', + dayHeaderFormat: 'cccc MMM dd', + dayRangeHeaderFormat: weekRangeFormat, + agendaHeaderFormat: dateRangeFormat, + agendaDateFormat: 'ccc MMM dd', + agendaTimeFormat: 'p', + agendaTimeRangeFormat: timeRangeFormat, +} +exports.formats = formats + +var dateFnsLocalizer = function dateFnsLocalizer(_ref6) { + var startOfWeek = _ref6.startOfWeek, + getDay = _ref6.getDay, + _format = _ref6.format, + locales = _ref6.locales + return new _localizer.DateLocalizer({ + formats: formats, + firstOfWeek: function firstOfWeek(culture) { + return getDay( + startOfWeek(new Date(), { + locale: locales[culture], + }) + ) + }, + format: function format(value, formatString, culture) { + return _format(new Date(value), formatString, { + locale: locales[culture], + }) + }, + }) +} + +var _default = dateFnsLocalizer +exports.default = _default diff --git a/lib/localizers/globalize.js b/lib/localizers/globalize.js new file mode 100644 index 000000000..b1e091fa6 --- /dev/null +++ b/lib/localizers/globalize.js @@ -0,0 +1,178 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +exports.__esModule = true +exports.default = _default +exports.formats = void 0 + +var dates = _interopRequireWildcard(require('../utils/dates')) + +var _oldGlobalize = _interopRequireDefault(require('./oldGlobalize')) + +var _localizer = require('../localizer') + +var dateRangeFormat = function dateRangeFormat(_ref, culture, local) { + var start = _ref.start, + end = _ref.end + return ( + local.format( + start, + { + date: 'short', + }, + culture + ) + + ' – ' + + local.format( + end, + { + date: 'short', + }, + culture + ) + ) +} + +var timeRangeFormat = function timeRangeFormat(_ref2, culture, local) { + var start = _ref2.start, + end = _ref2.end + return ( + local.format( + start, + { + time: 'short', + }, + culture + ) + + ' – ' + + local.format( + end, + { + time: 'short', + }, + culture + ) + ) +} + +var timeRangeStartFormat = function timeRangeStartFormat( + _ref3, + culture, + local +) { + var start = _ref3.start + return ( + local.format( + start, + { + time: 'short', + }, + culture + ) + ' – ' + ) +} + +var timeRangeEndFormat = function timeRangeEndFormat(_ref4, culture, local) { + var end = _ref4.end + return ( + ' – ' + + local.format( + end, + { + time: 'short', + }, + culture + ) + ) +} + +var weekRangeFormat = function weekRangeFormat(_ref5, culture, local) { + var start = _ref5.start, + end = _ref5.end + return ( + local.format(start, 'MMM dd', culture) + + ' – ' + + local.format(end, dates.eq(start, end, 'month') ? 'dd' : 'MMM dd', culture) + ) +} + +var formats = { + dateFormat: 'dd', + dayFormat: 'eee dd/MM', + weekdayFormat: 'eee', + selectRangeFormat: timeRangeFormat, + eventTimeRangeFormat: timeRangeFormat, + eventTimeRangeStartFormat: timeRangeStartFormat, + eventTimeRangeEndFormat: timeRangeEndFormat, + timeGutterFormat: { + time: 'short', + }, + monthHeaderFormat: 'MMMM yyyy', + dayHeaderFormat: 'eeee MMM dd', + dayRangeHeaderFormat: weekRangeFormat, + agendaHeaderFormat: dateRangeFormat, + agendaDateFormat: 'eee MMM dd', + agendaTimeFormat: { + time: 'short', + }, + agendaTimeRangeFormat: timeRangeFormat, +} +exports.formats = formats + +function _default(globalize) { + var locale = function locale(culture) { + return culture ? globalize(culture) : globalize + } // return the first day of the week from the locale data. Defaults to 'world' + // territory if no territory is derivable from CLDR. + // Failing to use CLDR supplemental (not loaded?), revert to the original + // method of getting first day of week. + + function firstOfWeek(culture) { + try { + var days = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'] + var cldr = locale(culture).cldr + var territory = cldr.attributes.territory + var weekData = cldr.get('supplemental').weekData + var firstDay = weekData.firstDay[territory || '001'] + return days.indexOf(firstDay) + } catch (e) { + if (process.env.NODE_ENV !== 'production') { + console.error( + 'Failed to accurately determine first day of the week.' + + ' Is supplemental data loaded into CLDR?' + ) + } // maybe cldr supplemental is not loaded? revert to original method + + var date = new Date() //cldr-data doesn't seem to be zero based + + var localeDay = Math.max( + parseInt( + locale(culture).formatDate(date, { + raw: 'e', + }), + 10 + ) - 1, + 0 + ) + return Math.abs(date.getDay() - localeDay) + } + } + + if (!globalize.load) return (0, _oldGlobalize.default)(globalize) + return new _localizer.DateLocalizer({ + firstOfWeek: firstOfWeek, + formats: formats, + format: function format(value, _format, culture) { + _format = + typeof _format === 'string' + ? { + raw: _format, + } + : _format + return locale(culture).formatDate(value, _format) + }, + }) +} diff --git a/lib/localizers/moment.js b/lib/localizers/moment.js new file mode 100644 index 000000000..b2c82bd1d --- /dev/null +++ b/lib/localizers/moment.js @@ -0,0 +1,89 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +exports.__esModule = true +exports.default = _default +exports.formats = void 0 + +var dates = _interopRequireWildcard(require('../utils/dates')) + +var _localizer = require('../localizer') + +var dateRangeFormat = function dateRangeFormat(_ref, culture, local) { + var start = _ref.start, + end = _ref.end + return ( + local.format(start, 'L', culture) + ' – ' + local.format(end, 'L', culture) + ) +} + +var timeRangeFormat = function timeRangeFormat(_ref2, culture, local) { + var start = _ref2.start, + end = _ref2.end + return ( + local.format(start, 'LT', culture) + + ' – ' + + local.format(end, 'LT', culture) + ) +} + +var timeRangeStartFormat = function timeRangeStartFormat( + _ref3, + culture, + local +) { + var start = _ref3.start + return local.format(start, 'LT', culture) + ' – ' +} + +var timeRangeEndFormat = function timeRangeEndFormat(_ref4, culture, local) { + var end = _ref4.end + return ' – ' + local.format(end, 'LT', culture) +} + +var weekRangeFormat = function weekRangeFormat(_ref5, culture, local) { + var start = _ref5.start, + end = _ref5.end + return ( + local.format(start, 'MMMM DD', culture) + + ' – ' + + local.format(end, dates.eq(start, end, 'month') ? 'DD' : 'MMMM DD', culture) + ) +} + +var formats = { + dateFormat: 'DD', + dayFormat: 'DD ddd', + weekdayFormat: 'ddd', + selectRangeFormat: timeRangeFormat, + eventTimeRangeFormat: timeRangeFormat, + eventTimeRangeStartFormat: timeRangeStartFormat, + eventTimeRangeEndFormat: timeRangeEndFormat, + timeGutterFormat: 'LT', + monthHeaderFormat: 'MMMM YYYY', + dayHeaderFormat: 'dddd MMM DD', + dayRangeHeaderFormat: weekRangeFormat, + agendaHeaderFormat: dateRangeFormat, + agendaDateFormat: 'ddd MMM DD', + agendaTimeFormat: 'LT', + agendaTimeRangeFormat: timeRangeFormat, +} +exports.formats = formats + +function _default(moment) { + var locale = function locale(m, c) { + return c ? m.locale(c) : m + } + + return new _localizer.DateLocalizer({ + formats: formats, + firstOfWeek: function firstOfWeek(culture) { + var data = culture ? moment.localeData(culture) : moment.localeData() + return data ? data.firstDayOfWeek() : 0 + }, + format: function format(value, _format, culture) { + return locale(moment(value), culture).format(_format) + }, + }) +} diff --git a/lib/localizers/oldGlobalize.js b/lib/localizers/oldGlobalize.js new file mode 100644 index 000000000..ff45f26ba --- /dev/null +++ b/lib/localizers/oldGlobalize.js @@ -0,0 +1,89 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +exports.__esModule = true +exports.default = _default +exports.formats = void 0 + +var dates = _interopRequireWildcard(require('../utils/dates')) + +var _localizer = require('../localizer') + +var dateRangeFormat = function dateRangeFormat(_ref, culture, local) { + var start = _ref.start, + end = _ref.end + return ( + local.format(start, 'd', culture) + ' – ' + local.format(end, 'd', culture) + ) +} + +var timeRangeFormat = function timeRangeFormat(_ref2, culture, local) { + var start = _ref2.start, + end = _ref2.end + return ( + local.format(start, 't', culture) + ' – ' + local.format(end, 't', culture) + ) +} + +var timeRangeStartFormat = function timeRangeStartFormat( + _ref3, + culture, + local +) { + var start = _ref3.start + return local.format(start, 't', culture) + ' – ' +} + +var timeRangeEndFormat = function timeRangeEndFormat(_ref4, culture, local) { + var end = _ref4.end + return ' – ' + local.format(end, 't', culture) +} + +var weekRangeFormat = function weekRangeFormat(_ref5, culture, local) { + var start = _ref5.start, + end = _ref5.end + return ( + local.format(start, 'MMM dd', culture) + + ' – ' + + local.format(end, dates.eq(start, end, 'month') ? 'dd' : 'MMM dd', culture) + ) +} + +var formats = { + dateFormat: 'dd', + dayFormat: 'ddd dd/MM', + weekdayFormat: 'ddd', + selectRangeFormat: timeRangeFormat, + eventTimeRangeFormat: timeRangeFormat, + eventTimeRangeStartFormat: timeRangeStartFormat, + eventTimeRangeEndFormat: timeRangeEndFormat, + timeGutterFormat: 't', + monthHeaderFormat: 'Y', + dayHeaderFormat: 'dddd MMM dd', + dayRangeHeaderFormat: weekRangeFormat, + agendaHeaderFormat: dateRangeFormat, + agendaDateFormat: 'ddd MMM dd', + agendaTimeFormat: 't', + agendaTimeRangeFormat: timeRangeFormat, +} +exports.formats = formats + +function _default(globalize) { + function getCulture(culture) { + return culture ? globalize.findClosestCulture(culture) : globalize.culture() + } + + function firstOfWeek(culture) { + culture = getCulture(culture) + return (culture && culture.calendar.firstDay) || 0 + } + + return new _localizer.DateLocalizer({ + firstOfWeek: firstOfWeek, + formats: formats, + format: function format(value, _format, culture) { + return globalize.format(value, _format, culture) + }, + }) +} diff --git a/lib/sass/agenda.scss b/lib/sass/agenda.scss new file mode 100644 index 000000000..7ab738757 --- /dev/null +++ b/lib/sass/agenda.scss @@ -0,0 +1,73 @@ +@import './variables'; + +.rbc-agenda-view { + display: flex; + flex-direction: column; + flex: 1 0 0; + overflow: auto; + + table.rbc-agenda-table { + width: 100%; + border: 1px solid $cell-border; + border-spacing: 0; + border-collapse: collapse; + + tbody > tr > td { + padding: 5px 10px; + vertical-align: top; + } + + .rbc-agenda-time-cell { + padding-left: 15px; + padding-right: 15px; + text-transform: lowercase; + } + + tbody > tr > td + td { + border-left: 1px solid $cell-border; + } + + .rbc-rtl & { + tbody > tr > td + td { + border-left-width: 0; + border-right: 1px solid $cell-border; + } + } + + tbody > tr + tr { + border-top: 1px solid $cell-border; + } + + thead > tr > th { + padding: 3px 5px; + text-align: left; + border-bottom: 1px solid $cell-border; + + .rbc-rtl & { + text-align: right; + } + } + } +} + +.rbc-agenda-time-cell { + text-transform: lowercase; + + .rbc-continues-after:after { + content: ' »' + } + .rbc-continues-prior:before { + content: '« ' + } +} + +.rbc-agenda-date-cell, +.rbc-agenda-time-cell { + white-space: nowrap; +} + + + +.rbc-agenda-event-cell { + width: 100% +} diff --git a/lib/sass/event.scss b/lib/sass/event.scss new file mode 100644 index 000000000..46234584a --- /dev/null +++ b/lib/sass/event.scss @@ -0,0 +1,56 @@ +@import './variables'; + +.rbc-event { + border: none; + box-sizing: border-box; + box-shadow: none; + margin: 0; + padding: $event-padding; + background-color: $event-bg; + border-radius: $event-border-radius; + color: $event-color; + cursor: pointer; + width: 100%; + text-align: left; + + .rbc-slot-selecting & { + cursor: inherit; + pointer-events: none; + } + + &.rbc-selected { + background-color: darken($event-bg, 10%); + } + + &:focus { + outline: 5px auto $event-outline; + } +} + +.rbc-event-label { + @extend .rbc-ellipsis; + font-size: 80%; +} + +.rbc-event-overlaps { + box-shadow: -1px 1px 5px 0px rgba(51,51,51,.5); +} + +.rbc-event-continues-prior { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.rbc-event-continues-after { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + + +.rbc-event-continues-earlier { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.rbc-event-continues-later { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} diff --git a/lib/sass/month.scss b/lib/sass/month.scss new file mode 100644 index 000000000..9f2fecdf7 --- /dev/null +++ b/lib/sass/month.scss @@ -0,0 +1,120 @@ +@import './variables'; + +.rbc-row { + display: flex; + flex-direction: row; +} + +.rbc-row-segment { + padding: 0 1px 1px 1px; + + .rbc-event-content { + @extend .rbc-ellipsis; + } +} + +.rbc-selected-cell { + background-color: $date-selection-bg-color; +} + + +.rbc-show-more { + @extend .rbc-ellipsis; + background-color: rgba(255, 255, 255, 0.3); + z-index: $event-zindex; + font-weight: bold; + font-size: 85%; + height: auto; + line-height: normal; +} + +.rbc-month-view { + position: relative; + border: 1px solid $calendar-border; + display: flex; + flex-direction: column; + flex: 1 0 0; + width: 100%; + user-select: none; + -webkit-user-select: none; + + height: 100%; // ie-fix +} + +.rbc-month-header { + display: flex; + flex-direction: row; +} + +.rbc-month-row { + display: flex; + position: relative; + flex-direction: column; + flex: 1 0 0; // postcss will remove the 0px here hence the duplication below + flex-basis: 0px; + overflow: hidden; + + height: 100%; // ie-fix + + & + & { + border-top: 1px solid $cell-border; + } +} + +.rbc-date-cell { + flex: 1 1 0; + min-width: 0; + padding-right: 5px; + text-align: right; + + &.rbc-now { + font-weight: bold; + } + + > a { + &, &:active, &:visited { + color: inherit; + text-decoration: none; + } + } +} + +.rbc-row-bg { + @extend .rbc-abs-full; + display: flex; + flex-direction: row; + flex: 1 0 0; + overflow: hidden; +} + +.rbc-day-bg { + flex: 1 0 0%; + + & + & { + border-left: 1px solid $cell-border; + } + + .rbc-rtl & + & { + border-left-width: 0; + border-right: 1px solid $cell-border; + } +} + +.rbc-overlay { + position: absolute; + z-index: $event-zindex + 1; + border: 1px solid #e5e5e5; + background-color: #fff; + box-shadow: 0 5px 15px rgba(0,0,0,.25); + padding: 10px; + + > * + * { + margin-top: 1px; + } +} + +.rbc-overlay-header { + border-bottom: 1px solid #e5e5e5; + margin: -10px -10px 5px -10px ; + padding: 2px 10px; +} diff --git a/lib/sass/reset.scss b/lib/sass/reset.scss new file mode 100644 index 000000000..33ae98707 --- /dev/null +++ b/lib/sass/reset.scss @@ -0,0 +1,22 @@ +.rbc-btn { + color: inherit; + font: inherit; + margin: 0; +} + +button.rbc-btn { + overflow: visible; + text-transform: none; + -webkit-appearance: button; + cursor: pointer; +} + +button[disabled].rbc-btn { + cursor: not-allowed; +} + +button.rbc-input::-moz-focus-inner { + border: 0; + padding: 0; +} + diff --git a/lib/sass/styles.scss b/lib/sass/styles.scss new file mode 100644 index 000000000..4eeae6941 --- /dev/null +++ b/lib/sass/styles.scss @@ -0,0 +1,110 @@ +@import './variables'; +@import './reset'; + +.rbc-calendar { + box-sizing: border-box; + height: 100%; + display: flex; + flex-direction: column; + align-items: stretch; +} + +.rbc-calendar *, +.rbc-calendar *:before, +.rbc-calendar *:after { + box-sizing: inherit; +} + +.rbc-abs-full { + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.rbc-ellipsis { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.rbc-rtl { + direction: rtl; +} + +.rbc-off-range { + color: $out-of-range-color; +} + +.rbc-off-range-bg { + background: $out-of-range-bg-color; +} + +.rbc-header { + overflow: hidden; + flex: 1 0 0%; + text-overflow: ellipsis; + white-space: nowrap; + padding: 0 3px; + text-align: center; + vertical-align: middle; + font-weight: bold; + font-size: 90%; + min-height: 0; + border-bottom: 1px solid $cell-border; + + & + & { + border-left: 1px solid $cell-border; + } + + .rbc-rtl & + & { + border-left-width: 0; + border-right: 1px solid $cell-border; + } + + & > a { + &, &:active, &:visited { + color: inherit; + text-decoration: none; + } + } +} + +.rbc-row-content { + position: relative; + user-select: none; + -webkit-user-select: none; + z-index: 4; +} + +.rbc-row-content-scrollable { + display: flex; + flex-direction: column; + height: 100%; + + .rbc-row-content-scroll-container { + height: 100%; + overflow-y: scroll; + + /* Hide scrollbar for Chrome, Safari and Opera */ + &::-webkit-scrollbar { + display: none; + } + + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + } +} + +.rbc-today { + background-color: $today-highlight-bg; +} + +@import './toolbar'; +@import './event'; +@import './month'; +@import './agenda'; +@import './time-grid'; diff --git a/lib/sass/time-column.scss b/lib/sass/time-column.scss new file mode 100644 index 000000000..fce2d3eb4 --- /dev/null +++ b/lib/sass/time-column.scss @@ -0,0 +1,135 @@ +@import './variables'; + +.rbc-time-column { + display: flex; + flex-direction: column; + min-height: 100%; + + .rbc-timeslot-group { + flex: 1; + } +} + + +.rbc-timeslot-group { + border-bottom: 1px solid $cell-border; + min-height: 40px; + display: flex; + flex-flow: column nowrap; +} + +.rbc-time-gutter, +.rbc-header-gutter { + flex: none; +} + +.rbc-label { + padding: 0 5px; +} + +.rbc-day-slot { + position: relative; + + .rbc-events-container { + bottom: 0; + left: 0; + position: absolute; + right: 0; + margin-right: 10px; + top: 0; + + &.rbc-rtl { + left: 10px; + right: 0; + } + } + + .rbc-event { + border: 1px solid $event-border; + display: flex; + max-height: 100%; + min-height: 20px; + flex-flow: column wrap; + align-items: flex-start; + overflow: hidden; + position: absolute; + } + + .rbc-background-event { + @extend .rbc-event; + opacity: 0.75; + } + + .rbc-event-label { + flex: none; + padding-right: 5px; + width: auto; + } + + .rbc-event-content { + width: 100%; + flex: 1 1 0; + word-wrap: break-word; + line-height: 1; + height: 100%; + min-height: 1em; + } + + .rbc-time-slot { + border-top: 1px solid lighten($cell-border, 10%); + } +} + +.rbc-time-view-resources { + .rbc-time-gutter, + .rbc-time-header-gutter { + position: sticky; + left: 0; + background-color: white; + border-right: 1px solid $cell-border; + z-index: 10; + margin-right: -1px; + } + + .rbc-time-header { + overflow: hidden; + } + + .rbc-time-header-content { + min-width: auto; + flex: 1 0 0; + flex-basis: 0px; + } + + .rbc-time-header-cell-single-day { + display: none; + } + + .rbc-day-slot { + min-width: 140px; + } + + .rbc-header, + .rbc-day-bg, { + width: 140px; + // min-width: 0; + flex: 1 1 0; + flex-basis: 0 px; + } +} + +.rbc-time-header-content + .rbc-time-header-content { + margin-left: -1px; +} + +.rbc-time-slot { + flex: 1 0 0; + + &.rbc-now { + font-weight: bold; + } +} + +.rbc-day-header { + text-align: center; +} diff --git a/lib/sass/time-grid.scss b/lib/sass/time-grid.scss new file mode 100644 index 000000000..02c3d2253 --- /dev/null +++ b/lib/sass/time-grid.scss @@ -0,0 +1,142 @@ +@import './variables'; +@import './time-column'; + +.rbc-slot-selection { + z-index: 10; + position: absolute; + background-color: $time-selection-bg-color; + color: $time-selection-color; + font-size: 75%; + width: 100%; + padding: 3px; +} + +.rbc-slot-selecting { + cursor: move; +} + +.rbc-time-view { + display: flex; + flex-direction: column; + flex: 1; + width: 100%; + border: 1px solid $calendar-border; + min-height: 0; + + .rbc-time-gutter { + white-space: nowrap; + } + + .rbc-allday-cell { + box-sizing: content-box; + width: 100%; + height: 100%; + position: relative; + } + .rbc-allday-cell + .rbc-allday-cell { + border-left: 1px solid $cell-border; + } + + .rbc-allday-events { + position: relative; + z-index: 4; + } + + .rbc-row { + box-sizing: border-box; + min-height: 20px; + } +} + +.rbc-time-header { + display: flex; + flex: 0 0 auto; // should not shrink below height + flex-direction: row; + + &.rbc-overflowing { + border-right: 1px solid $cell-border; + } + + .rbc-rtl &.rbc-overflowing { + border-right-width: 0; + border-left: 1px solid $cell-border; + } + + > .rbc-row:first-child { + border-bottom: 1px solid $cell-border; + } + + > .rbc-row.rbc-row-resource { + border-bottom: 1px solid $cell-border; + } + + // .rbc-gutter-cell { + // flex: none; + // } + + // > .rbc-gutter-cell + * { + // width: 100%; + // } +} + +.rbc-time-header-cell-single-day { + display: none; +} + +.rbc-time-header-content { + flex: 1; + display: flex; + min-width: 0; + flex-direction: column; + border-left: 1px solid $cell-border; + + .rbc-rtl & { + border-left-width: 0; + border-right: 1px solid $cell-border; + } + + >.rbc-row.rbc-row-resource { + border-bottom: 1px solid $cell-border; + flex-shrink: 0; + } +} + +.rbc-time-content { + display: flex; + flex: 1 0 0%; + align-items: flex-start; + width: 100%; + border-top: 2px solid $calendar-border; + overflow-y: auto; + position: relative; + + > .rbc-time-gutter { + flex: none; + } + + > * + * > * { + border-left: 1px solid $cell-border; + } + + .rbc-rtl & > * + * > * { + border-left-width: 0; + border-right: 1px solid $cell-border; + } + + > .rbc-day-slot { + width: 100%; + user-select: none; + -webkit-user-select: none; + } +} + +.rbc-current-time-indicator { + position: absolute; + z-index: 3; + left: 0; + right: 0; + height: 1px; + + background-color: $current-time-color; + pointer-events: none; +} diff --git a/lib/sass/toolbar.scss b/lib/sass/toolbar.scss new file mode 100644 index 000000000..96521e5ad --- /dev/null +++ b/lib/sass/toolbar.scss @@ -0,0 +1,106 @@ +@import './variables'; + +$active-background: darken($btn-bg, 10%); +$active-border: darken($btn-border, 12%); + +.rbc-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + margin-bottom: 10px; + font-size: 16px; + + .rbc-toolbar-label { + flex-grow:1; + padding: 0 10px; + text-align: center; + } + + & button { + color: $btn-color; + display: inline-block; + margin: 0; + text-align: center; + vertical-align: middle; + background: none; + background-image: none; + border: 1px solid $btn-border; + padding: .375rem 1rem; + border-radius: 4px; + line-height: normal; + white-space: nowrap; + + &:active, + &.rbc-active { + background-image: none; + box-shadow: inset 0 3px 5px rgba(0,0,0,.125); + background-color: $active-background; + border-color: $active-border; + + &:hover, + &:focus { + color: $btn-color; + background-color: darken($btn-bg, 17%); + border-color: darken($btn-border, 25%); + } + } + + &:focus { + color: $btn-color; + background-color: $active-background; + border-color: $active-border; + } + + &:hover { + color: $btn-color; + background-color: $active-background; + border-color: $active-border; + } + } +} + +.rbc-btn-group { + display: inline-block; + white-space: nowrap; + + > button:first-child:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + > button:last-child:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + + .rbc-rtl & > button:first-child:not(:last-child) { + border-radius: 4px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + + .rbc-rtl & > button:last-child:not(:first-child) { + border-radius: 4px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + > button:not(:first-child):not(:last-child) { + border-radius: 0; + } + + button + button { + margin-left: -1px; + } + + .rbc-rtl & button + button { + margin-left: 0; + margin-right: -1px; + } + + & + &, + & + button { + margin-left: 10px; + } +} diff --git a/lib/sass/variables.scss b/lib/sass/variables.scss new file mode 100644 index 000000000..c5c92631f --- /dev/null +++ b/lib/sass/variables.scss @@ -0,0 +1,33 @@ + +$out-of-range-color: lighten(#333, 40%) !default; +$out-of-range-bg-color: lighten(#333, 70%) !default; + +$calendar-border: #DDD !default; +$cell-border: #DDD !default; + +$border-color: #CCC !default; + +$segment-width: percentage(1 / 7) !default; + +$time-selection-color: white !default; +$time-selection-bg-color: rgba(0,0,0, .50) !default; +$date-selection-bg-color: rgba(0,0,0, .10) !default; + + +$event-bg: #3174ad !default; +$event-border: darken(#3174ad, 10%) !default; +$event-outline: #3b99fc !default; +$event-color: #fff !default; +$event-border-radius: 5px !default; +$event-padding: 2px 5px !default; +$event-zindex: 4 !default; + +$btn-color: #373a3c !default; +$btn-bg: #fff !default; +$btn-border: #ccc !default; + +$current-time-color: #74ad31 !default; + +$rbc-css-prefix: rbc-i !default; + +$today-highlight-bg: #eaf6ff !default; diff --git a/lib/utils/DateSlotMetrics.js b/lib/utils/DateSlotMetrics.js new file mode 100644 index 000000000..c4ceb9c5c --- /dev/null +++ b/lib/utils/DateSlotMetrics.js @@ -0,0 +1,99 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.getSlotMetrics = getSlotMetrics + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +var _memoizeOne = _interopRequireDefault(require('memoize-one')) + +var dates = _interopRequireWildcard(require('./dates')) + +var _eventLevels2 = require('./eventLevels') + +var isSegmentInSlot = function isSegmentInSlot(seg, slot) { + return seg.left <= slot && seg.right >= slot +} + +var isEqual = function isEqual(a, b) { + return a[0].range === b[0].range && a[0].events === b[0].events +} + +function getSlotMetrics() { + return (0, _memoizeOne.default)(function(options) { + var range = options.range, + events = options.events, + maxRows = options.maxRows, + minRows = options.minRows, + accessors = options.accessors + + var _endOfRange = (0, _eventLevels2.endOfRange)(range), + first = _endOfRange.first, + last = _endOfRange.last + + var segments = events.map(function(evt) { + return (0, _eventLevels2.eventSegments)(evt, range, accessors) + }) + + var _eventLevels = (0, _eventLevels2.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((0, _extends2.default)({}, 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(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) +} diff --git a/lib/utils/DayEventLayout.js b/lib/utils/DayEventLayout.js new file mode 100644 index 000000000..31110e9fa --- /dev/null +++ b/lib/utils/DayEventLayout.js @@ -0,0 +1,40 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.getStyledEvents = getStyledEvents + +var _overlap = _interopRequireDefault(require('./layout-algorithms/overlap')) + +var _noOverlap = _interopRequireDefault( + require('./layout-algorithms/no-overlap') +) + +/*eslint no-unused-vars: "off"*/ +var DefaultAlgorithms = { + overlap: _overlap.default, + 'no-overlap': _noOverlap.default, +} + +function isFunction(a) { + return !!(a && a.constructor && a.call && a.apply) +} // + +function getStyledEvents(_ref) { + var events = _ref.events, + minimumStartDifference = _ref.minimumStartDifference, + slotMetrics = _ref.slotMetrics, + accessors = _ref.accessors, + dayLayoutAlgorithm = _ref.dayLayoutAlgorithm + var algorithm = dayLayoutAlgorithm + if (dayLayoutAlgorithm in DefaultAlgorithms) + algorithm = DefaultAlgorithms[dayLayoutAlgorithm] + + if (!isFunction(algorithm)) { + // invalid algorithm + return [] + } + + return algorithm.apply(this, arguments) +} diff --git a/lib/utils/Resources.js b/lib/utils/Resources.js new file mode 100644 index 000000000..9015a488f --- /dev/null +++ b/lib/utils/Resources.js @@ -0,0 +1,35 @@ +'use strict' + +exports.__esModule = true +exports.default = Resources +exports.NONE = void 0 +var NONE = {} +exports.NONE = NONE + +function Resources(resources, accessors) { + return { + map: function map(fn) { + if (!resources) return [fn([NONE, null], 0)] + return resources.map(function(resource, idx) { + return fn([accessors.resourceId(resource), resource], idx) + }) + }, + groupEvents: function groupEvents(events) { + var eventsByResource = new Map() + + if (!resources) { + // Return all events if resources are not provided + eventsByResource.set(NONE, events) + return eventsByResource + } + + events.forEach(function(event) { + var id = accessors.resource(event) || NONE + var resourceEvents = eventsByResource.get(id) || [] + resourceEvents.push(event) + eventsByResource.set(id, resourceEvents) + }) + return eventsByResource + }, + } +} diff --git a/lib/utils/TimeSlots.js b/lib/utils/TimeSlots.js new file mode 100644 index 000000000..7e2fd16c9 --- /dev/null +++ b/lib/utils/TimeSlots.js @@ -0,0 +1,157 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +exports.__esModule = true +exports.getSlotMetrics = getSlotMetrics + +var dates = _interopRequireWildcard(require('./dates')) + +var getDstOffset = function getDstOffset(start, end) { + return start.getTimezoneOffset() - end.getTimezoneOffset() +} + +var getKey = function getKey(min, max, step, slots) { + return ( + '' + + +dates.startOf(min, 'minutes') + + ('' + +dates.startOf(max, 'minutes')) + + (step + '-' + slots) + ) +} + +function getSlotMetrics(_ref) { + var start = _ref.min, + end = _ref.max, + step = _ref.step, + timeslots = _ref.timeslots + var key = getKey(start, end, step, timeslots) // 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 + + var daystart = dates.startOf(start, 'day') + var daystartdstoffset = getDstOffset(daystart, start) + var totalMin = + 1 + dates.diff(start, end, 'minutes') + getDstOffset(start, end) + var minutesFromMidnight = + dates.diff(daystart, start, 'minutes') + daystartdstoffset + var numGroups = Math.ceil(totalMin / (step * timeslots)) + var numSlots = numGroups * timeslots + var groups = new Array(numGroups) + var slots = new Array(numSlots) // Each slot date is created from "zero", instead of adding `step` to + // the previous one, in order to avoid DST oddities + + for (var grp = 0; grp < numGroups; grp++) { + groups[grp] = new Array(timeslots) + + for (var slot = 0; slot < timeslots; slot++) { + var slotIdx = grp * timeslots + slot + var minFromStart = slotIdx * step // A date with total minutes calculated from the start of the day + + slots[slotIdx] = groups[grp][slot] = new Date( + start.getFullYear(), + start.getMonth(), + start.getDate(), + 0, + minutesFromMidnight + minFromStart, + 0, + 0 + ) + } + } // Necessary to be able to select up until the last timeslot in a day + + var lastSlotMinFromStart = slots.length * step + slots.push( + new Date( + start.getFullYear(), + start.getMonth(), + start.getDate(), + 0, + minutesFromMidnight + lastSlotMinFromStart, + 0, + 0 + ) + ) + + function positionFromDate(date) { + var diff = dates.diff(start, date, 'minutes') + getDstOffset(start, date) + return Math.min(diff, totalMin) + } + + return { + groups: groups, + update: function update(args) { + if (getKey(args) !== key) return getSlotMetrics(args) + return this + }, + dateIsInGroup: function dateIsInGroup(date, groupIndex) { + var nextGroup = groups[groupIndex + 1] + return dates.inRange( + date, + groups[groupIndex][0], + nextGroup ? nextGroup[0] : end, + 'minutes' + ) + }, + nextSlot: function nextSlot(slot) { + var next = slots[Math.min(slots.indexOf(slot) + 1, slots.length - 1)] // in the case of the last slot we won't a long enough range so manually get it + + if (next === slot) next = dates.add(slot, step, 'minutes') + return next + }, + closestSlotToPosition: function closestSlotToPosition(percent) { + var slot = Math.min( + slots.length - 1, + Math.max(0, Math.floor(percent * numSlots)) + ) + return slots[slot] + }, + closestSlotFromPoint: function closestSlotFromPoint(point, boundaryRect) { + var range = Math.abs(boundaryRect.top - boundaryRect.bottom) + return this.closestSlotToPosition((point.y - boundaryRect.top) / range) + }, + closestSlotFromDate: function closestSlotFromDate(date, offset) { + if (offset === void 0) { + offset = 0 + } + + if (dates.lt(date, start, 'minutes')) return slots[0] + var diffMins = dates.diff(start, date, 'minutes') + return slots[(diffMins - (diffMins % step)) / step + offset] + }, + startsBeforeDay: function startsBeforeDay(date) { + return dates.lt(date, start, 'day') + }, + startsAfterDay: function startsAfterDay(date) { + return dates.gt(date, end, 'day') + }, + startsBefore: function startsBefore(date) { + return dates.lt(dates.merge(start, date), start, 'minutes') + }, + startsAfter: function startsAfter(date) { + return dates.gt(dates.merge(end, date), end, 'minutes') + }, + getRange: function getRange(rangeStart, rangeEnd, ignoreMin, ignoreMax) { + if (!ignoreMin) rangeStart = dates.min(end, dates.max(start, rangeStart)) + if (!ignoreMax) rangeEnd = dates.min(end, dates.max(start, rangeEnd)) + var rangeStartMin = positionFromDate(rangeStart) + var rangeEndMin = positionFromDate(rangeEnd) + var top = + rangeEndMin > step * numSlots && !dates.eq(end, rangeEnd) + ? ((rangeStartMin - step) / (step * numSlots)) * 100 + : (rangeStartMin / (step * numSlots)) * 100 + return { + top: top, + height: (rangeEndMin / (step * numSlots)) * 100 - top, + start: positionFromDate(rangeStart), + startDate: rangeStart, + end: positionFromDate(rangeEnd), + endDate: rangeEnd, + } + }, + getCurrentTimePosition: function getCurrentTimePosition(rangeStart) { + var rangeStartMin = positionFromDate(rangeStart) + var top = (rangeStartMin / (step * numSlots)) * 100 + return top + }, + } +} diff --git a/lib/utils/accessors.js b/lib/utils/accessors.js new file mode 100644 index 000000000..174b3b263 --- /dev/null +++ b/lib/utils/accessors.js @@ -0,0 +1,33 @@ +'use strict' + +exports.__esModule = true +exports.accessor = accessor +exports.wrapAccessor = void 0 + +/** + * Retrieve via an accessor-like property + * + * accessor(obj, 'name') // => retrieves obj['name'] + * accessor(data, func) // => retrieves func(data) + * ... otherwise null + */ +function accessor(data, field) { + var value = null + if (typeof field === 'function') value = field(data) + else if ( + typeof field === 'string' && + typeof data === 'object' && + data != null && + field in data + ) + value = data[field] + return value +} + +var wrapAccessor = function wrapAccessor(acc) { + return function(data) { + return accessor(data, acc) + } +} + +exports.wrapAccessor = wrapAccessor diff --git a/lib/utils/constants.js b/lib/utils/constants.js new file mode 100644 index 000000000..788d67269 --- /dev/null +++ b/lib/utils/constants.js @@ -0,0 +1,19 @@ +'use strict' + +exports.__esModule = true +exports.views = exports.navigate = void 0 +var navigate = { + PREVIOUS: 'PREV', + NEXT: 'NEXT', + TODAY: 'TODAY', + DATE: 'DATE', +} +exports.navigate = navigate +var views = { + MONTH: 'month', + WEEK: 'week', + WORK_WEEK: 'work_week', + DAY: 'day', + AGENDA: 'agenda', +} +exports.views = views diff --git a/lib/utils/dates.js b/lib/utils/dates.js new file mode 100644 index 000000000..cced6b90e --- /dev/null +++ b/lib/utils/dates.js @@ -0,0 +1,193 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +exports.__esModule = true +exports.monthsInYear = monthsInYear +exports.firstVisibleDay = firstVisibleDay +exports.lastVisibleDay = lastVisibleDay +exports.visibleDays = visibleDays +exports.ceil = ceil +exports.range = range +exports.merge = merge +exports.eqTime = eqTime +exports.isJustDate = isJustDate +exports.duration = duration +exports.diff = diff +exports.total = total +exports.week = week +exports.today = today +exports.yesterday = yesterday +exports.tomorrow = tomorrow +exports.max = exports.min = exports.inRange = exports.lt = exports.lte = exports.gt = exports.gte = exports.eq = exports.add = exports.endOf = exports.startOf = exports.month = exports.hours = exports.minutes = exports.seconds = exports.milliseconds = void 0 + +var dates = _interopRequireWildcard(require('date-arithmetic')) + +exports.milliseconds = dates.milliseconds +exports.seconds = dates.seconds +exports.minutes = dates.minutes +exports.hours = dates.hours +exports.month = dates.month +exports.startOf = dates.startOf +exports.endOf = dates.endOf +exports.add = dates.add +exports.eq = dates.eq +exports.gte = dates.gte +exports.gt = dates.gt +exports.lte = dates.lte +exports.lt = dates.lt +exports.inRange = dates.inRange +exports.min = dates.min +exports.max = dates.max + +/* eslint no-fallthrough: off */ +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] + +function monthsInYear(year) { + var date = new Date(year, 0, 1) + return MONTHS.map(function(i) { + return dates.month(date, i) + }) +} + +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, 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 +} + +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 eqTime(dateA, dateB) { + return ( + dates.hours(dateA) === dates.hours(dateB) && + dates.minutes(dateA) === dates.minutes(dateB) && + dates.seconds(dateA) === dates.seconds(dateB) + ) +} + +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( + dates[unit](start, undefined, firstOfWeek) - + 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] + ) + ) +} + +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 +} + +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) +} + +function today() { + return dates.startOf(new Date(), 'day') +} + +function yesterday() { + return dates.add(dates.startOf(new Date(), 'day'), -1, 'day') +} + +function tomorrow() { + return dates.add(dates.startOf(new Date(), 'day'), 1, 'day') +} diff --git a/lib/utils/eventLevels.js b/lib/utils/eventLevels.js new file mode 100644 index 000000000..0ba9df1b7 --- /dev/null +++ b/lib/utils/eventLevels.js @@ -0,0 +1,126 @@ +'use strict' + +var _interopRequireWildcard = require('@babel/runtime/helpers/interopRequireWildcard') + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.endOfRange = endOfRange +exports.eventSegments = eventSegments +exports.eventLevels = eventLevels +exports.inRange = inRange +exports.segsOverlap = segsOverlap +exports.sortEvents = sortEvents + +var _findIndex = _interopRequireDefault(require('lodash/findIndex')) + +var dates = _interopRequireWildcard(require('./dates')) + +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 = (0, _findIndex.default)(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 +} diff --git a/lib/utils/helpers.js b/lib/utils/helpers.js new file mode 100644 index 000000000..36a3c5304 --- /dev/null +++ b/lib/utils/helpers.js @@ -0,0 +1,31 @@ +'use strict' + +exports.__esModule = true +exports.notify = notify +exports.instanceId = instanceId +exports.isFirstFocusedRender = isFirstFocusedRender +var idCount = 0 + +function uniqueId(prefix) { + return '' + ((prefix == null ? '' : prefix) + ++idCount) +} + +function notify(handler, args) { + handler && handler.apply(null, [].concat(args)) +} + +function instanceId(component, suffix) { + if (suffix === void 0) { + suffix = '' + } + + component.__id || (component.__id = uniqueId('rw_')) + return (component.props.id || component.__id) + suffix +} + +function isFirstFocusedRender(component) { + return ( + component._firstFocus || + (component.state.focused && (component._firstFocus = true)) + ) +} diff --git a/lib/utils/layout-algorithms/no-overlap.js b/lib/utils/layout-algorithms/no-overlap.js new file mode 100644 index 000000000..8df1f6419 --- /dev/null +++ b/lib/utils/layout-algorithms/no-overlap.js @@ -0,0 +1,119 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = _default + +var _overlap = _interopRequireDefault(require('./overlap')) + +function getMaxIdxDFS(node, maxIdx, visited) { + for (var i = 0; i < node.friends.length; ++i) { + if (visited.indexOf(node.friends[i]) > -1) continue + maxIdx = maxIdx > node.friends[i].idx ? maxIdx : node.friends[i].idx // TODO : trace it by not object but kinda index or something for performance + + visited.push(node.friends[i]) + var newIdx = getMaxIdxDFS(node.friends[i], maxIdx, visited) + maxIdx = maxIdx > newIdx ? maxIdx : newIdx + } + + return maxIdx +} + +function _default(_ref) { + var events = _ref.events, + minimumStartDifference = _ref.minimumStartDifference, + slotMetrics = _ref.slotMetrics, + accessors = _ref.accessors + var styledEvents = (0, _overlap.default)({ + events: events, + minimumStartDifference: minimumStartDifference, + slotMetrics: slotMetrics, + accessors: accessors, + }) + styledEvents.sort(function(a, b) { + a = a.style + b = b.style + if (a.top !== b.top) return a.top > b.top ? 1 : -1 + else return a.top + a.height < b.top + b.height ? 1 : -1 + }) + + for (var i = 0; i < styledEvents.length; ++i) { + styledEvents[i].friends = [] + delete styledEvents[i].style.left + delete styledEvents[i].style.left + delete styledEvents[i].idx + delete styledEvents[i].size + } + + for (var _i = 0; _i < styledEvents.length - 1; ++_i) { + var se1 = styledEvents[_i] + var y1 = se1.style.top + var y2 = se1.style.top + se1.style.height + + for (var j = _i + 1; j < styledEvents.length; ++j) { + var se2 = styledEvents[j] + var y3 = se2.style.top + var y4 = se2.style.top + se2.style.height // be friends when overlapped + + if ((y3 <= y1 && y1 < y4) || (y1 <= y3 && y3 < y2)) { + // TODO : hashmap would be effective for performance + se1.friends.push(se2) + se2.friends.push(se1) + } + } + } + + for (var _i2 = 0; _i2 < styledEvents.length; ++_i2) { + var se = styledEvents[_i2] + var bitmap = [] + + for (var _j = 0; _j < 100; ++_j) { + bitmap.push(1) + } // 1 means available + + for (var _j2 = 0; _j2 < se.friends.length; ++_j2) { + if (se.friends[_j2].idx !== undefined) bitmap[se.friends[_j2].idx] = 0 + } // 0 means reserved + + se.idx = bitmap.indexOf(1) + } + + for (var _i3 = 0; _i3 < styledEvents.length; ++_i3) { + var size = 0 + if (styledEvents[_i3].size) continue + var allFriends = [] + var maxIdx = getMaxIdxDFS(styledEvents[_i3], 0, allFriends) + size = 100 / (maxIdx + 1) + styledEvents[_i3].size = size + + for (var _j3 = 0; _j3 < allFriends.length; ++_j3) { + allFriends[_j3].size = size + } + } + + for (var _i4 = 0; _i4 < styledEvents.length; ++_i4) { + var e = styledEvents[_i4] + e.style.left = e.idx * e.size // stretch to maximum + + var _maxIdx = 0 + + for (var _j4 = 0; _j4 < e.friends.length; ++_j4) { + var idx = e.friends[_j4] + _maxIdx = _maxIdx > idx ? _maxIdx : idx + } + + if (_maxIdx <= e.idx) e.size = 100 - e.idx * e.size // padding between events + // for this feature, `width` is not percentage based unit anymore + // it will be used with calc() + + var padding = e.idx === 0 ? 0 : 3 + e.style.width = 'calc(' + e.size + '% - ' + padding + 'px)' + e.style.height = 'calc(' + e.style.height + '% - 2px)' + e.style.xOffset = 'calc(' + e.style.left + '% + ' + padding + 'px)' + } + + return styledEvents +} + +module.exports = exports['default'] diff --git a/lib/utils/layout-algorithms/overlap.js b/lib/utils/layout-algorithms/overlap.js new file mode 100644 index 000000000..9531dda37 --- /dev/null +++ b/lib/utils/layout-algorithms/overlap.js @@ -0,0 +1,234 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = getStyledEvents + +var _createClass2 = _interopRequireDefault( + require('@babel/runtime/helpers/createClass') +) + +var _sortBy = _interopRequireDefault(require('lodash/sortBy')) + +var Event = + /*#__PURE__*/ + (function() { + function Event(data, _ref) { + var accessors = _ref.accessors, + slotMetrics = _ref.slotMetrics + + var _slotMetrics$getRange = slotMetrics.getRange( + accessors.start(data), + accessors.end(data) + ), + start = _slotMetrics$getRange.start, + startDate = _slotMetrics$getRange.startDate, + end = _slotMetrics$getRange.end, + endDate = _slotMetrics$getRange.endDate, + top = _slotMetrics$getRange.top, + height = _slotMetrics$getRange.height + + this.start = start + this.end = end + this.startMs = +startDate + this.endMs = +endDate + this.top = top + this.height = height + this.data = data + } + /** + * The event's width without any overlap. + */ + + ;(0, _createClass2.default)(Event, [ + { + key: '_width', + get: function get() { + // The container event's width is determined by the maximum number of + // events in any of its rows. + if (this.rows) { + var columns = + this.rows.reduce( + function(max, row) { + return Math.max(max, row.leaves.length + 1) + }, // add itself + 0 + ) + 1 // add the container + + return 100 / columns + } + + var availableWidth = 100 - this.container._width // The row event's width is the space left by the container, divided + // among itself and its leaves. + + if (this.leaves) { + return availableWidth / (this.leaves.length + 1) + } // The leaf event's width is determined by its row's width + + return this.row._width + }, + /** + * The event's calculated width, possibly with extra width added for + * overlapping effect. + */ + }, + { + key: 'width', + get: function get() { + var noOverlap = this._width + var overlap = Math.min(100, this._width * 1.7) // Containers can always grow. + + if (this.rows) { + return overlap + } // Rows can grow if they have leaves. + + if (this.leaves) { + return this.leaves.length > 0 ? overlap : noOverlap + } // Leaves can grow unless they're the last item in a row. + + var leaves = this.row.leaves + var index = leaves.indexOf(this) + return index === leaves.length - 1 ? noOverlap : overlap + }, + }, + { + key: 'xOffset', + get: function get() { + // Containers have no offset. + if (this.rows) return 0 // Rows always start where their container ends. + + if (this.leaves) return this.container._width // Leaves are spread out evenly on the space left by its row. + + var _this$row = this.row, + leaves = _this$row.leaves, + xOffset = _this$row.xOffset, + _width = _this$row._width + var index = leaves.indexOf(this) + 1 + return xOffset + index * _width + }, + }, + ]) + return Event + })() +/** + * Return true if event a and b is considered to be on the same row. + */ + +function onSameRow(a, b, minimumStartDifference) { + return ( + // Occupies the same start slot. + Math.abs(b.start - a.start) < minimumStartDifference || // A's start slot overlaps with b's end slot. + (b.start > a.start && b.start < a.end) + ) +} + +function sortByRender(events) { + var sortedByTime = (0, _sortBy.default)(events, [ + 'startMs', + function(e) { + return -e.endMs + }, + ]) + var sorted = [] + + while (sortedByTime.length > 0) { + var event = sortedByTime.shift() + sorted.push(event) + + for (var i = 0; i < sortedByTime.length; i++) { + var test = sortedByTime[i] // Still inside this event, look for next. + + if (event.endMs > test.startMs) continue // We've found the first event of the next event group. + // If that event is not right next to our current event, we have to + // move it here. + + if (i > 0) { + var _event = sortedByTime.splice(i, 1)[0] + sorted.push(_event) + } // We've already found the next event group, so stop looking. + + break + } + } + + return sorted +} + +function getStyledEvents(_ref2) { + var events = _ref2.events, + minimumStartDifference = _ref2.minimumStartDifference, + slotMetrics = _ref2.slotMetrics, + accessors = _ref2.accessors + // Create proxy events and order them so that we don't have + // to fiddle with z-indexes. + var proxies = events.map(function(event) { + return new Event(event, { + slotMetrics: slotMetrics, + accessors: accessors, + }) + }) + var eventsInRenderOrder = sortByRender(proxies) // Group overlapping events, while keeping order. + // Every event is always one of: container, row or leaf. + // Containers can contain rows, and rows can contain leaves. + + var containerEvents = [] + + var _loop = function _loop(i) { + var event = eventsInRenderOrder[i] // Check if this event can go into a container event. + + var container = containerEvents.find(function(c) { + return ( + c.end > event.start || + Math.abs(event.start - c.start) < minimumStartDifference + ) + }) // Couldn't find a container — that means this event is a container. + + if (!container) { + event.rows = [] + containerEvents.push(event) + return 'continue' + } // Found a container for the event. + + event.container = container // Check if the event can be placed in an existing row. + // Start looking from behind. + + var row = null + + for (var j = container.rows.length - 1; !row && j >= 0; j--) { + if (onSameRow(container.rows[j], event, minimumStartDifference)) { + row = container.rows[j] + } + } + + if (row) { + // Found a row, so add it. + row.leaves.push(event) + event.row = row + } else { + // Couldn't find a row – that means this event is a row. + event.leaves = [] + container.rows.push(event) + } + } + + for (var i = 0; i < eventsInRenderOrder.length; i++) { + var _ret = _loop(i) + + if (_ret === 'continue') continue + } // Return the original events, along with their styles. + + return eventsInRenderOrder.map(function(event) { + return { + event: event.data, + style: { + top: event.top, + height: event.height, + width: event.width, + xOffset: Math.max(0, event.xOffset), + }, + } + }) +} + +module.exports = exports['default'] diff --git a/lib/utils/messages.js b/lib/utils/messages.js new file mode 100644 index 000000000..cbd3e270b --- /dev/null +++ b/lib/utils/messages.js @@ -0,0 +1,37 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = messages + +var _extends2 = _interopRequireDefault( + require('@babel/runtime/helpers/extends') +) + +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 (0, _extends2.default)({}, defaultMessages, msgs) +} + +module.exports = exports['default'] diff --git a/lib/utils/move.js b/lib/utils/move.js new file mode 100644 index 000000000..b00286b5f --- /dev/null +++ b/lib/utils/move.js @@ -0,0 +1,52 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = moveDate + +var _objectWithoutPropertiesLoose2 = _interopRequireDefault( + require('@babel/runtime/helpers/objectWithoutPropertiesLoose') +) + +var _invariant = _interopRequireDefault(require('invariant')) + +var _constants = require('./constants') + +var _Views = _interopRequireDefault(require('../Views')) + +function moveDate(View, _ref) { + var action = _ref.action, + date = _ref.date, + today = _ref.today, + props = (0, _objectWithoutPropertiesLoose2.default)(_ref, [ + 'action', + 'date', + 'today', + ]) + View = typeof View === 'string' ? _Views.default[View] : View + + switch (action) { + case _constants.navigate.TODAY: + date = today || new Date() + break + + case _constants.navigate.DATE: + break + + default: + !(View && typeof View.navigate === 'function') + ? process.env.NODE_ENV !== 'production' + ? (0, _invariant.default)( + false, + 'Calendar View components must implement a static `.navigate(date, action)` method.s' + ) + : invariant(false) + : void 0 + date = View.navigate(date, action, props) + } + + return date +} + +module.exports = exports['default'] diff --git a/lib/utils/propTypes.js b/lib/utils/propTypes.js new file mode 100644 index 000000000..14d66a062 --- /dev/null +++ b/lib/utils/propTypes.js @@ -0,0 +1,79 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.DayLayoutAlgorithmPropType = exports.views = exports.dateRangeFormat = exports.dateFormat = exports.accessor = void 0 + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _constants = require('./constants') + +var viewNames = Object.keys(_constants.views).map(function(k) { + return _constants.views[k] +}) + +var accessor = _propTypes.default.oneOfType([ + _propTypes.default.string, + _propTypes.default.func, +]) + +exports.accessor = accessor +var dateFormat = _propTypes.default.any +exports.dateFormat = dateFormat +var dateRangeFormat = _propTypes.default.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, + * }} + * ``` + */ + +exports.dateRangeFormat = dateRangeFormat + +var views = _propTypes.default.oneOfType([ + _propTypes.default.arrayOf(_propTypes.default.oneOf(viewNames)), + _propTypes.default.objectOf(function(prop, key) { + var isBuiltinView = + viewNames.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.default.elementType.apply( + _propTypes.default, + [prop, key].concat(args) + ) + } + }), +]) + +exports.views = views + +var DayLayoutAlgorithmPropType = _propTypes.default.oneOfType([ + _propTypes.default.oneOf(['overlap', 'no-overlap']), + _propTypes.default.func, +]) + +exports.DayLayoutAlgorithmPropType = DayLayoutAlgorithmPropType diff --git a/lib/utils/selection.js b/lib/utils/selection.js new file mode 100644 index 000000000..e2900eb5d --- /dev/null +++ b/lib/utils/selection.js @@ -0,0 +1,88 @@ +'use strict' + +exports.__esModule = true +exports.isSelected = isSelected +exports.slotWidth = slotWidth +exports.getSlotAtX = getSlotAtX +exports.pointInBox = pointInBox +exports.dateCellSelection = dateCellSelection + +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, + } +} From 1ed412fbb720a2553e67ac34d5963d3002958769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 3 Mar 2021 17:29:43 +0700 Subject: [PATCH 08/60] Configure typings --- package.json | 1 + typings.d.ts | 535 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 536 insertions(+) create mode 100644 typings.d.ts diff --git a/package.json b/package.json index 6f27a2891..444f5ff67 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "README.md", "CHANGELOG.md" ], + "types": "typings.d.ts", "keywords": [ "scheduler", "react-component", diff --git a/typings.d.ts b/typings.d.ts new file mode 100644 index 000000000..a56dee1c9 --- /dev/null +++ b/typings.d.ts @@ -0,0 +1,535 @@ +// Type definitions for react-big-calendar 0.30 +// Project: https://github.com/jquense/react-big-calendar +// Definitions by: Piotr Witek +// Austin Turner +// Krzysztof Bezrąk +// Sebastian Silbermann +// Paul Potsides +// janb87 +// Daniel Thorne +// Panagiotis Rikarnto Siavelis +// Lucas Silva Souza +// Siarhey Belofost +// Mark Nelissen +// Eric Kenney +// Paito Anderson +// Jan Michalak +// Tom Price +// Daniele Carrucciu +// Chris Vandenberg +// Chris Frewin +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 +import { Validator } from 'prop-types' + +type Omit = Pick> + +export type DayPropGetter = ( + date: Date, + resourceId?: number | string +) => React.HTMLAttributes +export type EventPropGetter = ( + event: T, + start: stringOrDate, + end: stringOrDate, + isSelected: boolean +) => React.HTMLAttributes +export type SlotPropGetter = ( + date: Date, + resourceId?: number | string +) => React.HTMLAttributes +export type SlotGroupPropGetter = () => React.HTMLAttributes + +export type stringOrDate = string | Date + +export type ViewKey = 'MONTH' | 'WEEK' | 'WORK_WEEK' | 'DAY' | 'AGENDA' +export type View = 'month' | 'week' | 'work_week' | 'day' | 'agenda' +export type ViewProps< + TEvent extends object = Event, + TResource extends object = object +> = Omit< + CalendarProps, + | 'elementProps' + | 'className' + | 'style' + | 'view' + | 'toolbar' + | 'components' + | 'formats' + | 'messages' + | 'culture' +> & { + date: stringOrDate // date has always a value, in contrast to optional date in CalendarProps + + // props assigned from Calendar's this.state.context, see there if you want to improve the type defs: + accessors: any + components: any + getters: any + localizer: any + + // props assigned from Calendar instance, see there if you want to improve the type defs: + getDrilldownView: any // = this.getDrilldownView + onNavigate: any // = this.handleNavigate + onDrillDown: any // = this.handleDrillDown + onSelectEvent: any // = this.handleSelectEvent + onDoubleClickEvent: any // = this.handleDoubleClickEvent + onSelectSlot: any // = this.handleSelectSlot +} +export type ViewsProps< + TEvent extends object = Event, + TResource extends object = object +> = + | View[] + | { + work_week?: boolean | React.ComponentType & ViewStatic + day?: boolean | React.ComponentType & ViewStatic + agenda?: boolean | React.ComponentType & ViewStatic + month?: boolean | React.ComponentType & ViewStatic + week?: boolean | React.ComponentType & ViewStatic + } +export type DayLayoutFunction = (_: { + events: TEvent[] + minimumStartDifference: number + slotMetrics: any + accessors: any +}) => Array<{ event: TEvent; style: React.CSSProperties }> +export type DayLayoutAlgorithm = 'overlap' | 'no-overlap' +export type NavigateAction = 'PREV' | 'NEXT' | 'TODAY' | 'DATE' +export interface Event { + allDay?: boolean + title?: string + start?: Date + end?: Date + resource?: any +} +export interface DateRange { + start: Date + end: Date +} + +export type DateFormatFunction = ( + date: Date, + culture?: Culture, + localizer?: DateLocalizer +) => string +export type DateRangeFormatFunction = ( + range: DateRange, + culture?: Culture, + localizer?: DateLocalizer +) => string +export type DateFormat = string | DateFormatFunction + +export interface Formats { + /** + * Format for the day of the month heading in the Month view. + * e.g. "01", "02", "03", etc + */ + dateFormat?: DateFormat + + /** + * A day of the week format for Week and Day headings, + * e.g. "Wed 01/04" + * + */ + dayFormat?: DateFormat + + /** + * Week day name format for the Month week day headings, + * e.g: "Sun", "Mon", "Tue", etc + * + */ + weekdayFormat?: DateFormat + + /** + * The timestamp cell formats in Week and Time views, e.g. "4:00 AM" + */ + timeGutterFormat?: DateFormat + + /** + * Toolbar header format for the Month view, e.g "2015 April" + * + */ + monthHeaderFormat?: DateFormat + + /** + * Toolbar header format for the Week views, e.g. "Mar 29 - Apr 04" + */ + dayRangeHeaderFormat?: DateRangeFormatFunction + + /** + * Toolbar header format for the Day view, e.g. "Wednesday Apr 01" + */ + dayHeaderFormat?: DateFormat + + /** + * Toolbar header format for the Agenda view, e.g. "4/1/2015 — 5/1/2015" + */ + agendaHeaderFormat?: DateRangeFormatFunction + + /** + * A time range format for selecting time slots, e.g "8:00am — 2:00pm" + */ + selectRangeFormat?: DateRangeFormatFunction + + agendaDateFormat?: DateFormat + agendaTimeFormat?: DateFormat + agendaTimeRangeFormat?: DateRangeFormatFunction + + /** + * Time range displayed on events. + */ + eventTimeRangeFormat?: DateRangeFormatFunction + + /** + * An optional event time range for events that continue onto another day + */ + eventTimeRangeStartFormat?: DateRangeFormatFunction + + /** + * An optional event time range for events that continue from another day + */ + eventTimeRangeEndFormat?: DateRangeFormatFunction +} + +export interface HeaderProps { + date: Date + label: string + localizer: DateLocalizer +} + +export interface ResourceHeaderProps { + label: React.ReactNode + index: number + resource: object +} + +export interface Components< + TEvent extends object = Event, + TResource extends object = object +> { + event?: React.ComponentType> + eventWrapper?: React.ComponentType> + eventContainerWrapper?: React.ComponentType + dateCellWrapper?: React.ComponentType + timeSlotWrapper?: React.ComponentType + timeGutterHeader?: React.ComponentType + timeGutterWrapper?: React.ComponentType + toolbar?: React.ComponentType> + agenda?: { + date?: React.ComponentType + time?: React.ComponentType + event?: React.ComponentType> + } + day?: { + header?: React.ComponentType + event?: React.ComponentType> + } + week?: { + header?: React.ComponentType + event?: React.ComponentType> + } + month?: { + header?: React.ComponentType + dateHeader?: React.ComponentType + dateFooter?: React.ComponentType + event?: React.ComponentType> + } + /** + * component used as a header for each column in the TimeGridHeader + */ + header?: React.ComponentType + resourceHeader?: React.ComponentType +} + +export interface ToolbarProps< + TEvent extends object = Event, + TResource extends object = object +> { + date: Date + view: View + views: ViewsProps + label: string + localizer: { messages: Messages } + onNavigate: (navigate: NavigateAction, date?: Date) => void + onView: (view: View) => void + children?: React.ReactNode +} + +export interface EventProps { + event: TEvent + title: string +} + +export interface EventWrapperProps { + // https://github.com/intljusticemission/react-big-calendar/blob/27a2656b40ac8729634d24376dff8ea781a66d50/src/TimeGridEvent.js#L28 + style?: React.CSSProperties & { xOffset: number } + className: string + event: TEvent + isRtl: boolean + getters: { + eventProp?: EventPropGetter + slotProp?: SlotPropGetter + dayProp?: DayPropGetter + } + onClick: (e: React.MouseEvent) => void + onDoubleClick: (e: React.MouseEvent) => void + accessors: { + title?: (event: TEvent) => string + tooltip?: (event: TEvent) => string + end?: (event: TEvent) => Date + start?: (event: TEvent) => Date + } + selected: boolean + label: string + continuesEarlier: boolean + continuesLater: boolean +} + +export interface Messages { + date?: string + time?: string + event?: string + allDay?: string + week?: string + work_week?: string + day?: string + month?: string + previous?: string + next?: string + yesterday?: string + tomorrow?: string + today?: string + agenda?: string + showMore?: (count: number) => string + noEventsInRange?: string +} + +export type Culture = string +export type FormatInput = number | string | Date + +export interface DateLocalizerSpec { + firstOfWeek: (culture: Culture) => number + format: (value: FormatInput, format: string, culture: Culture) => string + formats: Formats + propType?: Validator +} + +export class DateLocalizer { + formats: Formats + propType: Validator + startOfWeek: (culture: Culture) => number + + constructor(spec: DateLocalizerSpec) + + format(value: FormatInput, format: string, culture: Culture): string +} + +export interface CalendarProps< + TEvent extends object = Event, + TResource extends object = object +> extends React.Props> { + localizer: DateLocalizer + + date?: stringOrDate + getNow?: () => Date + view?: View + events?: TEvent[] + handleDragStart?: (event: TEvent) => void + onNavigate?: (newDate: Date, view: View, action: NavigateAction) => void + onView?: (view: View) => void + onDrillDown?: (date: Date, view: View) => void + onSelectSlot?: (slotInfo: { + start: stringOrDate + end: stringOrDate + slots: Date[] | string[] + action: 'select' | 'click' | 'doubleClick' + }) => void + onDoubleClickEvent?: ( + event: TEvent, + e: React.SyntheticEvent + ) => void + onSelectEvent?: (event: TEvent, e: React.SyntheticEvent) => void + onKeyPressEvent?: ( + event: TEvent, + e: React.SyntheticEvent + ) => void + onSelecting?: (range: { + start: stringOrDate + end: stringOrDate + }) => boolean | undefined | null + onRangeChange?: ( + range: Date[] | { start: stringOrDate; end: stringOrDate }, + view: View | undefined + ) => void + showAllEvents?: boolean + selected?: any + views?: ViewsProps + drilldownView?: View | null + getDrilldownView?: + | (( + targetDate: Date, + currentViewName: View, + configuredViewNames: View[] + ) => void) + | null + length?: number + toolbar?: boolean + popup?: boolean + popupOffset?: number | { x: number; y: number } + selectable?: boolean | 'ignoreEvents' + longPressThreshold?: number + step?: number + timeslots?: number + rtl?: boolean + eventPropGetter?: EventPropGetter + slotPropGetter?: SlotPropGetter + slotGroupPropGetter?: SlotGroupPropGetter + dayPropGetter?: DayPropGetter + showMultiDayTimes?: boolean + min?: stringOrDate + max?: stringOrDate + scrollToTime?: Date + culture?: string + formats?: Formats + components?: Components + messages?: Messages + dayLayoutAlgorithm?: DayLayoutAlgorithm | DayLayoutFunction + titleAccessor?: keyof TEvent | ((event: TEvent) => string) + tooltipAccessor?: keyof TEvent | ((event: TEvent) => string) + allDayAccessor?: keyof TEvent | ((event: TEvent) => boolean) + startAccessor?: keyof TEvent | ((event: TEvent) => Date) + endAccessor?: keyof TEvent | ((event: TEvent) => Date) + resourceAccessor?: keyof TEvent | ((event: TEvent) => any) + resources?: TResource[] + resourceIdAccessor?: keyof TResource | ((resource: TResource) => any) + resourceTitleAccessor?: keyof TResource | ((resource: TResource) => any) + defaultView?: View + defaultDate?: Date + className?: string + elementProps?: React.HTMLAttributes + style?: React.CSSProperties + onShowMore?: (events: TEvent[], date: Date) => void +} + +export interface TitleOptions { + formats: DateFormat[] + culture?: string + [propName: string]: any +} + +export interface ViewStatic { + navigate(date: Date, action: NavigateAction, props: any): Date + title(date: Date, options: TitleOptions): string +} + +export interface MoveOptions { + action: NavigateAction + date: Date + today: Date +} + +export class Calendar< + TEvent extends object = Event, + TResource extends object = object +> extends React.Component> {} + +export interface components { + dateCellWrapper: React.ComponentType + eventWrapper: React.ComponentType +} +export function globalizeLocalizer(globalizeInstance: object): DateLocalizer +export function momentLocalizer(momentInstance: object): DateLocalizer +export function dateFnsLocalizer(config: object): DateLocalizer +export interface Navigate { + PREVIOUS: 'PREV' + NEXT: 'NEXT' + TODAY: 'TODAY' + DATE: 'DATE' +} +export interface Views { + MONTH: 'month' + WEEK: 'week' + WORK_WEEK: 'work_week' + DAY: 'day' + AGENDA: 'agenda' +} +export function move(View: ViewStatic | ViewKey, options: MoveOptions): Date + +export interface TimeGridProps< + TEvent extends object = Event, + TResource extends object = object +> { + eventOffset: number + events?: TEvent[] + resources?: TResource[] + step?: number + timeslots?: number + range?: any[] + min?: stringOrDate + max?: stringOrDate + getNow?: () => Date + scrollToTime?: Date + showMultiDayTimes?: boolean + rtl?: boolean + width?: number + accessors?: object + components?: object + getters?: object + localizer?: object + selected?: object + selectable?: boolean | 'ignoreEvents' + longPressThreshold?: number + onNavigate?: (action: NavigateAction) => void + onSelectSlot?: (slotInfo: { + start: stringOrDate + end: stringOrDate + slots: Date[] | string[] + action: 'select' | 'click' | 'doubleClick' + }) => void + onSelectEnd?: (...args: any[]) => any + onSelectStart?: (...args: any[]) => any + onSelectEvent?: (event: TEvent, e: React.SyntheticEvent) => void + onDoubleClickEvent?: ( + event: TEvent, + e: React.SyntheticEvent + ) => void + onKeyPressEvent?: (...args: any[]) => any + onDrillDown?: (date: Date, view: View) => void + getDrilldownView?: + | (( + targetDate: Date, + currentViewName: View, + configuredViewNames: View[] + ) => void) + | null + dayLayoutAlgorithm?: any +} + +export class TimeGrid< + TEvent extends object = Event, + TResource extends object = object +> extends React.Component> {} + +export interface WorkWeekProps { + date: Date +} + +export class WorkWeek extends Week {} + +export interface WeekProps { + date: Date +} + +export class Week extends React.Component { + static range: (date: Date) => Date[] + static navigate: (date: Date, action: NavigateAction) => Date + static title: (date: Date) => string +} + +export interface DayProps { + date: Date +} +export class Day extends React.Component {} + +// Turn off automatic exports +export {} From 4ddcc4e400fbd6a3384099b7e03c71be2e013e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Thu, 4 Mar 2021 13:26:52 +0700 Subject: [PATCH 09/60] Add typings for header and footer --- typings.d.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/typings.d.ts b/typings.d.ts index a56dee1c9..4df984517 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -191,6 +191,18 @@ export interface Formats { eventTimeRangeEndFormat?: DateRangeFormatFunction } +export interface DateHeaderProps { + label: string + date: Date + isOffRange: boolean +} + +export interface DateFooterProps { + label: string + date: Date + isOffRange: boolean +} + export interface HeaderProps { date: Date label: string @@ -230,8 +242,8 @@ export interface Components< } month?: { header?: React.ComponentType - dateHeader?: React.ComponentType - dateFooter?: React.ComponentType + dateHeader?: React.ComponentType + dateFooter?: React.ComponentType event?: React.ComponentType> } /** From 1f625787d6c9a92960a3c2d172ca07e815b460ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Thu, 4 Mar 2021 13:48:21 +0700 Subject: [PATCH 10/60] Add reactelement child to event wrapper for customization --- typings.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/typings.d.ts b/typings.d.ts index 4df984517..766e7052a 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -21,6 +21,7 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.8 import { Validator } from 'prop-types' +import React, { ReactElement } from 'react' type Omit = Pick> @@ -295,6 +296,9 @@ export interface EventWrapperProps { label: string continuesEarlier: boolean continuesLater: boolean + + // I actually do not know how this works but it is necessary to implement event wrapper correctly. + child: ReactElement } export interface Messages { From e934952cecec825557916240b21bd5000af4653f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Thu, 4 Mar 2021 13:49:54 +0700 Subject: [PATCH 11/60] Add reactelement child to event wrapper for customization --- typings.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/typings.d.ts b/typings.d.ts index 4df984517..1e886215f 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -21,6 +21,7 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.8 import { Validator } from 'prop-types' +import React, { ReactElement } from 'react' type Omit = Pick> @@ -295,6 +296,9 @@ export interface EventWrapperProps { label: string continuesEarlier: boolean continuesLater: boolean + + // I actually do not know how this works but it is necessary to implement event wrapper correctly. + children: ReactElement } export interface Messages { From 11afa0260844876a9e0503d02025337ee1dd6f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Thu, 4 Mar 2021 15:57:18 +0700 Subject: [PATCH 12/60] Upgrade calendar to new version --- .size-snapshot.json | 22 +++---- lib/Calendar.js | 1 + lib/DateContentRow.js | 104 ++++++++++++++++++++++----------- lib/DateFooter.js | 33 +++++++++++ lib/Month.js | 90 +++++++++++++++++++--------- lib/css/react-big-calendar.css | 6 ++ lib/sass/month.scss | 14 +++-- 7 files changed, 195 insertions(+), 75 deletions(-) create mode 100644 lib/DateFooter.js diff --git a/.size-snapshot.json b/.size-snapshot.json index 6b64d6f7c..cd70c9434 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 493239, - "minified": 154665, - "gzipped": 47351 + "bundled": 495905, + "minified": 155557, + "gzipped": 47486 }, "./dist/react-big-calendar.min.js": { - "bundled": 420519, - "minified": 131098, - "gzipped": 41400 + "bundled": 423013, + "minified": 131893, + "gzipped": 41512 }, "dist/react-big-calendar.esm.js": { - "bundled": 183071, - "minified": 87281, - "gzipped": 21627, + "bundled": 185632, + "minified": 88339, + "gzipped": 21780, "treeshaked": { "rollup": { - "code": 62394, + "code": 63187, "import_statements": 1590 }, "webpack": { - "code": 66954 + "code": 67813 } } } diff --git a/lib/Calendar.js b/lib/Calendar.js index 642f08222..40c1270eb 100644 --- a/lib/Calendar.js +++ b/lib/Calendar.js @@ -1198,6 +1198,7 @@ Calendar.propTypes = header: _propTypes.default.elementType, dateHeader: _propTypes.default.elementType, event: _propTypes.default.elementType, + footer: _propTypes.default.elementType, }), }), diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js index 3e31bfe43..f59a98818 100644 --- a/lib/DateContentRow.js +++ b/lib/DateContentRow.js @@ -128,12 +128,26 @@ var DateContentRow = }) } - _this.renderDummy = function() { + _this.renderFooterCell = function(date, index) { var _this$props4 = _this.props, - className = _this$props4.className, - range = _this$props4.range, - renderHeader = _this$props4.renderHeader, - showAllEvents = _this$props4.showAllEvents + renderFooter = _this$props4.renderFooter, + getNow = _this$props4.getNow + return renderFooter({ + date: date, + key: 'footer_' + index, + className: (0, _clsx.default)( + 'rbc-date-cell', + dates.eq(date, getNow(), 'day') && 'rbc-now' + ), + }) + } + + _this.renderDummy = function() { + var _this$props5 = _this.props, + className = _this$props5.className, + range = _this$props5.range, + renderHeader = _this$props5.renderHeader, + showAllEvents = _this$props5.showAllEvents return _react.default.createElement( 'div', { @@ -198,35 +212,49 @@ var DateContentRow = ? (0, _height.default)(this.headingRow) : 0 var eventSpace = - (0, _height.default)((0, _reactDom.findDOMNode)(this)) - headingHeight - return Math.max(Math.floor(eventSpace / eventHeight), 1) + (0, _height.default)((0, _reactDom.findDOMNode)(this)) - headingHeight // This is 5 instead of 1 because there's a bug in this library :( + // For some reason, eventSpace == eventHeight == 18 on the first render, so it only shows 1 event. + // There might be a way to fix it by changing CSS but that's not an option right now + // Since responsive design is out of scope, this is actually a viable option + // + // When the vertical space is limited in the future, and the events row overflows the date, + // Consider parameterize it to control from the outside of this library + // or change CSS to make sure this calculation always work as expected + + var MINIMUM_EVENTS_ROW = 5 + var result = Math.max( + Math.floor(eventSpace / eventHeight), + MINIMUM_EVENTS_ROW + ) + return result } _proto.render = function render() { - var _this$props5 = this.props, - date = _this$props5.date, - rtl = _this$props5.rtl, - range = _this$props5.range, - className = _this$props5.className, - selected = _this$props5.selected, - selectable = _this$props5.selectable, - renderForMeasure = _this$props5.renderForMeasure, - accessors = _this$props5.accessors, - getters = _this$props5.getters, - components = _this$props5.components, - getNow = _this$props5.getNow, - renderHeader = _this$props5.renderHeader, - onSelect = _this$props5.onSelect, - localizer = _this$props5.localizer, - onSelectStart = _this$props5.onSelectStart, - onSelectEnd = _this$props5.onSelectEnd, - onDoubleClick = _this$props5.onDoubleClick, - onKeyPress = _this$props5.onKeyPress, - resourceId = _this$props5.resourceId, - longPressThreshold = _this$props5.longPressThreshold, - isAllDay = _this$props5.isAllDay, - resizable = _this$props5.resizable, - showAllEvents = _this$props5.showAllEvents + var _this$props6 = this.props, + date = _this$props6.date, + rtl = _this$props6.rtl, + range = _this$props6.range, + className = _this$props6.className, + selected = _this$props6.selected, + selectable = _this$props6.selectable, + renderForMeasure = _this$props6.renderForMeasure, + accessors = _this$props6.accessors, + getters = _this$props6.getters, + components = _this$props6.components, + getNow = _this$props6.getNow, + renderHeader = _this$props6.renderHeader, + renderFooter = _this$props6.renderFooter, + onSelect = _this$props6.onSelect, + localizer = _this$props6.localizer, + onSelectStart = _this$props6.onSelectStart, + onSelectEnd = _this$props6.onSelectEnd, + onDoubleClick = _this$props6.onDoubleClick, + onKeyPress = _this$props6.onKeyPress, + resourceId = _this$props6.resourceId, + longPressThreshold = _this$props6.longPressThreshold, + isAllDay = _this$props6.isAllDay, + resizable = _this$props6.resizable, + showAllEvents = _this$props6.showAllEvents if (renderForMeasure) return this.renderDummy() var metrics = this.slotMetrics(this.props) var levels = metrics.levels, @@ -282,7 +310,7 @@ var DateContentRow = _react.default.createElement( 'div', { - className: 'rbc-row ', + className: 'rbc-row', ref: this.createHeadingRef, }, range.map(this.renderHeadingCell) @@ -323,7 +351,16 @@ var DateContentRow = ) ) ) - ) + ), + renderFooter && + _react.default.createElement( + 'div', + { + className: 'rbc-row rbc-row-footer', + ref: this.createHeadingRef, + }, + range.map(this.renderFooterCell) + ) ) } @@ -341,6 +378,7 @@ DateContentRow.propTypes = resourceId: _propTypes.default.any, renderForMeasure: _propTypes.default.bool, renderHeader: _propTypes.default.func, + renderFooter: _propTypes.default.func, container: _propTypes.default.func, selected: _propTypes.default.object, selectable: _propTypes.default.oneOf([true, false, 'ignoreEvents']), diff --git a/lib/DateFooter.js b/lib/DateFooter.js new file mode 100644 index 000000000..e0d2e09c2 --- /dev/null +++ b/lib/DateFooter.js @@ -0,0 +1,33 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var DateFooter = function DateFooter(_ref) { + var label = _ref.label + return _react.default.createElement( + 'span', + { + role: 'cell', + }, + label + ) +} + +DateFooter.propTypes = + process.env.NODE_ENV !== 'production' + ? { + label: _propTypes.default.node, + date: _propTypes.default.instanceOf(Date), + isOffRange: _propTypes.default.bool, + } + : {} +var _default = DateFooter +exports.default = _default +module.exports = exports['default'] diff --git a/lib/Month.js b/lib/Month.js index bb67f7ab3..3f806cc39 100644 --- a/lib/Month.js +++ b/lib/Month.js @@ -55,6 +55,8 @@ var _Header = _interopRequireDefault(require('./Header')) var _DateHeader = _interopRequireDefault(require('./DateHeader')) +var _DateFooter = _interopRequireDefault(require('./DateFooter')) + var _eventLevels = require('./utils/eventLevels') var eventsForWeek = function eventsForWeek(evts, start, end, accessors) { @@ -131,6 +133,7 @@ var MonthView = getters: getters, localizer: localizer, renderHeader: _this.readerDateHeading, + renderFooter: _this.renderDateFooter, renderForMeasure: needLimitMeasure, onShowMore: _this.handleShowMore, onSelect: _this.handleSelectEvent, @@ -183,6 +186,39 @@ var MonthView = ) } + _this.renderDateFooter = function(_ref2) { + var date = _ref2.date, + className = _ref2.className, + props = (0, _objectWithoutPropertiesLoose2.default)(_ref2, [ + 'date', + 'className', + ]) + var _this$props3 = _this.props, + currentDate = _this$props3.date, + localizer = _this$props3.localizer + var isOffRange = dates.month(date) !== dates.month(currentDate) + var isCurrent = dates.eq(date, currentDate, 'day') + var DateFooterComponent = + _this.props.components.dateFooter || _DateFooter.default + var label = localizer.format(date, 'dateFormat') + return _react.default.createElement( + 'div', + (0, _extends2.default)({}, props, { + className: (0, _clsx.default)( + className, + isOffRange && 'rbc-off-range', + isCurrent && 'rbc-current' + ), + role: 'cell', + }), + _react.default.createElement(DateFooterComponent, { + label: label, + date: date, + isOffRange: isOffRange, + }) + ) + } + _this.handleSelectSlot = function(range, slotInfo) { _this._pendingSelection = _this._pendingSelection.concat(range) clearTimeout(_this._selectTimer) @@ -242,11 +278,11 @@ var MonthView = } _this.handleShowMore = function(events, date, cell, slot, target) { - var _this$props3 = _this.props, - popup = _this$props3.popup, - onDrillDown = _this$props3.onDrillDown, - onShowMore = _this$props3.onShowMore, - getDrilldownView = _this$props3.getDrilldownView //cancel any pending selections so only the event click goes through. + var _this$props4 = _this.props, + popup = _this$props4.popup, + onDrillDown = _this$props4.onDrillDown, + onShowMore = _this$props4.onShowMore, + getDrilldownView = _this$props4.getDrilldownView //cancel any pending selections so only the event click goes through. _this.clearSelection() @@ -295,9 +331,9 @@ var MonthView = var _proto = MonthView.prototype _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps( - _ref2 + _ref3 ) { - var date = _ref2.date + var date = _ref3.date this.setState({ needLimitMeasure: !dates.eq(date, this.props.date, 'month'), }) @@ -334,10 +370,10 @@ var MonthView = } _proto.render = function render() { - var _this$props4 = this.props, - date = _this$props4.date, - localizer = _this$props4.localizer, - className = _this$props4.className, + var _this$props5 = this.props, + date = _this$props5.date, + localizer = _this$props5.localizer, + className = _this$props5.className, month = dates.visibleDays(date, localizer), weeks = (0, _chunk.default)(month, 7) this._weekCount = weeks.length @@ -362,9 +398,9 @@ var MonthView = } _proto.renderHeaders = function renderHeaders(row) { - var _this$props5 = this.props, - localizer = _this$props5.localizer, - components = _this$props5.components + var _this$props6 = this.props, + localizer = _this$props6.localizer, + components = _this$props6.components var first = row[0] var last = row[row.length - 1] var HeaderComponent = components.header || _Header.default @@ -388,13 +424,13 @@ var MonthView = var _this3 = this var overlay = (this.state && this.state.overlay) || {} - var _this$props6 = this.props, - accessors = _this$props6.accessors, - localizer = _this$props6.localizer, - components = _this$props6.components, - getters = _this$props6.getters, - selected = _this$props6.selected, - popupOffset = _this$props6.popupOffset + var _this$props7 = this.props, + accessors = _this$props7.accessors, + localizer = _this$props7.localizer, + components = _this$props7.components, + getters = _this$props7.getters, + selected = _this$props7.selected, + popupOffset = _this$props7.popupOffset return _react.default.createElement( _Overlay.default, { @@ -410,8 +446,8 @@ var MonthView = return overlay.target }, }, - function(_ref3) { - var props = _ref3.props + function(_ref4) { + var props = _ref4.props return _react.default.createElement( _Popup.default, (0, _extends2.default)({}, props, { @@ -509,8 +545,8 @@ MonthView.propTypes = } : {} -MonthView.range = function(date, _ref4) { - var localizer = _ref4.localizer +MonthView.range = function(date, _ref5) { + var localizer = _ref5.localizer var start = dates.firstVisibleDay(date, localizer) var end = dates.lastVisibleDay(date, localizer) return { @@ -532,8 +568,8 @@ MonthView.navigate = function(date, action) { } } -MonthView.title = function(date, _ref5) { - var localizer = _ref5.localizer +MonthView.title = function(date, _ref6) { + var localizer = _ref6.localizer return localizer.format(date, 'monthHeaderFormat') } diff --git a/lib/css/react-big-calendar.css b/lib/css/react-big-calendar.css index 0d8d520a9..f6342b81b 100644 --- a/lib/css/react-big-calendar.css +++ b/lib/css/react-big-calendar.css @@ -323,6 +323,12 @@ button.rbc-input::-moz-focus-inner { border-top: 1px solid #ddd; } +.rbc-row-footer { + position: absolute; + width: 100%; + bottom: 0; +} + .rbc-date-cell { flex: 1 1 0; min-width: 0; diff --git a/lib/sass/month.scss b/lib/sass/month.scss index 9f2fecdf7..030e65dde 100644 --- a/lib/sass/month.scss +++ b/lib/sass/month.scss @@ -17,7 +17,6 @@ background-color: $date-selection-bg-color; } - .rbc-show-more { @extend .rbc-ellipsis; background-color: rgba(255, 255, 255, 0.3); @@ -60,6 +59,11 @@ border-top: 1px solid $cell-border; } } +.rbc-row-footer { + position: absolute; + width: 100%; + bottom: 0; +} .rbc-date-cell { flex: 1 1 0; @@ -72,7 +76,9 @@ } > a { - &, &:active, &:visited { + &, + &:active, + &:visited { color: inherit; text-decoration: none; } @@ -105,7 +111,7 @@ z-index: $event-zindex + 1; border: 1px solid #e5e5e5; background-color: #fff; - box-shadow: 0 5px 15px rgba(0,0,0,.25); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.25); padding: 10px; > * + * { @@ -115,6 +121,6 @@ .rbc-overlay-header { border-bottom: 1px solid #e5e5e5; - margin: -10px -10px 5px -10px ; + margin: -10px -10px 5px -10px; padding: 2px 10px; } From c86dc9ed81919db7e89a3d6b86713342cfe8b344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Mon, 8 Mar 2021 11:09:19 +0700 Subject: [PATCH 13/60] Remove padding from date cells --- lib/css/react-big-calendar.css | 1 - lib/sass/month.scss | 2 +- src/less/month.less | 2 +- src/sass/month.scss | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/css/react-big-calendar.css b/lib/css/react-big-calendar.css index f6342b81b..88438e871 100644 --- a/lib/css/react-big-calendar.css +++ b/lib/css/react-big-calendar.css @@ -332,7 +332,6 @@ button.rbc-input::-moz-focus-inner { .rbc-date-cell { flex: 1 1 0; min-width: 0; - padding-right: 5px; text-align: right; } .rbc-date-cell.rbc-now { diff --git a/lib/sass/month.scss b/lib/sass/month.scss index 030e65dde..a18502cc9 100644 --- a/lib/sass/month.scss +++ b/lib/sass/month.scss @@ -68,7 +68,7 @@ .rbc-date-cell { flex: 1 1 0; min-width: 0; - padding-right: 5px; + // padding-right: 5px; text-align: right; &.rbc-now { diff --git a/src/less/month.less b/src/less/month.less index f9fd1f483..8767640f3 100644 --- a/src/less/month.less +++ b/src/less/month.less @@ -68,7 +68,7 @@ .rbc-date-cell { flex: 1 1 0; min-width: 0; - padding-right: 5px; + // padding-right: 5px; text-align: right; &.rbc-now { diff --git a/src/sass/month.scss b/src/sass/month.scss index 030e65dde..a18502cc9 100644 --- a/src/sass/month.scss +++ b/src/sass/month.scss @@ -68,7 +68,7 @@ .rbc-date-cell { flex: 1 1 0; min-width: 0; - padding-right: 5px; + // padding-right: 5px; text-align: right; &.rbc-now { From 967cb76b66c3d0ce0c2da1cf124fdd4afd3a0072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Mon, 8 Mar 2021 17:31:35 +0700 Subject: [PATCH 14/60] Adjust minimum events per row --- .size-snapshot.json | 2 +- lib/DateContentRow.js | 2 +- src/DateContentRow.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index cd70c9434..855906c2e 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -12,7 +12,7 @@ "dist/react-big-calendar.esm.js": { "bundled": 185632, "minified": 88339, - "gzipped": 21780, + "gzipped": 21778, "treeshaked": { "rollup": { "code": 63187, diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js index f59a98818..523a542c1 100644 --- a/lib/DateContentRow.js +++ b/lib/DateContentRow.js @@ -221,7 +221,7 @@ var DateContentRow = // Consider parameterize it to control from the outside of this library // or change CSS to make sure this calculation always work as expected - var MINIMUM_EVENTS_ROW = 5 + var MINIMUM_EVENTS_ROW = 4 var result = Math.max( Math.floor(eventSpace / eventHeight), MINIMUM_EVENTS_ROW diff --git a/src/DateContentRow.js b/src/DateContentRow.js index f9b682196..2f77e4c2c 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -64,7 +64,7 @@ class DateContentRow extends React.Component { // When the vertical space is limited in the future, and the events row overflows the date, // Consider parameterize it to control from the outside of this library // or change CSS to make sure this calculation always work as expected - const MINIMUM_EVENTS_ROW = 5 + const MINIMUM_EVENTS_ROW = 4 const result = Math.max( Math.floor(eventSpace / eventHeight), MINIMUM_EVENTS_ROW From db71b9ecc72c0d5e8a0dcbf7438d553274695c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Mon, 8 Mar 2021 17:44:32 +0700 Subject: [PATCH 15/60] Update row limit to fixed size --- .size-snapshot.json | 24 ++++++++++++------------ lib/DateContentRow.js | 24 ++++++++++-------------- src/DateContentRow.js | 20 ++++++++++---------- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 855906c2e..7e1a8bf53 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 495905, - "minified": 155557, - "gzipped": 47486 + "bundled": 495806, + "minified": 155357, + "gzipped": 47409 }, "./dist/react-big-calendar.min.js": { - "bundled": 423013, - "minified": 131893, - "gzipped": 41512 + "bundled": 422914, + "minified": 131693, + "gzipped": 41460 }, "dist/react-big-calendar.esm.js": { - "bundled": 185632, - "minified": 88339, - "gzipped": 21778, + "bundled": 185637, + "minified": 88160, + "gzipped": 21712, "treeshaked": { "rollup": { - "code": 63187, - "import_statements": 1590 + "code": 63048, + "import_statements": 1555 }, "webpack": { - "code": 67813 + "code": 67608 } } } diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js index 523a542c1..cc0a8522d 100644 --- a/lib/DateContentRow.js +++ b/lib/DateContentRow.js @@ -21,8 +21,6 @@ var _inheritsLoose2 = _interopRequireDefault( var _clsx = _interopRequireDefault(require('clsx')) -var _height = _interopRequireDefault(require('dom-helpers/height')) - var _querySelectorAll = _interopRequireDefault( require('dom-helpers/querySelectorAll') ) @@ -51,6 +49,7 @@ var DateSlotMetrics = _interopRequireWildcard( require('./utils/DateSlotMetrics') ) +// import getHeight from 'dom-helpers/height' var DateContentRow = /*#__PURE__*/ (function(_React$Component) { @@ -207,12 +206,10 @@ var DateContentRow = var _proto = DateContentRow.prototype _proto.getRowLimit = function getRowLimit() { - var eventHeight = (0, _height.default)(this.eventRow) - var headingHeight = this.headingRow - ? (0, _height.default)(this.headingRow) - : 0 - var eventSpace = - (0, _height.default)((0, _reactDom.findDOMNode)(this)) - headingHeight // This is 5 instead of 1 because there's a bug in this library :( + // let eventHeight = getHeight(this.eventRow) + // let headingHeight = this.headingRow ? getHeight(this.headingRow) : 0 + // let eventSpace = getHeight(findDOMNode(this)) - headingHeight + // This is 4 instead of 1 because there's a bug in this library :( // For some reason, eventSpace == eventHeight == 18 on the first render, so it only shows 1 event. // There might be a way to fix it by changing CSS but that's not an option right now // Since responsive design is out of scope, this is actually a viable option @@ -220,13 +217,12 @@ var DateContentRow = // When the vertical space is limited in the future, and the events row overflows the date, // Consider parameterize it to control from the outside of this library // or change CSS to make sure this calculation always work as expected + var MINIMUM_EVENTS_ROW = 4 // const result = Math.max( + // Math.floor(eventSpace / eventHeight), + // MINIMUM_EVENTS_ROW + // ) - var MINIMUM_EVENTS_ROW = 4 - var result = Math.max( - Math.floor(eventSpace / eventHeight), - MINIMUM_EVENTS_ROW - ) - return result + return MINIMUM_EVENTS_ROW } _proto.render = function render() { diff --git a/src/DateContentRow.js b/src/DateContentRow.js index 2f77e4c2c..a906feb83 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -1,5 +1,5 @@ import clsx from 'clsx' -import getHeight from 'dom-helpers/height' +// import getHeight from 'dom-helpers/height' import qsa from 'dom-helpers/querySelectorAll' import PropTypes from 'prop-types' import React from 'react' @@ -52,11 +52,11 @@ class DateContentRow extends React.Component { } getRowLimit() { - let eventHeight = getHeight(this.eventRow) - let headingHeight = this.headingRow ? getHeight(this.headingRow) : 0 - let eventSpace = getHeight(findDOMNode(this)) - headingHeight + // let eventHeight = getHeight(this.eventRow) + // let headingHeight = this.headingRow ? getHeight(this.headingRow) : 0 + // let eventSpace = getHeight(findDOMNode(this)) - headingHeight - // This is 5 instead of 1 because there's a bug in this library :( + // This is 4 instead of 1 because there's a bug in this library :( // For some reason, eventSpace == eventHeight == 18 on the first render, so it only shows 1 event. // There might be a way to fix it by changing CSS but that's not an option right now // Since responsive design is out of scope, this is actually a viable option @@ -65,11 +65,11 @@ class DateContentRow extends React.Component { // Consider parameterize it to control from the outside of this library // or change CSS to make sure this calculation always work as expected const MINIMUM_EVENTS_ROW = 4 - const result = Math.max( - Math.floor(eventSpace / eventHeight), - MINIMUM_EVENTS_ROW - ) - return result + // const result = Math.max( + // Math.floor(eventSpace / eventHeight), + // MINIMUM_EVENTS_ROW + // ) + return MINIMUM_EVENTS_ROW } renderHeadingCell = (date, index) => { From 602542cfe563400511389b107bebd64d56b4045b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Mon, 8 Mar 2021 17:47:48 +0700 Subject: [PATCH 16/60] Update row limit to fixed size: 5 --- .size-snapshot.json | 2 +- lib/DateContentRow.js | 4 ++-- src/DateContentRow.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 7e1a8bf53..45466ea57 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -12,7 +12,7 @@ "dist/react-big-calendar.esm.js": { "bundled": 185637, "minified": 88160, - "gzipped": 21712, + "gzipped": 21714, "treeshaked": { "rollup": { "code": 63048, diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js index cc0a8522d..0c7f50537 100644 --- a/lib/DateContentRow.js +++ b/lib/DateContentRow.js @@ -209,7 +209,7 @@ var DateContentRow = // let eventHeight = getHeight(this.eventRow) // let headingHeight = this.headingRow ? getHeight(this.headingRow) : 0 // let eventSpace = getHeight(findDOMNode(this)) - headingHeight - // This is 4 instead of 1 because there's a bug in this library :( + // This is 5 instead of 1 because there's a bug in this library :( // For some reason, eventSpace == eventHeight == 18 on the first render, so it only shows 1 event. // There might be a way to fix it by changing CSS but that's not an option right now // Since responsive design is out of scope, this is actually a viable option @@ -217,7 +217,7 @@ var DateContentRow = // When the vertical space is limited in the future, and the events row overflows the date, // Consider parameterize it to control from the outside of this library // or change CSS to make sure this calculation always work as expected - var MINIMUM_EVENTS_ROW = 4 // const result = Math.max( + var MINIMUM_EVENTS_ROW = 5 // const result = Math.max( // Math.floor(eventSpace / eventHeight), // MINIMUM_EVENTS_ROW // ) diff --git a/src/DateContentRow.js b/src/DateContentRow.js index a906feb83..1cf5d1655 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -56,7 +56,7 @@ class DateContentRow extends React.Component { // let headingHeight = this.headingRow ? getHeight(this.headingRow) : 0 // let eventSpace = getHeight(findDOMNode(this)) - headingHeight - // This is 4 instead of 1 because there's a bug in this library :( + // This is 5 instead of 1 because there's a bug in this library :( // For some reason, eventSpace == eventHeight == 18 on the first render, so it only shows 1 event. // There might be a way to fix it by changing CSS but that's not an option right now // Since responsive design is out of scope, this is actually a viable option @@ -64,7 +64,7 @@ class DateContentRow extends React.Component { // When the vertical space is limited in the future, and the events row overflows the date, // Consider parameterize it to control from the outside of this library // or change CSS to make sure this calculation always work as expected - const MINIMUM_EVENTS_ROW = 4 + const MINIMUM_EVENTS_ROW = 5 // const result = Math.max( // Math.floor(eventSpace / eventHeight), // MINIMUM_EVENTS_ROW From 6b7d0dd1cb6a89c8c1836689fc8d384744829494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Tue, 9 Mar 2021 10:47:23 +0700 Subject: [PATCH 17/60] Make show more button customizable --- examples/demos/rendering.js | 8 ++++++++ src/DateContentRow.js | 1 + src/EventEndingRow.js | 16 +++++++--------- src/ShowMoreButton.js | 18 ++++++++++++++++++ typings.d.ts | 7 +++++++ 5 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 src/ShowMoreButton.js diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index 683f67e15..d82267303 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -58,6 +58,13 @@ const CalendarFooter = ({ label }) => {
) } +const ShowMoreButton = ({ key, onClick, label }) => { + return ( + + ) +} let Rendering = ({ localizer }) => { const [localEvents, setEvents] = useState([]) @@ -82,6 +89,7 @@ let Rendering = ({ localizer }) => { month: { dateHeader: CalendarHeader, dateFooter: CalendarFooter, + showMoreButton: ShowMoreButton, }, // agenda: { // event: EventAgenda, diff --git a/src/DateContentRow.js b/src/DateContentRow.js index 1cf5d1655..6064ed095 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -218,6 +218,7 @@ class DateContentRow extends React.Component { )} diff --git a/src/EventEndingRow.js b/src/EventEndingRow.js index 1fde7bb37..b308c04d1 100644 --- a/src/EventEndingRow.js +++ b/src/EventEndingRow.js @@ -3,6 +3,7 @@ import React from 'react' import EventRowMixin from './EventRowMixin' import { eventLevels } from './utils/eventLevels' import range from 'lodash/range' +import ShowMoreButton from './ShowMoreButton' let isSegmentInSlot = (seg, slot) => seg.left <= slot && seg.right >= slot let eventsInSlot = (segments, slot) => @@ -74,18 +75,15 @@ class EventEndingRow extends React.Component { } renderShowMore(segments, slot) { - let { localizer } = this.props + let { localizer, components } = this.props let count = eventsInSlot(segments, slot) + const key = 'sm_' + slot + const onClick = e => this.showMore(slot, e) + const label = localizer.messages.showMore(count) + const ShowMore = components.showMoreButton || ShowMoreButton return count ? ( - this.showMore(slot, e)} - > - {localizer.messages.showMore(count)} - + ) : ( false ) diff --git a/src/ShowMoreButton.js b/src/ShowMoreButton.js new file mode 100644 index 000000000..5f4bde4a5 --- /dev/null +++ b/src/ShowMoreButton.js @@ -0,0 +1,18 @@ +import PropTypes from 'prop-types' +import React from 'react' + +const ShowMoreButton = ({ key, onClick, label }) => { + return ( + + {label} + + ) +} + +ShowMoreButton.propTypes = { + key: PropTypes.string.isRequired, + onClick: PropTypes.func.isRequired, + label: PropTypes.string.isRequired, +} + +export default ShowMoreButton diff --git a/typings.d.ts b/typings.d.ts index 1e886215f..ffd1241df 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -204,6 +204,12 @@ export interface DateFooterProps { isOffRange: boolean } +export interface ShowMoreButtonProps { + key: string + onClick: () => void + label: string +} + export interface HeaderProps { date: Date label: string @@ -246,6 +252,7 @@ export interface Components< dateHeader?: React.ComponentType dateFooter?: React.ComponentType event?: React.ComponentType> + showMoreButton?: React.ComponentType } /** * component used as a header for each column in the TimeGridHeader From 30a1ed91369b15a28c1b3588a64ee6f93cf1e346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Tue, 9 Mar 2021 10:53:43 +0700 Subject: [PATCH 18/60] Update build for showMoreButton --- .size-snapshot.json | 22 +++++++++++----------- lib/DateContentRow.js | 1 + lib/EventEndingRow.js | 31 ++++++++++++++++++------------- lib/ShowMoreButton.js | 38 ++++++++++++++++++++++++++++++++++++++ typings.d.ts | 2 +- 5 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 lib/ShowMoreButton.js diff --git a/.size-snapshot.json b/.size-snapshot.json index 45466ea57..d8796efe3 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 495806, - "minified": 155357, - "gzipped": 47409 + "bundled": 496480, + "minified": 155617, + "gzipped": 47489 }, "./dist/react-big-calendar.min.js": { - "bundled": 422914, - "minified": 131693, - "gzipped": 41460 + "bundled": 423468, + "minified": 131878, + "gzipped": 41515 }, "dist/react-big-calendar.esm.js": { - "bundled": 185637, - "minified": 88160, - "gzipped": 21714, + "bundled": 186303, + "minified": 88523, + "gzipped": 21812, "treeshaked": { "rollup": { - "code": 63048, + "code": 63233, "import_statements": 1555 }, "webpack": { - "code": 67608 + "code": 67795 } } } diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js index 0c7f50537..5f103fc43 100644 --- a/lib/DateContentRow.js +++ b/lib/DateContentRow.js @@ -341,6 +341,7 @@ var DateContentRow = { segments: extra, onShowMore: this.handleShowMore, + components: components, }, eventRowProps ) diff --git a/lib/EventEndingRow.js b/lib/EventEndingRow.js index 97c09b597..3f8abccd9 100644 --- a/lib/EventEndingRow.js +++ b/lib/EventEndingRow.js @@ -23,6 +23,8 @@ var _eventLevels = require('./utils/eventLevels') var _range = _interopRequireDefault(require('lodash/range')) +var _ShowMoreButton = _interopRequireDefault(require('./ShowMoreButton')) + var isSegmentInSlot = function isSegmentInSlot(seg, slot) { return seg.left <= slot && seg.right >= slot } @@ -122,21 +124,24 @@ var EventEndingRow = _proto.renderShowMore = function renderShowMore(segments, slot) { var _this = this - var localizer = this.props.localizer + var _this$props2 = this.props, + localizer = _this$props2.localizer, + components = _this$props2.components var count = eventsInSlot(segments, slot) + var key = 'sm_' + slot + + var onClick = function onClick(e) { + return _this.showMore(slot, e) + } + + var label = localizer.messages.showMore(count) + var ShowMore = components.showMoreButton || _ShowMoreButton.default return count - ? _react.default.createElement( - 'a', - { - key: 'sm_' + slot, - href: '#', - className: 'rbc-show-more', - onClick: function onClick(e) { - return _this.showMore(slot, e) - }, - }, - localizer.messages.showMore(count) - ) + ? _react.default.createElement(ShowMore, { + key: key, + onClick: onClick, + label: label, + }) : false } diff --git a/lib/ShowMoreButton.js b/lib/ShowMoreButton.js new file mode 100644 index 000000000..2a1252ad4 --- /dev/null +++ b/lib/ShowMoreButton.js @@ -0,0 +1,38 @@ +'use strict' + +var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = void 0 + +var _propTypes = _interopRequireDefault(require('prop-types')) + +var _react = _interopRequireDefault(require('react')) + +var ShowMoreButton = function ShowMoreButton(_ref) { + var key = _ref.key, + onClick = _ref.onClick, + label = _ref.label + return _react.default.createElement( + 'a', + { + key: key, + href: '#', + className: 'rbc-show-more', + onClick: onClick, + }, + label + ) +} + +ShowMoreButton.propTypes = + process.env.NODE_ENV !== 'production' + ? { + key: _propTypes.default.string.isRequired, + onClick: _propTypes.default.func.isRequired, + label: _propTypes.default.string.isRequired, + } + : {} +var _default = ShowMoreButton +exports.default = _default +module.exports = exports['default'] diff --git a/typings.d.ts b/typings.d.ts index ffd1241df..1c5c5d679 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -252,7 +252,7 @@ export interface Components< dateHeader?: React.ComponentType dateFooter?: React.ComponentType event?: React.ComponentType> - showMoreButton?: React.ComponentType + showMoreButton?: React.ComponentType } /** * component used as a header for each column in the TimeGridHeader From 9ebbeb08a0d777605c89b51f50bc974f4f95eb2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Tue, 9 Mar 2021 11:02:55 +0700 Subject: [PATCH 19/60] Add events count for showMore to better customize it --- src/EventEndingRow.js | 7 ++++++- src/ShowMoreButton.js | 1 + typings.d.ts | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/EventEndingRow.js b/src/EventEndingRow.js index b308c04d1..83184362d 100644 --- a/src/EventEndingRow.js +++ b/src/EventEndingRow.js @@ -83,7 +83,12 @@ class EventEndingRow extends React.Component { const label = localizer.messages.showMore(count) const ShowMore = components.showMoreButton || ShowMoreButton return count ? ( - + ) : ( false ) diff --git a/src/ShowMoreButton.js b/src/ShowMoreButton.js index 5f4bde4a5..986472c2f 100644 --- a/src/ShowMoreButton.js +++ b/src/ShowMoreButton.js @@ -13,6 +13,7 @@ ShowMoreButton.propTypes = { key: PropTypes.string.isRequired, onClick: PropTypes.func.isRequired, label: PropTypes.string.isRequired, + extraEventsCount: PropTypes.number, } export default ShowMoreButton diff --git a/typings.d.ts b/typings.d.ts index 1c5c5d679..92002f10a 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -208,6 +208,7 @@ export interface ShowMoreButtonProps { key: string onClick: () => void label: string + extraEventsCount: number } export interface HeaderProps { From c8ec3bddd6c1abcdfafabf849c62b460f403c641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Tue, 9 Mar 2021 11:03:31 +0700 Subject: [PATCH 20/60] Build: Add extra events count prop for showMore --- .size-snapshot.json | 22 +++++++++++----------- lib/EventEndingRow.js | 1 + lib/ShowMoreButton.js | 1 + 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index d8796efe3..6da48e87c 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 496480, - "minified": 155617, - "gzipped": 47489 + "bundled": 496553, + "minified": 155662, + "gzipped": 47509 }, "./dist/react-big-calendar.min.js": { - "bundled": 423468, - "minified": 131878, - "gzipped": 41515 + "bundled": 423501, + "minified": 131897, + "gzipped": 41527 }, "dist/react-big-calendar.esm.js": { - "bundled": 186303, - "minified": 88523, - "gzipped": 21812, + "bundled": 186372, + "minified": 88576, + "gzipped": 21830, "treeshaked": { "rollup": { - "code": 63233, + "code": 63252, "import_statements": 1555 }, "webpack": { - "code": 67795 + "code": 67814 } } } diff --git a/lib/EventEndingRow.js b/lib/EventEndingRow.js index 3f8abccd9..6d0bec0d3 100644 --- a/lib/EventEndingRow.js +++ b/lib/EventEndingRow.js @@ -141,6 +141,7 @@ var EventEndingRow = key: key, onClick: onClick, label: label, + extraEventsCount: count, }) : false } diff --git a/lib/ShowMoreButton.js b/lib/ShowMoreButton.js index 2a1252ad4..9a84f2651 100644 --- a/lib/ShowMoreButton.js +++ b/lib/ShowMoreButton.js @@ -31,6 +31,7 @@ ShowMoreButton.propTypes = key: _propTypes.default.string.isRequired, onClick: _propTypes.default.func.isRequired, label: _propTypes.default.string.isRequired, + extraEventsCount: _propTypes.default.number, } : {} var _default = ShowMoreButton From 8884a59cb7399a8a6e1d355addd06c994963b7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 10 Mar 2021 17:15:40 +0700 Subject: [PATCH 21/60] Add typings for header --- typings.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings.d.ts b/typings.d.ts index 92002f10a..43ddeafc7 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -249,7 +249,7 @@ export interface Components< event?: React.ComponentType> } month?: { - header?: React.ComponentType + header?: React.ComponentType dateHeader?: React.ComponentType dateFooter?: React.ComponentType event?: React.ComponentType> From 2e38eff42a9f87dbce213f466129f1a43665632c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Thu, 11 Mar 2021 11:45:11 +0700 Subject: [PATCH 22/60] Add events list as props to showMoreButton --- examples/demos/rendering.js | 2 +- src/DateContentRow.js | 2 ++ src/EventEndingRow.js | 3 ++- typings.d.ts | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index d82267303..b5e6d42e6 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -58,7 +58,7 @@ const CalendarFooter = ({ label }) => {
) } -const ShowMoreButton = ({ key, onClick, label }) => { +const ShowMoreButton = ({ key, onClick, label, events }) => { return ( - ) +const ShowMoreButton = ({ onClick, label }) => { + return } let Rendering = ({ localizer }) => { diff --git a/src/DateContentRow.js b/src/DateContentRow.js index 2f7245584..6064ed095 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -128,7 +128,6 @@ class DateContentRow extends React.Component { render() { const { date, - events, rtl, range, className, @@ -167,7 +166,6 @@ class DateContentRow extends React.Component { let WeekWrapper = components.weekWrapper const eventRowProps = { - events, selected, accessors, getters, diff --git a/src/EventEndingRow.js b/src/EventEndingRow.js index bcffbb536..83184362d 100644 --- a/src/EventEndingRow.js +++ b/src/EventEndingRow.js @@ -75,7 +75,7 @@ class EventEndingRow extends React.Component { } renderShowMore(segments, slot) { - let { localizer, components, events } = this.props + let { localizer, components } = this.props let count = eventsInSlot(segments, slot) const key = 'sm_' + slot @@ -88,7 +88,6 @@ class EventEndingRow extends React.Component { onClick={onClick} label={label} extraEventsCount={count} - events={events} /> ) : ( false diff --git a/typings.d.ts b/typings.d.ts index a59903059..65f61ef9e 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -209,7 +209,6 @@ export interface ShowMoreButtonProps { onClick: () => void label: string extraEventsCount: number - events: TEvent[] } export interface HeaderProps { From d8e21f09e73f70660ea37a5909a293f46dcdd697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Thu, 11 Mar 2021 14:53:59 +0700 Subject: [PATCH 26/60] Revert "Remove events as props from show more button" This reverts commit 12c1cd9a126844d2473e89e529003e67f9d3c631. --- examples/demos/rendering.js | 8 ++++++-- src/DateContentRow.js | 2 ++ src/EventEndingRow.js | 3 ++- typings.d.ts | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index fa97a11c1..b5e6d42e6 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -58,8 +58,12 @@ const CalendarFooter = ({ label }) => { ) } -const ShowMoreButton = ({ onClick, label }) => { - return +const ShowMoreButton = ({ key, onClick, label, events }) => { + return ( + + ) } let Rendering = ({ localizer }) => { diff --git a/src/DateContentRow.js b/src/DateContentRow.js index 6064ed095..2f7245584 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -128,6 +128,7 @@ class DateContentRow extends React.Component { render() { const { date, + events, rtl, range, className, @@ -166,6 +167,7 @@ class DateContentRow extends React.Component { let WeekWrapper = components.weekWrapper const eventRowProps = { + events, selected, accessors, getters, diff --git a/src/EventEndingRow.js b/src/EventEndingRow.js index 83184362d..bcffbb536 100644 --- a/src/EventEndingRow.js +++ b/src/EventEndingRow.js @@ -75,7 +75,7 @@ class EventEndingRow extends React.Component { } renderShowMore(segments, slot) { - let { localizer, components } = this.props + let { localizer, components, events } = this.props let count = eventsInSlot(segments, slot) const key = 'sm_' + slot @@ -88,6 +88,7 @@ class EventEndingRow extends React.Component { onClick={onClick} label={label} extraEventsCount={count} + events={events} /> ) : ( false diff --git a/typings.d.ts b/typings.d.ts index 65f61ef9e..a59903059 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -209,6 +209,7 @@ export interface ShowMoreButtonProps { onClick: () => void label: string extraEventsCount: number + events: TEvent[] } export interface HeaderProps { From 70e669f852d4bd22830e25d1d95e301e82851af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Thu, 11 Mar 2021 14:54:19 +0700 Subject: [PATCH 27/60] Revert "Fix typings for events" This reverts commit ed203484ef9b7153e77de5391806e0740880a23f. --- typings.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings.d.ts b/typings.d.ts index a59903059..d0204f14e 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -209,7 +209,7 @@ export interface ShowMoreButtonProps { onClick: () => void label: string extraEventsCount: number - events: TEvent[] + events: TEvent } export interface HeaderProps { From 036937f5107ea8b3c3332f1eeb7e18a9606383d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Thu, 11 Mar 2021 14:54:26 +0700 Subject: [PATCH 28/60] Revert "Build: Add events list as props to show more button" This reverts commit bffd6ee21840cb0923c23b02fb7d850f1ba9451f. --- .size-snapshot.json | 22 +++++++++++----------- lib/DateContentRow.js | 2 -- lib/EventEndingRow.js | 4 +--- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index c422e79bf..6da48e87c 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 496681, - "minified": 155702, - "gzipped": 47526 + "bundled": 496553, + "minified": 155662, + "gzipped": 47509 }, "./dist/react-big-calendar.min.js": { - "bundled": 423629, - "minified": 131937, - "gzipped": 41544 + "bundled": 423501, + "minified": 131897, + "gzipped": 41527 }, "dist/react-big-calendar.esm.js": { - "bundled": 186492, - "minified": 88616, - "gzipped": 21864, + "bundled": 186372, + "minified": 88576, + "gzipped": 21830, "treeshaked": { "rollup": { - "code": 63292, + "code": 63252, "import_statements": 1555 }, "webpack": { - "code": 67854 + "code": 67814 } } } diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js index a1c2a241b..5f103fc43 100644 --- a/lib/DateContentRow.js +++ b/lib/DateContentRow.js @@ -228,7 +228,6 @@ var DateContentRow = _proto.render = function render() { var _this$props6 = this.props, date = _this$props6.date, - events = _this$props6.events, rtl = _this$props6.rtl, range = _this$props6.range, className = _this$props6.className, @@ -261,7 +260,6 @@ var DateContentRow = : _NoopWrapper.default var WeekWrapper = components.weekWrapper var eventRowProps = { - events: events, selected: selected, accessors: accessors, getters: getters, diff --git a/lib/EventEndingRow.js b/lib/EventEndingRow.js index fbf9e6a8e..6d0bec0d3 100644 --- a/lib/EventEndingRow.js +++ b/lib/EventEndingRow.js @@ -126,8 +126,7 @@ var EventEndingRow = var _this$props2 = this.props, localizer = _this$props2.localizer, - components = _this$props2.components, - events = _this$props2.events + components = _this$props2.components var count = eventsInSlot(segments, slot) var key = 'sm_' + slot @@ -143,7 +142,6 @@ var EventEndingRow = onClick: onClick, label: label, extraEventsCount: count, - events: events, }) : false } From 3d5b3d2bb708ec498d1c779a677f96a91065d993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Thu, 11 Mar 2021 14:54:31 +0700 Subject: [PATCH 29/60] Revert "Add events list as props to showMoreButton" This reverts commit 2e38eff42a9f87dbce213f466129f1a43665632c. --- examples/demos/rendering.js | 2 +- src/DateContentRow.js | 2 -- src/EventEndingRow.js | 3 +-- typings.d.ts | 3 +-- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index b5e6d42e6..d82267303 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -58,7 +58,7 @@ const CalendarFooter = ({ label }) => { ) } -const ShowMoreButton = ({ key, onClick, label, events }) => { +const ShowMoreButton = ({ key, onClick, label }) => { return ( - ) +const ShowMoreButton = ({ label, events }) => { + return } let Rendering = ({ localizer }) => { diff --git a/src/DateContentRow.js b/src/DateContentRow.js index 6064ed095..331236e09 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -38,6 +38,12 @@ class DateContentRow extends React.Component { onShowMore(events, range[slot - 1], cell, slot, target) } + getEvents = slot => { + const metrics = this.slotMetrics(this.props) + const events = metrics.getEventsForSlot(slot) + return events + } + createHeadingRef = r => { this.headingRow = r } @@ -218,6 +224,7 @@ class DateContentRow extends React.Component { diff --git a/src/EventEndingRow.js b/src/EventEndingRow.js index 83184362d..cba0a2252 100644 --- a/src/EventEndingRow.js +++ b/src/EventEndingRow.js @@ -75,17 +75,19 @@ class EventEndingRow extends React.Component { } renderShowMore(segments, slot) { - let { localizer, components } = this.props + let { localizer, components, getEvents } = this.props let count = eventsInSlot(segments, slot) const key = 'sm_' + slot const onClick = e => this.showMore(slot, e) + const events = getEvents(slot) const label = localizer.messages.showMore(count) const ShowMore = components.showMoreButton || ShowMoreButton return count ? ( diff --git a/typings.d.ts b/typings.d.ts index 43ddeafc7..8e3e8f68e 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -204,9 +204,9 @@ export interface DateFooterProps { isOffRange: boolean } -export interface ShowMoreButtonProps { - key: string +export interface ShowMoreButtonProps { onClick: () => void + events: TEvent[] label: string extraEventsCount: number } @@ -253,7 +253,7 @@ export interface Components< dateHeader?: React.ComponentType dateFooter?: React.ComponentType event?: React.ComponentType> - showMoreButton?: React.ComponentType + showMoreButton?: React.ComponentType> } /** * component used as a header for each column in the TimeGridHeader From 4738bb23935acc71a824b04876ac6cf4b07978d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 12 Mar 2021 10:33:27 +0700 Subject: [PATCH 31/60] build: pass in daily events as props for popups --- .size-snapshot.json | 22 +++++++++++----------- lib/DateContentRow.js | 8 ++++++++ lib/EventEndingRow.js | 5 ++++- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 6da48e87c..534b76762 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 496553, - "minified": 155662, - "gzipped": 47509 + "bundled": 496877, + "minified": 155792, + "gzipped": 47546 }, "./dist/react-big-calendar.min.js": { - "bundled": 423501, - "minified": 131897, - "gzipped": 41527 + "bundled": 423825, + "minified": 132027, + "gzipped": 41561 }, "dist/react-big-calendar.esm.js": { - "bundled": 186372, - "minified": 88576, - "gzipped": 21830, + "bundled": 186678, + "minified": 88706, + "gzipped": 21861, "treeshaked": { "rollup": { - "code": 63252, + "code": 63382, "import_statements": 1555 }, "webpack": { - "code": 67814 + "code": 67944 } } } diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js index 5f103fc43..01f9fa003 100644 --- a/lib/DateContentRow.js +++ b/lib/DateContentRow.js @@ -96,6 +96,13 @@ var DateContentRow = onShowMore(events, range[slot - 1], cell, slot, target) } + _this.getEvents = function(slot) { + var metrics = _this.slotMetrics(_this.props) + + var events = metrics.getEventsForSlot(slot) + return events + } + _this.createHeadingRef = function(r) { _this.headingRow = r } @@ -341,6 +348,7 @@ var DateContentRow = { segments: extra, onShowMore: this.handleShowMore, + getEvents: this.getEvents, components: components, }, eventRowProps diff --git a/lib/EventEndingRow.js b/lib/EventEndingRow.js index 6d0bec0d3..2e12a42a9 100644 --- a/lib/EventEndingRow.js +++ b/lib/EventEndingRow.js @@ -126,7 +126,8 @@ var EventEndingRow = var _this$props2 = this.props, localizer = _this$props2.localizer, - components = _this$props2.components + components = _this$props2.components, + getEvents = _this$props2.getEvents var count = eventsInSlot(segments, slot) var key = 'sm_' + slot @@ -134,12 +135,14 @@ var EventEndingRow = return _this.showMore(slot, e) } + var events = getEvents(slot) var label = localizer.messages.showMore(count) var ShowMore = components.showMoreButton || _ShowMoreButton.default return count ? _react.default.createElement(ShowMore, { key: key, onClick: onClick, + events: events, label: label, extraEventsCount: count, }) From fa1ea359a88168d9557af6fa2b39c92369b1cea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 12 Mar 2021 12:08:38 +0700 Subject: [PATCH 32/60] feature: Implement children as an optional --- examples/demos/rendering.js | 10 ++++++++-- src/EventCell.js | 3 +++ src/EventEndingRow.js | 30 +++++++++++++++++++++++++++--- typings.d.ts | 6 ++++-- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index cc4a5546b..cffb46d4d 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -58,8 +58,14 @@ const CalendarFooter = ({ label }) => { ) } -const ShowMoreButton = ({ label, events }) => { - return +const ShowMoreButton = ({ label, events, children }) => { + return ( +
+ POPUP + {children} +
+ ) + // return } let Rendering = ({ localizer }) => { diff --git a/src/EventCell.js b/src/EventCell.js index 0c5bc88ae..dfdcdea71 100644 --- a/src/EventCell.js +++ b/src/EventCell.js @@ -6,6 +6,7 @@ import * as dates from './utils/dates' class EventCell extends React.Component { render() { let { + type, style, className, event, @@ -50,6 +51,7 @@ class EventCell extends React.Component { localizer={localizer} slotStart={slotStart} slotEnd={slotEnd} + isInPopup={type == 'popup'} /> ) : ( title @@ -84,6 +86,7 @@ EventCell.propTypes = { event: PropTypes.object.isRequired, slotStart: PropTypes.instanceOf(Date), slotEnd: PropTypes.instanceOf(Date), + type: PropTypes.string, resizable: PropTypes.bool, selected: PropTypes.bool, diff --git a/src/EventEndingRow.js b/src/EventEndingRow.js index cba0a2252..a60f8bf6d 100644 --- a/src/EventEndingRow.js +++ b/src/EventEndingRow.js @@ -4,6 +4,7 @@ import EventRowMixin from './EventRowMixin' import { eventLevels } from './utils/eventLevels' import range from 'lodash/range' import ShowMoreButton from './ShowMoreButton' +import EventCell from './EventCell' let isSegmentInSlot = (seg, slot) => seg.left <= slot && seg.right >= slot let eventsInSlot = (segments, slot) => @@ -75,9 +76,17 @@ class EventEndingRow extends React.Component { } renderShowMore(segments, slot) { - let { localizer, components, getEvents } = this.props + let { + localizer, + components, + getEvents, + getters, + accessors, + onSelect, + onDoubleClick, + onKeyPress, + } = this.props let count = eventsInSlot(segments, slot) - const key = 'sm_' + slot const onClick = e => this.showMore(slot, e) const events = getEvents(slot) @@ -90,7 +99,22 @@ class EventEndingRow extends React.Component { events={events} label={label} extraEventsCount={count} - /> + > + {events.map((event, index) => ( + + ))} +
) : ( false ) diff --git a/typings.d.ts b/typings.d.ts index 8e3e8f68e..fdd40c72b 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -102,6 +102,7 @@ export interface Event { start?: Date end?: Date resource?: any + isInPopup?: boolean } export interface DateRange { start: Date @@ -205,8 +206,9 @@ export interface DateFooterProps { } export interface ShowMoreButtonProps { - onClick: () => void - events: TEvent[] + onClick: () => void //Use this to implement the default behavior + events: TEvent[] // Use this to entirely customize the popup + children: ReactElement[] // Use this to customize the popup but retain events behaviors label: string extraEventsCount: number } From 3f31ce5564f8eea284380097f3dce137474c9029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 12 Mar 2021 12:09:11 +0700 Subject: [PATCH 33/60] build: implement children as event cells for show more buttons --- .size-snapshot.json | 22 +++++++++++----------- lib/EventCell.js | 4 ++++ lib/EventEndingRow.js | 40 ++++++++++++++++++++++++++++++++-------- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 534b76762..588d4cfd6 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 496877, - "minified": 155792, - "gzipped": 47546 + "bundled": 497629, + "minified": 156081, + "gzipped": 47654 }, "./dist/react-big-calendar.min.js": { - "bundled": 423825, - "minified": 132027, - "gzipped": 41561 + "bundled": 424549, + "minified": 132302, + "gzipped": 41659 }, "dist/react-big-calendar.esm.js": { - "bundled": 186678, - "minified": 88706, - "gzipped": 21861, + "bundled": 187379, + "minified": 89014, + "gzipped": 21946, "treeshaked": { "rollup": { - "code": 63382, + "code": 63657, "import_statements": 1555 }, "webpack": { - "code": 67944 + "code": 68221 } } } diff --git a/lib/EventCell.js b/lib/EventCell.js index d61dafed6..b86e1f1a2 100644 --- a/lib/EventCell.js +++ b/lib/EventCell.js @@ -40,6 +40,7 @@ var EventCell = _proto.render = function render() { var _this$props = this.props, + type = _this$props.type, style = _this$props.style, className = _this$props.className, event = _this$props.event, @@ -60,6 +61,7 @@ var EventCell = slotStart = _this$props.slotStart, slotEnd = _this$props.slotEnd, props = (0, _objectWithoutPropertiesLoose2.default)(_this$props, [ + 'type', 'style', 'className', 'event', @@ -106,6 +108,7 @@ var EventCell = localizer: localizer, slotStart: slotStart, slotEnd: slotEnd, + isInPopup: type == 'popup', }) : title ) @@ -155,6 +158,7 @@ EventCell.propTypes = event: _propTypes.default.object.isRequired, slotStart: _propTypes.default.instanceOf(Date), slotEnd: _propTypes.default.instanceOf(Date), + type: _propTypes.default.string, resizable: _propTypes.default.bool, selected: _propTypes.default.bool, isAllDay: _propTypes.default.bool, diff --git a/lib/EventEndingRow.js b/lib/EventEndingRow.js index 2e12a42a9..41b377d78 100644 --- a/lib/EventEndingRow.js +++ b/lib/EventEndingRow.js @@ -25,6 +25,8 @@ var _range = _interopRequireDefault(require('lodash/range')) var _ShowMoreButton = _interopRequireDefault(require('./ShowMoreButton')) +var _EventCell = _interopRequireDefault(require('./EventCell')) + var isSegmentInSlot = function isSegmentInSlot(seg, slot) { return seg.left <= slot && seg.right >= slot } @@ -127,7 +129,12 @@ var EventEndingRow = var _this$props2 = this.props, localizer = _this$props2.localizer, components = _this$props2.components, - getEvents = _this$props2.getEvents + getEvents = _this$props2.getEvents, + getters = _this$props2.getters, + accessors = _this$props2.accessors, + onSelect = _this$props2.onSelect, + onDoubleClick = _this$props2.onDoubleClick, + onKeyPress = _this$props2.onKeyPress var count = eventsInSlot(segments, slot) var key = 'sm_' + slot @@ -139,13 +146,30 @@ var EventEndingRow = var label = localizer.messages.showMore(count) var ShowMore = components.showMoreButton || _ShowMoreButton.default return count - ? _react.default.createElement(ShowMore, { - key: key, - onClick: onClick, - events: events, - label: label, - extraEventsCount: count, - }) + ? _react.default.createElement( + ShowMore, + { + key: key, + onClick: onClick, + events: events, + label: label, + extraEventsCount: count, + }, + events.map(function(event, index) { + return _react.default.createElement(_EventCell.default, { + key: index, + type: 'popup', + event: event, + getters: getters, + onSelect: onSelect, + accessors: accessors, + components: components, + onDoubleClick: onDoubleClick, + onKeyPress: onKeyPress, + draggable: true, + }) + }) + ) : false } From 688f02dd6cd77a4b101efb560a7feb0a21e98a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 12 Mar 2021 13:14:34 +0700 Subject: [PATCH 34/60] feature: add date of the selected day to show more button --- examples/demos/rendering.js | 10 ++-------- src/DateContentRow.js | 4 +++- src/EventCell.js | 1 - src/EventEndingRow.js | 3 ++- typings.d.ts | 1 + 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index cffb46d4d..2af528003 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -58,14 +58,8 @@ const CalendarFooter = ({ label }) => { ) } -const ShowMoreButton = ({ label, events, children }) => { - return ( -
- POPUP - {children} -
- ) - // return +const ShowMoreButton = ({ label, events, children, date }) => { + return } let Rendering = ({ localizer }) => { diff --git a/src/DateContentRow.js b/src/DateContentRow.js index 331236e09..dd7e18459 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -39,9 +39,11 @@ class DateContentRow extends React.Component { } getEvents = slot => { + const { range } = this.props + const metrics = this.slotMetrics(this.props) const events = metrics.getEventsForSlot(slot) - return events + return { events, date: range[slot - 1] } } createHeadingRef = r => { diff --git a/src/EventCell.js b/src/EventCell.js index dfdcdea71..609985f66 100644 --- a/src/EventCell.js +++ b/src/EventCell.js @@ -38,7 +38,6 @@ class EventCell extends React.Component { isAllDay || allDay || dates.diff(start, dates.ceil(end, 'day'), 'day') > 1 let userProps = getters.eventProp(event, start, end, selected) - const content = (
{Event ? ( diff --git a/src/EventEndingRow.js b/src/EventEndingRow.js index a60f8bf6d..f9c2a2c43 100644 --- a/src/EventEndingRow.js +++ b/src/EventEndingRow.js @@ -89,7 +89,7 @@ class EventEndingRow extends React.Component { let count = eventsInSlot(segments, slot) const key = 'sm_' + slot const onClick = e => this.showMore(slot, e) - const events = getEvents(slot) + const { events, date } = getEvents(slot) const label = localizer.messages.showMore(count) const ShowMore = components.showMoreButton || ShowMoreButton return count ? ( @@ -97,6 +97,7 @@ class EventEndingRow extends React.Component { key={key} onClick={onClick} events={events} + date={date} label={label} extraEventsCount={count} > diff --git a/typings.d.ts b/typings.d.ts index fdd40c72b..16f798336 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -209,6 +209,7 @@ export interface ShowMoreButtonProps { onClick: () => void //Use this to implement the default behavior events: TEvent[] // Use this to entirely customize the popup children: ReactElement[] // Use this to customize the popup but retain events behaviors + date: Date // date of the day selected label: string extraEventsCount: number } From d20a6bc81392852afa2896253881079be790f8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 12 Mar 2021 13:15:00 +0700 Subject: [PATCH 35/60] build: add date to selected day to show more button --- .size-snapshot.json | 22 +++++++++++----------- lib/DateContentRow.js | 7 ++++++- lib/EventEndingRow.js | 6 +++++- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 588d4cfd6..90907457d 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 497629, - "minified": 156081, - "gzipped": 47654 + "bundled": 497829, + "minified": 156148, + "gzipped": 47681 }, "./dist/react-big-calendar.min.js": { - "bundled": 424549, - "minified": 132302, - "gzipped": 41659 + "bundled": 424749, + "minified": 132369, + "gzipped": 41683 }, "dist/react-big-calendar.esm.js": { - "bundled": 187379, - "minified": 89014, - "gzipped": 21946, + "bundled": 187565, + "minified": 89081, + "gzipped": 21972, "treeshaked": { "rollup": { - "code": 63657, + "code": 63724, "import_statements": 1555 }, "webpack": { - "code": 68221 + "code": 68288 } } } diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js index 01f9fa003..b4312d6af 100644 --- a/lib/DateContentRow.js +++ b/lib/DateContentRow.js @@ -97,10 +97,15 @@ var DateContentRow = } _this.getEvents = function(slot) { + var range = _this.props.range + var metrics = _this.slotMetrics(_this.props) var events = metrics.getEventsForSlot(slot) - return events + return { + events: events, + date: range[slot - 1], + } } _this.createHeadingRef = function(r) { diff --git a/lib/EventEndingRow.js b/lib/EventEndingRow.js index 41b377d78..4116c0c06 100644 --- a/lib/EventEndingRow.js +++ b/lib/EventEndingRow.js @@ -142,7 +142,10 @@ var EventEndingRow = return _this.showMore(slot, e) } - var events = getEvents(slot) + var _getEvents = getEvents(slot), + events = _getEvents.events, + date = _getEvents.date + var label = localizer.messages.showMore(count) var ShowMore = components.showMoreButton || _ShowMoreButton.default return count @@ -152,6 +155,7 @@ var EventEndingRow = key: key, onClick: onClick, events: events, + date: date, label: label, extraEventsCount: count, }, From 31a7c281ea20c69ce03c656dc4a7bd130fb78b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 12 Mar 2021 13:31:07 +0700 Subject: [PATCH 36/60] fix: typings --- typings.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings.d.ts b/typings.d.ts index 16f798336..3290a936c 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -102,7 +102,6 @@ export interface Event { start?: Date end?: Date resource?: any - isInPopup?: boolean } export interface DateRange { start: Date @@ -282,6 +281,7 @@ export interface ToolbarProps< export interface EventProps { event: TEvent title: string + isInPopup?: boolean } export interface EventWrapperProps { From 785299d372f7380f78ae65354fb50e3406092499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 19 Mar 2021 16:11:37 +0700 Subject: [PATCH 37/60] feature: add daily status to calendar --- examples/dailyStatuses.js | 22 ++++++++++++++++++++++ examples/demos/rendering.js | 12 ++++++++++-- src/Month.js | 19 +++++++++++++++++-- typings.d.ts | 3 ++- 4 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 examples/dailyStatuses.js diff --git a/examples/dailyStatuses.js b/examples/dailyStatuses.js new file mode 100644 index 000000000..e34020a8c --- /dev/null +++ b/examples/dailyStatuses.js @@ -0,0 +1,22 @@ +function getRandomInt(arrayLength) { + return Math.floor(Math.random() * Math.floor(arrayLength - 1)) +} + +const openingTimes = ['Regular', 'Non-Regular', 'Spare', 'Closed'] +const repeatCondition = ['Doesnt Repeat', 'Weekly Until', 'Daily Until'] + +var times = 35 +let dailyStatuses = [] + +for (var i = 0; i < times; i++) { + const newOpeningTimes = { + id: i, + openingStatus: openingTimes[getRandomInt(openingTimes.length)], + repeatCondition: repeatCondition[getRandomInt(repeatCondition.length)], + start: new Date(2015, 3, i), + end: new Date(2015, 3, i), + } + dailyStatuses.push(newOpeningTimes) +} + +export default dailyStatuses diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index 2af528003..5b6f8fbcb 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -1,6 +1,7 @@ import React, { Children, useEffect, useState } from 'react' import { Calendar, Views } from 'react-big-calendar' import events from '../events' +import dailyStatuses from '../dailyStatuses' function Event({ event }) { return ( @@ -48,8 +49,14 @@ const ColoredEventWrapper = ({ children, event }) => { }, }) } -const CalendarHeader = ({ label }) => { - return
{label}
+const CalendarHeader = ({ label, dailyStatus }) => { + return ( +
+

+ {label} - {dailyStatus.openingStatus} +

+
+ ) } const CalendarFooter = ({ label }) => { return ( @@ -73,6 +80,7 @@ let Rendering = ({ localizer }) => { return ( evts.filter(e => inRange(e, start, end, accessors)) +class DateWithStatus extends Date { + constructor(date, dailyStatus) { + super(date) + this.dailyStatus = dailyStatus + } +} class MonthView extends React.Component { constructor(...args) { super(...args) @@ -74,10 +80,17 @@ class MonthView extends React.Component { } render() { - let { date, localizer, className } = this.props, - month = dates.visibleDays(date, localizer), + let { date, localizer, className, dailyStatuses } = this.props, + month = dates.visibleDays(date, localizer).map((monthDate, index) => { + return new DateWithStatus(monthDate, dailyStatuses[index]) + }), weeks = chunk(month, 7) + if (dailyStatuses.length != month.length) { + console.warn(`react-big-calendar: dailyStatuses length is not matching the visible days on calendar. + Make sure ${dailyStatuses} and ${month} matches so that the data is correctly displayed + `) + } this._weekCount = weeks.length return ( @@ -169,6 +182,7 @@ class MonthView extends React.Component { role="cell" > { + dailyStatus: TDailyStatus label: string date: Date isOffRange: boolean From 70f0ad8e0ae0af11cd0b8fe63974dc8b40aca0a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 19 Mar 2021 16:28:16 +0700 Subject: [PATCH 38/60] build: add daily status to calendar --- .size-snapshot.json | 24 ++--- lib/Month.js | 238 +++++++++++++++++++++++++------------------- 2 files changed, 150 insertions(+), 112 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 90907457d..3181f2354 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 497829, - "minified": 156148, - "gzipped": 47681 + "bundled": 501142, + "minified": 157760, + "gzipped": 48224 }, "./dist/react-big-calendar.min.js": { - "bundled": 424749, - "minified": 132369, - "gzipped": 41683 + "bundled": 428015, + "minified": 134001, + "gzipped": 42231 }, "dist/react-big-calendar.esm.js": { - "bundled": 187565, - "minified": 89081, - "gzipped": 21972, + "bundled": 188558, + "minified": 89658, + "gzipped": 22187, "treeshaked": { "rollup": { - "code": 63724, - "import_statements": 1555 + "code": 64195, + "import_statements": 1614 }, "webpack": { - "code": 68288 + "code": 68803 } } } diff --git a/lib/Month.js b/lib/Month.js index 3f806cc39..9dce233dd 100644 --- a/lib/Month.js +++ b/lib/Month.js @@ -23,6 +23,10 @@ var _inheritsLoose2 = _interopRequireDefault( require('@babel/runtime/helpers/inheritsLoose') ) +var _wrapNativeSuper2 = _interopRequireDefault( + require('@babel/runtime/helpers/wrapNativeSuper') +) + var _propTypes = _interopRequireDefault(require('prop-types')) var _react = _interopRequireDefault(require('react')) @@ -65,13 +69,29 @@ var eventsForWeek = function eventsForWeek(evts, start, end, accessors) { }) } +var DateWithStatus = + /*#__PURE__*/ + (function(_Date) { + ;(0, _inheritsLoose2.default)(DateWithStatus, _Date) + + function DateWithStatus(date, dailyStatus) { + var _this + + _this = _Date.call(this, date) || this + _this.dailyStatus = dailyStatus + return _this + } + + return DateWithStatus + })((0, _wrapNativeSuper2.default)(Date)) + var MonthView = /*#__PURE__*/ (function(_React$Component) { ;(0, _inheritsLoose2.default)(MonthView, _React$Component) function MonthView() { - var _this + var _this2 for ( var _len = arguments.length, _args = new Array(_len), _key = 0; @@ -81,32 +101,32 @@ var MonthView = _args[_key] = arguments[_key] } - _this = + _this2 = _React$Component.call.apply(_React$Component, [this].concat(_args)) || this - _this.getContainer = function() { + _this2.getContainer = function() { return (0, _reactDom.findDOMNode)( - (0, _assertThisInitialized2.default)(_this) + (0, _assertThisInitialized2.default)(_this2) ) } - _this.renderWeek = function(week, weekIdx) { - var _this$props = _this.props, - events = _this$props.events, - components = _this$props.components, - selectable = _this$props.selectable, - getNow = _this$props.getNow, - selected = _this$props.selected, - date = _this$props.date, - localizer = _this$props.localizer, - longPressThreshold = _this$props.longPressThreshold, - accessors = _this$props.accessors, - getters = _this$props.getters, - showAllEvents = _this$props.showAllEvents - var _this$state = _this.state, - needLimitMeasure = _this$state.needLimitMeasure, - rowLimit = _this$state.rowLimit + _this2.renderWeek = function(week, weekIdx) { + var _this2$props = _this2.props, + events = _this2$props.events, + components = _this2$props.components, + selectable = _this2$props.selectable, + getNow = _this2$props.getNow, + selected = _this2$props.selected, + date = _this2$props.date, + localizer = _this2$props.localizer, + longPressThreshold = _this2$props.longPressThreshold, + accessors = _this2$props.accessors, + getters = _this2$props.getters, + showAllEvents = _this2$props.showAllEvents + var _this2$state = _this2.state, + needLimitMeasure = _this2$state.needLimitMeasure, + rowLimit = _this2$state.rowLimit events = eventsForWeek( events, week[0], @@ -118,8 +138,8 @@ var MonthView = }) return _react.default.createElement(_DateContentRow.default, { key: weekIdx, - ref: weekIdx === 0 ? _this.slotRowRef : undefined, - container: _this.getContainer, + ref: weekIdx === 0 ? _this2.slotRowRef : undefined, + container: _this2.getContainer, className: 'rbc-month-row', getNow: getNow, date: date, @@ -132,38 +152,38 @@ var MonthView = accessors: accessors, getters: getters, localizer: localizer, - renderHeader: _this.readerDateHeading, - renderFooter: _this.renderDateFooter, + renderHeader: _this2.readerDateHeading, + renderFooter: _this2.renderDateFooter, renderForMeasure: needLimitMeasure, - onShowMore: _this.handleShowMore, - onSelect: _this.handleSelectEvent, - onDoubleClick: _this.handleDoubleClickEvent, - onKeyPress: _this.handleKeyPressEvent, - onSelectSlot: _this.handleSelectSlot, + onShowMore: _this2.handleShowMore, + onSelect: _this2.handleSelectEvent, + onDoubleClick: _this2.handleDoubleClickEvent, + onKeyPress: _this2.handleKeyPressEvent, + onSelectSlot: _this2.handleSelectSlot, longPressThreshold: longPressThreshold, - rtl: _this.props.rtl, - resizable: _this.props.resizable, + rtl: _this2.props.rtl, + resizable: _this2.props.resizable, showAllEvents: showAllEvents, }) } - _this.readerDateHeading = function(_ref) { + _this2.readerDateHeading = function(_ref) { var date = _ref.date, className = _ref.className, props = (0, _objectWithoutPropertiesLoose2.default)(_ref, [ 'date', 'className', ]) - var _this$props2 = _this.props, - currentDate = _this$props2.date, - getDrilldownView = _this$props2.getDrilldownView, - localizer = _this$props2.localizer + var _this2$props2 = _this2.props, + currentDate = _this2$props2.date, + getDrilldownView = _this2$props2.getDrilldownView, + localizer = _this2$props2.localizer var isOffRange = dates.month(date) !== dates.month(currentDate) var isCurrent = dates.eq(date, currentDate, 'day') var drilldownView = getDrilldownView(date) var label = localizer.format(date, 'dateFormat') var DateHeaderComponent = - _this.props.components.dateHeader || _DateHeader.default + _this2.props.components.dateHeader || _DateHeader.default return _react.default.createElement( 'div', (0, _extends2.default)({}, props, { @@ -175,31 +195,32 @@ var MonthView = role: 'cell', }), _react.default.createElement(DateHeaderComponent, { + dailyStatus: date.dailyStatus, label: label, date: date, drilldownView: drilldownView, isOffRange: isOffRange, onDrillDown: function onDrillDown(e) { - return _this.handleHeadingClick(date, drilldownView, e) + return _this2.handleHeadingClick(date, drilldownView, e) }, }) ) } - _this.renderDateFooter = function(_ref2) { + _this2.renderDateFooter = function(_ref2) { var date = _ref2.date, className = _ref2.className, props = (0, _objectWithoutPropertiesLoose2.default)(_ref2, [ 'date', 'className', ]) - var _this$props3 = _this.props, - currentDate = _this$props3.date, - localizer = _this$props3.localizer + var _this2$props3 = _this2.props, + currentDate = _this2$props3.date, + localizer = _this2$props3.localizer var isOffRange = dates.month(date) !== dates.month(currentDate) var isCurrent = dates.eq(date, currentDate, 'day') var DateFooterComponent = - _this.props.components.dateFooter || _DateFooter.default + _this2.props.components.dateFooter || _DateFooter.default var label = localizer.format(date, 'dateFormat') return _react.default.createElement( 'div', @@ -219,24 +240,24 @@ var MonthView = ) } - _this.handleSelectSlot = function(range, slotInfo) { - _this._pendingSelection = _this._pendingSelection.concat(range) - clearTimeout(_this._selectTimer) - _this._selectTimer = setTimeout(function() { - return _this.selectDates(slotInfo) + _this2.handleSelectSlot = function(range, slotInfo) { + _this2._pendingSelection = _this2._pendingSelection.concat(range) + clearTimeout(_this2._selectTimer) + _this2._selectTimer = setTimeout(function() { + return _this2.selectDates(slotInfo) }) } - _this.handleHeadingClick = function(date, view, e) { + _this2.handleHeadingClick = function(date, view, e) { e.preventDefault() - _this.clearSelection() + _this2.clearSelection() - ;(0, _helpers.notify)(_this.props.onDrillDown, [date, view]) + ;(0, _helpers.notify)(_this2.props.onDrillDown, [date, view]) } - _this.handleSelectEvent = function() { - _this.clearSelection() + _this2.handleSelectEvent = function() { + _this2.clearSelection() for ( var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; @@ -246,11 +267,11 @@ var MonthView = args[_key2] = arguments[_key2] } - ;(0, _helpers.notify)(_this.props.onSelectEvent, args) + ;(0, _helpers.notify)(_this2.props.onSelectEvent, args) } - _this.handleDoubleClickEvent = function() { - _this.clearSelection() + _this2.handleDoubleClickEvent = function() { + _this2.clearSelection() for ( var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; @@ -260,11 +281,11 @@ var MonthView = args[_key3] = arguments[_key3] } - ;(0, _helpers.notify)(_this.props.onDoubleClickEvent, args) + ;(0, _helpers.notify)(_this2.props.onDoubleClickEvent, args) } - _this.handleKeyPressEvent = function() { - _this.clearSelection() + _this2.handleKeyPressEvent = function() { + _this2.clearSelection() for ( var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; @@ -274,27 +295,27 @@ var MonthView = args[_key4] = arguments[_key4] } - ;(0, _helpers.notify)(_this.props.onKeyPressEvent, args) + ;(0, _helpers.notify)(_this2.props.onKeyPressEvent, args) } - _this.handleShowMore = function(events, date, cell, slot, target) { - var _this$props4 = _this.props, - popup = _this$props4.popup, - onDrillDown = _this$props4.onDrillDown, - onShowMore = _this$props4.onShowMore, - getDrilldownView = _this$props4.getDrilldownView //cancel any pending selections so only the event click goes through. + _this2.handleShowMore = function(events, date, cell, slot, target) { + var _this2$props4 = _this2.props, + popup = _this2$props4.popup, + onDrillDown = _this2$props4.onDrillDown, + onShowMore = _this2$props4.onShowMore, + getDrilldownView = _this2$props4.getDrilldownView //cancel any pending selections so only the event click goes through. - _this.clearSelection() + _this2.clearSelection() if (popup) { var position = (0, _position.default)( cell, (0, _reactDom.findDOMNode)( - (0, _assertThisInitialized2.default)(_this) + (0, _assertThisInitialized2.default)(_this2) ) ) - _this.setState({ + _this2.setState({ overlay: { date: date, events: events, @@ -312,20 +333,20 @@ var MonthView = ;(0, _helpers.notify)(onShowMore, [events, date, slot]) } - _this.overlayDisplay = function() { - _this.setState({ + _this2.overlayDisplay = function() { + _this2.setState({ overlay: null, }) } - _this._bgRows = [] - _this._pendingSelection = [] - _this.slotRowRef = _react.default.createRef() - _this.state = { + _this2._bgRows = [] + _this2._pendingSelection = [] + _this2.slotRowRef = _react.default.createRef() + _this2.state = { rowLimit: 5, needLimitMeasure: true, } - return _this + return _this2 } var _proto = MonthView.prototype @@ -340,7 +361,7 @@ var MonthView = } _proto.componentDidMount = function componentDidMount() { - var _this2 = this + var _this3 = this var running if (this.state.needLimitMeasure) this.measureRowLimit(this.props) @@ -351,7 +372,7 @@ var MonthView = animationFrame.request(function() { running = false - _this2.setState({ + _this3.setState({ needLimitMeasure: true, }) //eslint-disable-line }) @@ -370,12 +391,28 @@ var MonthView = } _proto.render = function render() { - var _this$props5 = this.props, - date = _this$props5.date, - localizer = _this$props5.localizer, - className = _this$props5.className, - month = dates.visibleDays(date, localizer), + var _this$props = this.props, + date = _this$props.date, + localizer = _this$props.localizer, + className = _this$props.className, + dailyStatuses = _this$props.dailyStatuses, + month = dates + .visibleDays(date, localizer) + .map(function(monthDate, index) { + return new DateWithStatus(monthDate, dailyStatuses[index]) + }), weeks = (0, _chunk.default)(month, 7) + + if (dailyStatuses.length != month.length) { + console.warn( + 'react-big-calendar: dailyStatuses length is not matching the visible days on calendar. \n Make sure ' + + dailyStatuses + + ' and ' + + month + + ' matches so that the data is correctly displayed\n ' + ) + } + this._weekCount = weeks.length return _react.default.createElement( 'div', @@ -398,9 +435,9 @@ var MonthView = } _proto.renderHeaders = function renderHeaders(row) { - var _this$props6 = this.props, - localizer = _this$props6.localizer, - components = _this$props6.components + var _this$props2 = this.props, + localizer = _this$props2.localizer, + components = _this$props2.components var first = row[0] var last = row[row.length - 1] var HeaderComponent = components.header || _Header.default @@ -421,16 +458,16 @@ var MonthView = } _proto.renderOverlay = function renderOverlay() { - var _this3 = this + var _this4 = this var overlay = (this.state && this.state.overlay) || {} - var _this$props7 = this.props, - accessors = _this$props7.accessors, - localizer = _this$props7.localizer, - components = _this$props7.components, - getters = _this$props7.getters, - selected = _this$props7.selected, - popupOffset = _this$props7.popupOffset + var _this$props3 = this.props, + accessors = _this$props3.accessors, + localizer = _this$props3.localizer, + components = _this$props3.components, + getters = _this$props3.getters, + selected = _this$props3.selected, + popupOffset = _this$props3.popupOffset return _react.default.createElement( _Overlay.default, { @@ -438,7 +475,7 @@ var MonthView = placement: 'bottom', show: !!overlay.position, onHide: function onHide() { - return _this3.setState({ + return _this4.setState({ overlay: null, }) }, @@ -458,14 +495,14 @@ var MonthView = components: components, localizer: localizer, position: overlay.position, - show: _this3.overlayDisplay, + show: _this4.overlayDisplay, events: overlay.events, slotStart: overlay.date, slotEnd: overlay.end, - onSelect: _this3.handleSelectEvent, - onDoubleClick: _this3.handleDoubleClickEvent, - onKeyPress: _this3.handleKeyPressEvent, - handleDragStart: _this3.props.handleDragStart, + onSelect: _this4.handleSelectEvent, + onDoubleClick: _this4.handleDoubleClickEvent, + onKeyPress: _this4.handleKeyPressEvent, + handleDragStart: _this4.props.handleDragStart, }) ) } @@ -508,6 +545,7 @@ MonthView.propTypes = process.env.NODE_ENV !== 'production' ? { events: _propTypes.default.array.isRequired, + dailyStatuses: _propTypes.default.array.isRequired, date: _propTypes.default.instanceOf(Date), min: _propTypes.default.instanceOf(Date), max: _propTypes.default.instanceOf(Date), From 6a0017914693c02f14b5b30616ddc2354b3b4700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 19 Mar 2021 16:55:22 +0700 Subject: [PATCH 39/60] feature: Add typings for dailyStatus --- typings.d.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/typings.d.ts b/typings.d.ts index 4420530c3..84b79b632 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -228,6 +228,7 @@ export interface ResourceHeaderProps { export interface Components< TEvent extends object = Event, + TDailyStatus extends object = object, TResource extends object = object > { event?: React.ComponentType> @@ -253,7 +254,7 @@ export interface Components< } month?: { header?: React.ComponentType - dateHeader?: React.ComponentType + dateHeader?: React.ComponentType> dateFooter?: React.ComponentType event?: React.ComponentType> showMoreButton?: React.ComponentType> @@ -354,14 +355,16 @@ export class DateLocalizer { export interface CalendarProps< TEvent extends object = Event, + TDailyStatus extends object = object, TResource extends object = object -> extends React.Props> { +> extends React.Props> { localizer: DateLocalizer date?: stringOrDate getNow?: () => Date view?: View events?: TEvent[] + dailyStatuses?: TDailyStatus[] handleDragStart?: (event: TEvent) => void onNavigate?: (newDate: Date, view: View, action: NavigateAction) => void onView?: (view: View) => void @@ -458,8 +461,9 @@ export interface MoveOptions { export class Calendar< TEvent extends object = Event, + TDailyStatus extends object = object, TResource extends object = object -> extends React.Component> {} +> extends React.Component> {} export interface components { dateCellWrapper: React.ComponentType From b42586db91675d860cd5192c803733c28695c354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Tue, 23 Mar 2021 16:12:56 +0700 Subject: [PATCH 40/60] feature: export functions for first and last visible day --- src/index.js | 1 + typings.d.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/index.js b/src/index.js index e61687a38..2f912e80c 100644 --- a/src/index.js +++ b/src/index.js @@ -14,3 +14,4 @@ export { default as globalizeLocalizer } from './localizers/globalize' export { default as dateFnsLocalizer } from './localizers/date-fns' export { default as move } from './utils/move' export { views as Views, navigate as Navigate } from './utils/constants' +export { firstVisibleDay, lastVisibleDay } from './utils/dates' diff --git a/typings.d.ts b/typings.d.ts index 84b79b632..6df55d696 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -563,5 +563,8 @@ export interface DayProps { } export class Day extends React.Component {} +export function firstVisibleDay(date: Date, localizer: any): Date +export function lastVisibleDay(date: Date, localizer: any): Date + // Turn off automatic exports export {} From ed2a33be759539734ad8120c615e00602123f1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Tue, 23 Mar 2021 16:13:12 +0700 Subject: [PATCH 41/60] build: export functions for first and last visible day --- .size-snapshot.json | 18 +++++++++--------- examples/demos/rendering.js | 4 ++-- lib/index.js | 7 ++++++- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 3181f2354..d252ae457 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,18 +1,18 @@ { "./dist/react-big-calendar.js": { - "bundled": 501142, - "minified": 157760, - "gzipped": 48224 + "bundled": 501230, + "minified": 157801, + "gzipped": 48245 }, "./dist/react-big-calendar.min.js": { - "bundled": 428015, - "minified": 134001, - "gzipped": 42231 + "bundled": 428103, + "minified": 134042, + "gzipped": 42253 }, "dist/react-big-calendar.esm.js": { - "bundled": 188558, - "minified": 89658, - "gzipped": 22187, + "bundled": 188591, + "minified": 89689, + "gzipped": 22199, "treeshaked": { "rollup": { "code": 64195, diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index 5b6f8fbcb..a21790a06 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -1,5 +1,5 @@ import React, { Children, useEffect, useState } from 'react' -import { Calendar, Views } from 'react-big-calendar' +import { Calendar, Views, firstVisibleDay } from 'react-big-calendar' import events from '../events' import dailyStatuses from '../dailyStatuses' @@ -71,7 +71,7 @@ const ShowMoreButton = ({ label, events, children, date }) => { let Rendering = ({ localizer }) => { const [localEvents, setEvents] = useState([]) - + console.log(firstVisibleDay(new Date(), localizer)) useEffect(() => { const allDayEvents = events.filter(event => event.allDay) const notAllDayEvents = events.filter(event => !event.allDay) diff --git a/lib/index.js b/lib/index.js index b7f74d242..c7f77b026 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,7 +3,7 @@ var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') exports.__esModule = true -exports.Navigate = exports.Views = exports.DateLocalizer = exports.move = exports.dateFnsLocalizer = exports.globalizeLocalizer = exports.momentLocalizer = exports.Calendar = exports.components = void 0 +exports.lastVisibleDay = exports.firstVisibleDay = exports.Navigate = exports.Views = exports.DateLocalizer = exports.move = exports.dateFnsLocalizer = exports.globalizeLocalizer = exports.momentLocalizer = exports.Calendar = exports.components = void 0 var _EventWrapper = _interopRequireDefault(require('./EventWrapper')) @@ -37,6 +37,11 @@ var _constants = require('./utils/constants') exports.Views = _constants.views exports.Navigate = _constants.navigate + +var _dates = require('./utils/dates') + +exports.firstVisibleDay = _dates.firstVisibleDay +exports.lastVisibleDay = _dates.lastVisibleDay var components = { eventWrapper: _EventWrapper.default, timeSlotWrapper: _BackgroundWrapper.default, From 99b5b6b04e4bb77ed2ef769a311066d1bfe3d1fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 24 Mar 2021 10:49:27 +0700 Subject: [PATCH 42/60] fix: map daily status with monthdate appropriately --- src/Month.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Month.js b/src/Month.js index 511e6c53c..1627e2490 100644 --- a/src/Month.js +++ b/src/Month.js @@ -81,16 +81,14 @@ class MonthView extends React.Component { render() { let { date, localizer, className, dailyStatuses } = this.props, - month = dates.visibleDays(date, localizer).map((monthDate, index) => { - return new DateWithStatus(monthDate, dailyStatuses[index]) + month = dates.visibleDays(date, localizer).map(monthDate => { + const dailyStatus = dailyStatuses.find( + status => status.start == monthDate + ) + return new DateWithStatus(monthDate, dailyStatus) }), weeks = chunk(month, 7) - if (dailyStatuses.length != month.length) { - console.warn(`react-big-calendar: dailyStatuses length is not matching the visible days on calendar. - Make sure ${dailyStatuses} and ${month} matches so that the data is correctly displayed - `) - } this._weekCount = weeks.length return ( From 55dda13163e402b1e3d9c0b178113e124f7229d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 24 Mar 2021 10:50:05 +0700 Subject: [PATCH 43/60] build: map daily status with monthdate appropriately --- .size-snapshot.json | 22 +++++++++++----------- lib/Month.js | 22 ++++++---------------- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index d252ae457..9ff03ff36 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 501230, - "minified": 157801, - "gzipped": 48245 + "bundled": 501047, + "minified": 157622, + "gzipped": 48129 }, "./dist/react-big-calendar.min.js": { - "bundled": 428103, - "minified": 134042, - "gzipped": 42253 + "bundled": 427920, + "minified": 133863, + "gzipped": 42133 }, "dist/react-big-calendar.esm.js": { - "bundled": 188591, - "minified": 89689, - "gzipped": 22199, + "bundled": 188408, + "minified": 89514, + "gzipped": 22084, "treeshaked": { "rollup": { - "code": 64195, + "code": 64020, "import_statements": 1614 }, "webpack": { - "code": 68803 + "code": 68628 } } } diff --git a/lib/Month.js b/lib/Month.js index 9dce233dd..62a091965 100644 --- a/lib/Month.js +++ b/lib/Month.js @@ -396,23 +396,13 @@ var MonthView = localizer = _this$props.localizer, className = _this$props.className, dailyStatuses = _this$props.dailyStatuses, - month = dates - .visibleDays(date, localizer) - .map(function(monthDate, index) { - return new DateWithStatus(monthDate, dailyStatuses[index]) - }), + month = dates.visibleDays(date, localizer).map(function(monthDate) { + var dailyStatus = dailyStatuses.find(function(status) { + return status.start == monthDate + }) + return new DateWithStatus(monthDate, dailyStatus) + }), weeks = (0, _chunk.default)(month, 7) - - if (dailyStatuses.length != month.length) { - console.warn( - 'react-big-calendar: dailyStatuses length is not matching the visible days on calendar. \n Make sure ' + - dailyStatuses + - ' and ' + - month + - ' matches so that the data is correctly displayed\n ' - ) - } - this._weekCount = weeks.length return _react.default.createElement( 'div', From f37917b7e779d57806d4ea3a9353c944f5e9b176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 24 Mar 2021 11:00:33 +0700 Subject: [PATCH 44/60] fix: fix date comparison --- src/Month.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Month.js b/src/Month.js index 1627e2490..763a0f171 100644 --- a/src/Month.js +++ b/src/Month.js @@ -83,7 +83,7 @@ class MonthView extends React.Component { let { date, localizer, className, dailyStatuses } = this.props, month = dates.visibleDays(date, localizer).map(monthDate => { const dailyStatus = dailyStatuses.find( - status => status.start == monthDate + status => status.start.getTime() == monthDate.getTime() ) return new DateWithStatus(monthDate, dailyStatus) }), From f67a5b538f28dcc8f6a502ed185c85a1aee6e396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 24 Mar 2021 11:01:13 +0700 Subject: [PATCH 45/60] build: fix date comparison --- lib/Month.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Month.js b/lib/Month.js index 62a091965..6f6c160b9 100644 --- a/lib/Month.js +++ b/lib/Month.js @@ -398,7 +398,7 @@ var MonthView = dailyStatuses = _this$props.dailyStatuses, month = dates.visibleDays(date, localizer).map(function(monthDate) { var dailyStatus = dailyStatuses.find(function(status) { - return status.start == monthDate + return status.start.getTime() == monthDate.getTime() }) return new DateWithStatus(monthDate, dailyStatus) }), From c874feb2a92f8356996bfd75aa69cacde99c10c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 24 Mar 2021 11:01:27 +0700 Subject: [PATCH 46/60] build: fix date comparison --- .size-snapshot.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 9ff03ff36..11c5c27cb 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 501047, - "minified": 157622, - "gzipped": 48129 + "bundled": 501067, + "minified": 157642, + "gzipped": 48136 }, "./dist/react-big-calendar.min.js": { - "bundled": 427920, - "minified": 133863, - "gzipped": 42133 + "bundled": 427940, + "minified": 133883, + "gzipped": 42138 }, "dist/react-big-calendar.esm.js": { - "bundled": 188408, - "minified": 89514, - "gzipped": 22084, + "bundled": 188428, + "minified": 89534, + "gzipped": 22090, "treeshaked": { "rollup": { - "code": 64020, + "code": 64040, "import_statements": 1614 }, "webpack": { - "code": 68628 + "code": 68648 } } } From 5d6cfc22a0667496673aa639b53f125537d0155c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 24 Mar 2021 13:15:58 +0700 Subject: [PATCH 47/60] fix: fix date comparison to same day only --- examples/dailyStatuses.js | 2 +- examples/demos/rendering.js | 3 ++- src/Month.js | 4 ++-- src/utils/dates.js | 8 ++++++++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/dailyStatuses.js b/examples/dailyStatuses.js index e34020a8c..88096ff71 100644 --- a/examples/dailyStatuses.js +++ b/examples/dailyStatuses.js @@ -5,7 +5,7 @@ function getRandomInt(arrayLength) { const openingTimes = ['Regular', 'Non-Regular', 'Spare', 'Closed'] const repeatCondition = ['Doesnt Repeat', 'Weekly Until', 'Daily Until'] -var times = 35 +var times = 3 let dailyStatuses = [] for (var i = 0; i < times; i++) { diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index a21790a06..cfeb227b0 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -50,10 +50,11 @@ const ColoredEventWrapper = ({ children, event }) => { }) } const CalendarHeader = ({ label, dailyStatus }) => { + const openingStatus = dailyStatus ? dailyStatus.openingStatus : 'hehe' return (

- {label} - {dailyStatus.openingStatus} + {label} - {openingStatus}

) diff --git a/src/Month.js b/src/Month.js index 763a0f171..58abd9165 100644 --- a/src/Month.js +++ b/src/Month.js @@ -82,8 +82,8 @@ class MonthView extends React.Component { render() { let { date, localizer, className, dailyStatuses } = this.props, month = dates.visibleDays(date, localizer).map(monthDate => { - const dailyStatus = dailyStatuses.find( - status => status.start.getTime() == monthDate.getTime() + const dailyStatus = dailyStatuses.find(status => + dates.isSameDay(status.start, monthDate) ) return new DateWithStatus(monthDate, dailyStatus) }), diff --git a/src/utils/dates.js b/src/utils/dates.js index 7e6eabfa7..06df805b2 100644 --- a/src/utils/dates.js +++ b/src/utils/dates.js @@ -168,3 +168,11 @@ export function yesterday() { export function tomorrow() { return dates.add(dates.startOf(new Date(), 'day'), 1, 'day') } + +export function isSameDay(d1, d2) { + return ( + d1.getFullYear() === d2.getFullYear() && + d1.getMonth() === d2.getMonth() && + d1.getDate() === d2.getDate() + ) +} From 76affb9af4cb6525b095227961789b0619d1a597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Wed, 24 Mar 2021 13:16:31 +0700 Subject: [PATCH 48/60] build: fix date comparison to same day only --- .size-snapshot.json | 22 +++++++++++----------- lib/Month.js | 2 +- lib/utils/dates.js | 9 +++++++++ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 11c5c27cb..3f88bfc2d 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 501067, - "minified": 157642, - "gzipped": 48136 + "bundled": 501209, + "minified": 157723, + "gzipped": 48164 }, "./dist/react-big-calendar.min.js": { - "bundled": 427940, - "minified": 133883, - "gzipped": 42138 + "bundled": 428082, + "minified": 133964, + "gzipped": 42167 }, "dist/react-big-calendar.esm.js": { - "bundled": 188428, - "minified": 89534, - "gzipped": 22090, + "bundled": 188564, + "minified": 89645, + "gzipped": 22129, "treeshaked": { "rollup": { - "code": 64040, + "code": 64121, "import_statements": 1614 }, "webpack": { - "code": 68648 + "code": 68729 } } } diff --git a/lib/Month.js b/lib/Month.js index 6f6c160b9..63d8a7610 100644 --- a/lib/Month.js +++ b/lib/Month.js @@ -398,7 +398,7 @@ var MonthView = dailyStatuses = _this$props.dailyStatuses, month = dates.visibleDays(date, localizer).map(function(monthDate) { var dailyStatus = dailyStatuses.find(function(status) { - return status.start.getTime() == monthDate.getTime() + return dates.isSameDay(status.start, monthDate) }) return new DateWithStatus(monthDate, dailyStatus) }), diff --git a/lib/utils/dates.js b/lib/utils/dates.js index cced6b90e..1e27c634e 100644 --- a/lib/utils/dates.js +++ b/lib/utils/dates.js @@ -19,6 +19,7 @@ exports.week = week exports.today = today exports.yesterday = yesterday exports.tomorrow = tomorrow +exports.isSameDay = isSameDay exports.max = exports.min = exports.inRange = exports.lt = exports.lte = exports.gt = exports.gte = exports.eq = exports.add = exports.endOf = exports.startOf = exports.month = exports.hours = exports.minutes = exports.seconds = exports.milliseconds = void 0 var dates = _interopRequireWildcard(require('date-arithmetic')) @@ -191,3 +192,11 @@ function yesterday() { function tomorrow() { return dates.add(dates.startOf(new Date(), 'day'), 1, 'day') } + +function isSameDay(d1, d2) { + return ( + d1.getFullYear() === d2.getFullYear() && + d1.getMonth() === d2.getMonth() && + d1.getDate() === d2.getDate() + ) +} From 45435df9eb351db55df19e1db9c08b03ef0d7d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 26 Mar 2021 16:48:55 +0700 Subject: [PATCH 49/60] feature: implement utilities for components --- examples/demos/rendering.js | 15 ++++++++++++--- src/DateContentRow.js | 3 +++ src/EventCell.js | 3 +++ src/EventEndingRow.js | 2 ++ src/EventRowMixin.js | 2 ++ src/Month.js | 16 ++++++++++++++-- typings.d.ts | 26 ++++++++++++++++++-------- 7 files changed, 54 insertions(+), 13 deletions(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index cfeb227b0..f7e1391d9 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -3,7 +3,13 @@ import { Calendar, Views, firstVisibleDay } from 'react-big-calendar' import events from '../events' import dailyStatuses from '../dailyStatuses' -function Event({ event }) { +const utilities = { + onSaved: text => { + console.log(text) + }, +} +function Event({ event, utilities }) { + utilities && utilities.onSaved(`Utilities for Event ${event.title}`) return ( {event.title} @@ -49,7 +55,8 @@ const ColoredEventWrapper = ({ children, event }) => { }, }) } -const CalendarHeader = ({ label, dailyStatus }) => { +const CalendarHeader = ({ label, dailyStatus, utilities }) => { + utilities && utilities.onSaved('Utilities for Header') const openingStatus = dailyStatus ? dailyStatus.openingStatus : 'hehe' return (
@@ -59,7 +66,8 @@ const CalendarHeader = ({ label, dailyStatus }) => {
) } -const CalendarFooter = ({ label }) => { +const CalendarFooter = ({ label, utilities }) => { + utilities && utilities.onSaved('Utilities for Footer') return (
@@ -85,6 +93,7 @@ let Rendering = ({ localizer }) => { localizer={localizer} defaultDate={new Date(2015, 3, 1)} defaultView={Views.MONTH} + utilities={utilities} // dayPropGetter={customDayPropGetter} // slotPropGetter={customSlotPropGetter} popup diff --git a/src/DateContentRow.js b/src/DateContentRow.js index dd7e18459..743c68a19 100644 --- a/src/DateContentRow.js +++ b/src/DateContentRow.js @@ -161,6 +161,7 @@ class DateContentRow extends React.Component { isAllDay, resizable, showAllEvents, + utilities, } = this.props if (renderForMeasure) return this.renderDummy() @@ -185,6 +186,7 @@ class DateContentRow extends React.Component { resourceId, slotMetrics: metrics, resizable, + utilities, } return ( @@ -248,6 +250,7 @@ DateContentRow.propTypes = { date: PropTypes.instanceOf(Date), events: PropTypes.array.isRequired, range: PropTypes.array.isRequired, + utilities: PropTypes.object, rtl: PropTypes.bool, resizable: PropTypes.bool, diff --git a/src/EventCell.js b/src/EventCell.js index 609985f66..ff152502c 100644 --- a/src/EventCell.js +++ b/src/EventCell.js @@ -24,6 +24,7 @@ class EventCell extends React.Component { components: { event: Event, eventWrapper: EventWrapper }, slotStart, slotEnd, + utilities, ...props } = this.props delete props.resizable @@ -43,6 +44,7 @@ class EventCell extends React.Component { {Event ? ( { - let { date: currentDate, getDrilldownView, localizer } = this.props + let { + date: currentDate, + getDrilldownView, + localizer, + utilities, + } = this.props let isOffRange = dates.month(date) !== dates.month(currentDate) let isCurrent = dates.eq(date, currentDate, 'day') @@ -185,6 +192,8 @@ class MonthView extends React.Component { date={date} drilldownView={drilldownView} isOffRange={isOffRange} + isCurrent={isCurrent} + utilities={utilities} onDrillDown={e => this.handleHeadingClick(date, drilldownView, e)} />
@@ -192,7 +201,7 @@ class MonthView extends React.Component { } renderDateFooter = ({ date, className, ...props }) => { - let { date: currentDate, localizer } = this.props + let { date: currentDate, localizer, utilities } = this.props let isOffRange = dates.month(date) !== dates.month(currentDate) let isCurrent = dates.eq(date, currentDate, 'day') @@ -213,6 +222,8 @@ class MonthView extends React.Component { label={label} date={date} isOffRange={isOffRange} + isCurrent={isCurrent} + utilities={utilities} />
) @@ -361,6 +372,7 @@ class MonthView extends React.Component { } MonthView.propTypes = { + utilities: PropTypes.object, events: PropTypes.array.isRequired, dailyStatuses: PropTypes.array.isRequired, date: PropTypes.instanceOf(Date), diff --git a/typings.d.ts b/typings.d.ts index 6df55d696..1cd25e204 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -192,19 +192,22 @@ export interface Formats { eventTimeRangeEndFormat?: DateRangeFormatFunction } -export interface DateHeaderProps { +export interface DateHeaderProps { dailyStatus: TDailyStatus label: string date: Date isOffRange: boolean + isCurrent: boolean + utilities: TUtilities } -export interface DateFooterProps { +export interface DateFooterProps { label: string date: Date isOffRange: boolean + isCurrent: boolean + utilities: TUtilities } - export interface ShowMoreButtonProps { onClick: () => void //Use this to implement the default behavior events: TEvent[] // Use this to entirely customize the popup @@ -229,6 +232,7 @@ export interface ResourceHeaderProps { export interface Components< TEvent extends object = Event, TDailyStatus extends object = object, + TUtilities extends object = object, TResource extends object = object > { event?: React.ComponentType> @@ -254,9 +258,9 @@ export interface Components< } month?: { header?: React.ComponentType - dateHeader?: React.ComponentType> - dateFooter?: React.ComponentType - event?: React.ComponentType> + dateHeader?: React.ComponentType> + dateFooter?: React.ComponentType> + event?: React.ComponentType> showMoreButton?: React.ComponentType> } /** @@ -280,10 +284,14 @@ export interface ToolbarProps< children?: React.ReactNode } -export interface EventProps { +export interface EventProps< + TEvent extends object = Event, + TUtilities extends object = object +> { event: TEvent title: string isInPopup?: boolean + utilities: TUtilities } export interface EventWrapperProps { @@ -356,6 +364,7 @@ export class DateLocalizer { export interface CalendarProps< TEvent extends object = Event, TDailyStatus extends object = object, + TUtilities extends object = object, TResource extends object = object > extends React.Props> { localizer: DateLocalizer @@ -365,6 +374,7 @@ export interface CalendarProps< view?: View events?: TEvent[] dailyStatuses?: TDailyStatus[] + utilities: TUtilities handleDragStart?: (event: TEvent) => void onNavigate?: (newDate: Date, view: View, action: NavigateAction) => void onView?: (view: View) => void @@ -422,7 +432,7 @@ export interface CalendarProps< scrollToTime?: Date culture?: string formats?: Formats - components?: Components + components?: Components messages?: Messages dayLayoutAlgorithm?: DayLayoutAlgorithm | DayLayoutFunction titleAccessor?: keyof TEvent | ((event: TEvent) => string) From 26bfef373c0e0bc8ea8d70683f7299b3bec15b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 26 Mar 2021 16:49:29 +0700 Subject: [PATCH 50/60] build: implement utilities for components --- .size-snapshot.json | 22 +++++++++++----------- lib/DateContentRow.js | 5 ++++- lib/EventCell.js | 4 ++++ lib/EventEndingRow.js | 4 +++- lib/EventRowMixin.js | 4 +++- lib/Month.js | 15 ++++++++++++--- 6 files changed, 37 insertions(+), 17 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 3f88bfc2d..178daf991 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 501209, - "minified": 157723, - "gzipped": 48164 + "bundled": 501925, + "minified": 157998, + "gzipped": 48266 }, "./dist/react-big-calendar.min.js": { - "bundled": 428082, - "minified": 133964, - "gzipped": 42167 + "bundled": 428699, + "minified": 134182, + "gzipped": 42250 }, "dist/react-big-calendar.esm.js": { - "bundled": 188564, - "minified": 89645, - "gzipped": 22129, + "bundled": 189242, + "minified": 89944, + "gzipped": 22221, "treeshaked": { "rollup": { - "code": 64121, + "code": 64339, "import_statements": 1614 }, "webpack": { - "code": 68729 + "code": 68947 } } } diff --git a/lib/DateContentRow.js b/lib/DateContentRow.js index b4312d6af..115529268 100644 --- a/lib/DateContentRow.js +++ b/lib/DateContentRow.js @@ -262,7 +262,8 @@ var DateContentRow = longPressThreshold = _this$props6.longPressThreshold, isAllDay = _this$props6.isAllDay, resizable = _this$props6.resizable, - showAllEvents = _this$props6.showAllEvents + showAllEvents = _this$props6.showAllEvents, + utilities = _this$props6.utilities if (renderForMeasure) return this.renderDummy() var metrics = this.slotMetrics(this.props) var levels = metrics.levels, @@ -283,6 +284,7 @@ var DateContentRow = resourceId: resourceId, slotMetrics: metrics, resizable: resizable, + utilities: utilities, } return _react.default.createElement( 'div', @@ -383,6 +385,7 @@ DateContentRow.propTypes = date: _propTypes.default.instanceOf(Date), events: _propTypes.default.array.isRequired, range: _propTypes.default.array.isRequired, + utilities: _propTypes.default.object, rtl: _propTypes.default.bool, resizable: _propTypes.default.bool, resourceId: _propTypes.default.any, diff --git a/lib/EventCell.js b/lib/EventCell.js index b86e1f1a2..5e62990c9 100644 --- a/lib/EventCell.js +++ b/lib/EventCell.js @@ -60,6 +60,7 @@ var EventCell = EventWrapper = _this$props$component.eventWrapper, slotStart = _this$props.slotStart, slotEnd = _this$props.slotEnd, + utilities = _this$props.utilities, props = (0, _objectWithoutPropertiesLoose2.default)(_this$props, [ 'type', 'style', @@ -79,6 +80,7 @@ var EventCell = 'components', 'slotStart', 'slotEnd', + 'utilities', ]) delete props.resizable var title = accessors.title(event) @@ -101,6 +103,7 @@ var EventCell = Event ? _react.default.createElement(Event, { event: event, + utilities: utilities, continuesPrior: continuesPrior, continuesAfter: continuesAfter, title: title, @@ -156,6 +159,7 @@ EventCell.propTypes = process.env.NODE_ENV !== 'production' ? { event: _propTypes.default.object.isRequired, + utilities: _propTypes.default.object, slotStart: _propTypes.default.instanceOf(Date), slotEnd: _propTypes.default.instanceOf(Date), type: _propTypes.default.string, diff --git a/lib/EventEndingRow.js b/lib/EventEndingRow.js index 4116c0c06..ecaa28c6f 100644 --- a/lib/EventEndingRow.js +++ b/lib/EventEndingRow.js @@ -134,7 +134,8 @@ var EventEndingRow = accessors = _this$props2.accessors, onSelect = _this$props2.onSelect, onDoubleClick = _this$props2.onDoubleClick, - onKeyPress = _this$props2.onKeyPress + onKeyPress = _this$props2.onKeyPress, + utilities = _this$props2.utilities var count = eventsInSlot(segments, slot) var key = 'sm_' + slot @@ -168,6 +169,7 @@ var EventEndingRow = onSelect: onSelect, accessors: accessors, components: components, + utilities: utilities, onDoubleClick: onDoubleClick, onKeyPress: onKeyPress, draggable: true, diff --git a/lib/EventRowMixin.js b/lib/EventRowMixin.js index ed868afa4..d4c9c4bb4 100644 --- a/lib/EventRowMixin.js +++ b/lib/EventRowMixin.js @@ -42,11 +42,13 @@ var _default = { localizer = props.localizer, slotMetrics = props.slotMetrics, components = props.components, - resizable = props.resizable + resizable = props.resizable, + utilities = props.utilities var continuesPrior = slotMetrics.continuesPrior(event) var continuesAfter = slotMetrics.continuesAfter(event) return _react.default.createElement(_EventCell.default, { event: event, + utilities: utilities, getters: getters, localizer: localizer, accessors: accessors, diff --git a/lib/Month.js b/lib/Month.js index 63d8a7610..79a4b7171 100644 --- a/lib/Month.js +++ b/lib/Month.js @@ -123,7 +123,8 @@ var MonthView = longPressThreshold = _this2$props.longPressThreshold, accessors = _this2$props.accessors, getters = _this2$props.getters, - showAllEvents = _this2$props.showAllEvents + showAllEvents = _this2$props.showAllEvents, + utilities = _this2$props.utilities var _this2$state = _this2.state, needLimitMeasure = _this2$state.needLimitMeasure, rowLimit = _this2$state.rowLimit @@ -152,6 +153,7 @@ var MonthView = accessors: accessors, getters: getters, localizer: localizer, + utilities: utilities, renderHeader: _this2.readerDateHeading, renderFooter: _this2.renderDateFooter, renderForMeasure: needLimitMeasure, @@ -177,7 +179,8 @@ var MonthView = var _this2$props2 = _this2.props, currentDate = _this2$props2.date, getDrilldownView = _this2$props2.getDrilldownView, - localizer = _this2$props2.localizer + localizer = _this2$props2.localizer, + utilities = _this2$props2.utilities var isOffRange = dates.month(date) !== dates.month(currentDate) var isCurrent = dates.eq(date, currentDate, 'day') var drilldownView = getDrilldownView(date) @@ -200,6 +203,8 @@ var MonthView = date: date, drilldownView: drilldownView, isOffRange: isOffRange, + isCurrent: isCurrent, + utilities: utilities, onDrillDown: function onDrillDown(e) { return _this2.handleHeadingClick(date, drilldownView, e) }, @@ -216,7 +221,8 @@ var MonthView = ]) var _this2$props3 = _this2.props, currentDate = _this2$props3.date, - localizer = _this2$props3.localizer + localizer = _this2$props3.localizer, + utilities = _this2$props3.utilities var isOffRange = dates.month(date) !== dates.month(currentDate) var isCurrent = dates.eq(date, currentDate, 'day') var DateFooterComponent = @@ -236,6 +242,8 @@ var MonthView = label: label, date: date, isOffRange: isOffRange, + isCurrent: isCurrent, + utilities: utilities, }) ) } @@ -534,6 +542,7 @@ var MonthView = MonthView.propTypes = process.env.NODE_ENV !== 'production' ? { + utilities: _propTypes.default.object, events: _propTypes.default.array.isRequired, dailyStatuses: _propTypes.default.array.isRequired, date: _propTypes.default.instanceOf(Date), From 1fbd33b38fa662343734c2edd1abe45cf57db1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 26 Mar 2021 16:52:34 +0700 Subject: [PATCH 51/60] fix: typings for calendar --- typings.d.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/typings.d.ts b/typings.d.ts index 1cd25e204..2ab670f6a 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -472,8 +472,11 @@ export interface MoveOptions { export class Calendar< TEvent extends object = Event, TDailyStatus extends object = object, + TUtilities extends object = object, TResource extends object = object -> extends React.Component> {} +> extends React.Component< + CalendarProps +> {} export interface components { dateCellWrapper: React.ComponentType From 584db50fc7a877ebf46954f95bd51727fe6d62c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 26 Mar 2021 16:54:45 +0700 Subject: [PATCH 52/60] chore: make utitlities optional --- typings.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings.d.ts b/typings.d.ts index 2ab670f6a..606161547 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -374,7 +374,7 @@ export interface CalendarProps< view?: View events?: TEvent[] dailyStatuses?: TDailyStatus[] - utilities: TUtilities + utilities?: TUtilities handleDragStart?: (event: TEvent) => void onNavigate?: (newDate: Date, view: View, action: NavigateAction) => void onView?: (view: View) => void From 8c58599a3dec3d09dffb4d27249147061eb6f192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Fri, 26 Mar 2021 17:10:59 +0700 Subject: [PATCH 53/60] chore: add missing typings --- typings.d.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/typings.d.ts b/typings.d.ts index 606161547..9a9a815d1 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -192,7 +192,10 @@ export interface Formats { eventTimeRangeEndFormat?: DateRangeFormatFunction } -export interface DateHeaderProps { +export interface DateHeaderProps< + TDailyStatus, + TUtilities extends object = object +> { dailyStatus: TDailyStatus label: string date: Date @@ -201,7 +204,7 @@ export interface DateHeaderProps { utilities: TUtilities } -export interface DateFooterProps { +export interface DateFooterProps { label: string date: Date isOffRange: boolean @@ -235,7 +238,7 @@ export interface Components< TUtilities extends object = object, TResource extends object = object > { - event?: React.ComponentType> + event?: React.ComponentType> eventWrapper?: React.ComponentType> eventContainerWrapper?: React.ComponentType dateCellWrapper?: React.ComponentType From 4e7511080af4df44c5f7ff0c2ca6bf36a7fc552e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Mon, 29 Mar 2021 10:21:10 +0700 Subject: [PATCH 54/60] feature: implement utilities for toolbar --- examples/demos/rendering.js | 5 +++++ src/Calendar.js | 8 ++++++++ typings.d.ts | 4 +++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/demos/rendering.js b/examples/demos/rendering.js index f7e1391d9..d4c1e2d99 100644 --- a/examples/demos/rendering.js +++ b/examples/demos/rendering.js @@ -78,6 +78,10 @@ const ShowMoreButton = ({ label, events, children, date }) => { return } +const ToolBar = ({ utilities }) => { + utilities && utilities.onSaved('Utilities for Toolbar') + return

Toolbar

+} let Rendering = ({ localizer }) => { const [localEvents, setEvents] = useState([]) console.log(firstVisibleDay(new Date(), localizer)) @@ -101,6 +105,7 @@ let Rendering = ({ localizer }) => { event: Event, eventWrapper: ColoredEventWrapper, month: { + toolbar: ToolBar, dateHeader: CalendarHeader, dateFooter: CalendarFooter, showMoreButton: ShowMoreButton, diff --git a/src/Calendar.js b/src/Calendar.js index 8c6795605..20fc9ddce 100644 --- a/src/Calendar.js +++ b/src/Calendar.js @@ -777,6 +777,11 @@ class Calendar extends React.Component { * or custom `Function(events, minimumStartDifference, slotMetrics, accessors)` */ dayLayoutAlgorithm: DayLayoutAlgorithmPropType, + + /** + * Utilities for month view components + */ + utilities: PropTypes.object, } static defaultProps = { @@ -924,6 +929,7 @@ class Calendar extends React.Component { length, showMultiDayTimes, onShowMore, + utilities, components: _0, formats: _1, messages: _2, @@ -955,6 +961,7 @@ class Calendar extends React.Component { > + toolbar?: React.ComponentType> agenda?: { date?: React.ComponentType time?: React.ComponentType @@ -275,6 +275,7 @@ export interface Components< export interface ToolbarProps< TEvent extends object = Event, + TUtilities extends object = object, TResource extends object = object > { date: Date @@ -285,6 +286,7 @@ export interface ToolbarProps< onNavigate: (navigate: NavigateAction, date?: Date) => void onView: (view: View) => void children?: React.ReactNode + utilities: TUtilities } export interface EventProps< From 0a6e1d6b2858714dc3a914bc65d0bf94b046fec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Mon, 29 Mar 2021 10:21:49 +0700 Subject: [PATCH 55/60] build: implement utilities for toolbar --- .size-snapshot.json | 22 +++++++++++----------- lib/Calendar.js | 9 +++++++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index 178daf991..cbd5c54e1 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 501925, - "minified": 157998, - "gzipped": 48266 + "bundled": 502137, + "minified": 158067, + "gzipped": 48290 }, "./dist/react-big-calendar.min.js": { - "bundled": 428699, - "minified": 134182, - "gzipped": 42250 + "bundled": 428818, + "minified": 134232, + "gzipped": 42269 }, "dist/react-big-calendar.esm.js": { - "bundled": 189242, - "minified": 89944, - "gzipped": 22221, + "bundled": 189440, + "minified": 90021, + "gzipped": 22247, "treeshaked": { "rollup": { - "code": 64339, + "code": 64389, "import_statements": 1614 }, "webpack": { - "code": 68947 + "code": 68997 } } } diff --git a/lib/Calendar.js b/lib/Calendar.js index 40c1270eb..53949f5ac 100644 --- a/lib/Calendar.js +++ b/lib/Calendar.js @@ -381,6 +381,7 @@ var Calendar = length = _this$props4.length, showMultiDayTimes = _this$props4.showMultiDayTimes, onShowMore = _this$props4.onShowMore, + utilities = _this$props4.utilities, _0 = _this$props4.components, _1 = _this$props4.formats, _2 = _this$props4.messages, @@ -398,6 +399,7 @@ var Calendar = 'length', 'showMultiDayTimes', 'onShowMore', + 'utilities', 'components', 'formats', 'messages', @@ -430,6 +432,7 @@ var Calendar = _react.default.createElement(CalToolbar, { date: current, view: view, + utilities: utilities, views: viewNames, label: label, onView: this.handleViewChange, @@ -439,6 +442,7 @@ var Calendar = _react.default.createElement( View, (0, _extends2.default)({}, props, { + utilities: utilities, events: events, backgroundEvents: backgroundEvents, date: current, @@ -1228,6 +1232,11 @@ Calendar.propTypes = * or custom `Function(events, minimumStartDifference, slotMetrics, accessors)` */ dayLayoutAlgorithm: _propTypes2.DayLayoutAlgorithmPropType, + + /** + * Utilities for month view components + */ + utilities: _propTypes.default.object, } : {} From 4aea7ab3b36f2ac3b58767c86e3abfccfe796aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Mon, 29 Mar 2021 10:27:15 +0700 Subject: [PATCH 56/60] fix: fix generic --- typings.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/typings.d.ts b/typings.d.ts index 6dd725c81..48ca64cc3 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -78,6 +78,7 @@ export type ViewProps< } export type ViewsProps< TEvent extends object = Event, + TUtilities extends object = object, TResource extends object = object > = | View[] @@ -280,7 +281,7 @@ export interface ToolbarProps< > { date: Date view: View - views: ViewsProps + views: ViewsProps label: string localizer: { messages: Messages } onNavigate: (navigate: NavigateAction, date?: Date) => void From d6b797c902ed67eba49214c224dffec36e69a5e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Tue, 30 Mar 2021 10:18:56 +0700 Subject: [PATCH 57/60] fix: fix undefined dailystatus --- src/Month.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Month.js b/src/Month.js index 29eaa45ec..3868870b5 100644 --- a/src/Month.js +++ b/src/Month.js @@ -81,12 +81,14 @@ class MonthView extends React.Component { render() { let { date, localizer, className, dailyStatuses } = this.props, - month = dates.visibleDays(date, localizer).map(monthDate => { - const dailyStatus = dailyStatuses.find(status => - dates.isSameDay(status.start, monthDate) - ) - return new DateWithStatus(monthDate, dailyStatus) - }), + month = dailyStatuses + ? dates.visibleDays(date, localizer).map(monthDate => { + const dailyStatus = dailyStatuses.find(status => + dates.isSameDay(status.start, monthDate) + ) + return new DateWithStatus(monthDate, dailyStatus) + }) + : dates.visibleDays(date, localizer), weeks = chunk(month, 7) this._weekCount = weeks.length From b4906b105df851d5132b38dd20ad0ff4e2bab4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20=C4=90=E1=BB=A9c=20B=C3=ACnh?= Date: Tue, 30 Mar 2021 10:20:20 +0700 Subject: [PATCH 58/60] build: fix undefined dailystatus --- .size-snapshot.json | 22 +++++++++++----------- lib/Month.js | 14 ++++++++------ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/.size-snapshot.json b/.size-snapshot.json index cbd5c54e1..4b38bb446 100644 --- a/.size-snapshot.json +++ b/.size-snapshot.json @@ -1,25 +1,25 @@ { "./dist/react-big-calendar.js": { - "bundled": 502137, - "minified": 158067, - "gzipped": 48290 + "bundled": 502184, + "minified": 158082, + "gzipped": 48281 }, "./dist/react-big-calendar.min.js": { - "bundled": 428818, - "minified": 134232, - "gzipped": 42269 + "bundled": 428865, + "minified": 134247, + "gzipped": 42252 }, "dist/react-big-calendar.esm.js": { - "bundled": 189440, - "minified": 90021, - "gzipped": 22247, + "bundled": 189487, + "minified": 90040, + "gzipped": 22252, "treeshaked": { "rollup": { - "code": 64389, + "code": 64404, "import_statements": 1614 }, "webpack": { - "code": 68997 + "code": 69012 } } } diff --git a/lib/Month.js b/lib/Month.js index 79a4b7171..d7a9dab87 100644 --- a/lib/Month.js +++ b/lib/Month.js @@ -404,12 +404,14 @@ var MonthView = localizer = _this$props.localizer, className = _this$props.className, dailyStatuses = _this$props.dailyStatuses, - month = dates.visibleDays(date, localizer).map(function(monthDate) { - var dailyStatus = dailyStatuses.find(function(status) { - return dates.isSameDay(status.start, monthDate) - }) - return new DateWithStatus(monthDate, dailyStatus) - }), + month = dailyStatuses + ? dates.visibleDays(date, localizer).map(function(monthDate) { + var dailyStatus = dailyStatuses.find(function(status) { + return dates.isSameDay(status.start, monthDate) + }) + return new DateWithStatus(monthDate, dailyStatus) + }) + : dates.visibleDays(date, localizer), weeks = (0, _chunk.default)(month, 7) this._weekCount = weeks.length return _react.default.createElement( From c79a9bc47ae15beabca96e308932077949b08862 Mon Sep 17 00:00:00 2001 From: Pham Hong Phi Date: Sun, 30 May 2021 12:26:49 +0700 Subject: [PATCH 59/60] Update package.json Dont put module field if we dont serve it --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 444f5ff67..73c7a3801 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ }, "license": "MIT", "main": "lib/index.js", - "module": "dist/react-big-calendar.esm.js", "style": "lib/css/react-big-calendar.css", "files": [ "lib/", From 0f7ade6468c2ac72528a8aa53d3de05e92c3753a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 15 Jan 2022 03:33:52 +0000 Subject: [PATCH 60/60] chore(deps-dev): bump marked from 0.5.2 to 4.0.10 Bumps [marked](https://github.com/markedjs/marked) from 0.5.2 to 4.0.10. - [Release notes](https://github.com/markedjs/marked/releases) - [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json) - [Commits](https://github.com/markedjs/marked/compare/v0.5.2...v4.0.10) --- updated-dependencies: - dependency-name: marked dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 73c7a3801..59da01c27 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "jest": "^23.6.0", "lint-staged": "^8.0.4", "markdown-jsx-loader": "^3.0.2", - "marked": "^0.5.1", + "marked": "^4.0.10", "moment": "^2.22.2", "mt-changelog": "^0.6.1", "node-sass": "4.12.0", diff --git a/yarn.lock b/yarn.lock index 6257f7868..a7aa9aa73 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10337,10 +10337,10 @@ marked@^0.3.5, marked@^0.3.6: resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790" integrity sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg== -marked@^0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/marked/-/marked-0.5.2.tgz#3efdb27b1fd0ecec4f5aba362bddcd18120e5ba9" - integrity sha512-fdZvBa7/vSQIZCi4uuwo2N3q+7jJURpMVCcbaX0S1Mg65WZ5ilXvC67MviJAsdjqqgD+CEq4RKo5AYGgINkVAA== +marked@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.10.tgz#423e295385cc0c3a70fa495e0df68b007b879423" + integrity sha512-+QvuFj0nGgO970fySghXGmuw+Fd0gD2x3+MqCWLIPf5oxdv1Ka6b2q+z9RP01P/IaKPMEramy+7cNy/Lw8c3hw== matcher@^1.0.0: version "1.1.1"