diff --git a/examples/App.js b/examples/App.js index d37721a18..7a57d90f8 100644 --- a/examples/App.js +++ b/examples/App.js @@ -16,6 +16,7 @@ import './prism.scss' import Card from './Card' import ExampleControlSlot from './ExampleControlSlot' import Basic from './demos/basic' +import BackgroundEvents from './demos/backgroundEvents' import Selectable from './demos/selectable' import CreateEventWithNoOverlap from './demos/createEventWithNoOverlap' import Cultures from './demos/cultures' @@ -44,6 +45,7 @@ const EXAMPLES = { timeslots: 'Custom Time Grids', rendering: 'Customized Component Rendering', customView: 'Custom Calendar Views', + backgroundEvents: 'Background Events', resource: 'Resource Scheduling', dnd: 'Addon: Drag and drop', dndresource: 'Resource Drag and drop', @@ -74,6 +76,7 @@ class Example extends React.Component { let selected = this.state.selected let Current = { basic: Basic, + backgroundEvents: BackgroundEvents, selectable: Selectable, cultures: Cultures, popup: Popup, diff --git a/examples/backgroundEvents.js b/examples/backgroundEvents.js new file mode 100644 index 000000000..eeb5ac57d --- /dev/null +++ b/examples/backgroundEvents.js @@ -0,0 +1,8 @@ +export default [ + { + id: 0, + title: 'Available for Clients', + start: new Date(2015, 3, 13, 6), + end: new Date(2015, 3, 13, 18), + }, +] diff --git a/examples/demos/backgroundEvents.js b/examples/demos/backgroundEvents.js new file mode 100644 index 000000000..c163afd7d --- /dev/null +++ b/examples/demos/backgroundEvents.js @@ -0,0 +1,24 @@ +import React from 'react' +import { Calendar, Views } from 'react-big-calendar' +import events from '../events' +import backgroundEvents from '../backgroundEvents' +import * as dates from '../../src/utils/dates' + +let allViews = Object.keys(Views).map(k => Views[k]) + +let Basic = ({ localizer }) => ( + +) + +export default Basic diff --git a/examples/events.js b/examples/events.js index 08e377027..90aaa4b4c 100644 --- a/examples/events.js +++ b/examples/events.js @@ -77,10 +77,28 @@ export default [ }, { id: 11, - title: 'Birthday Party', - start: new Date(2015, 3, 13, 7, 0, 0), + title: 'Planning Meeting with Paige', + start: new Date(2015, 3, 13, 8, 0, 0), end: new Date(2015, 3, 13, 10, 30, 0), }, + { + id: 11.1, + title: 'Inconvenient Conference Call', + start: new Date(2015, 3, 13, 9, 30, 0), + end: new Date(2015, 3, 13, 12, 0, 0), + }, + { + id: 11.2, + title: "Project Kickoff - Lou's Shoes", + start: new Date(2015, 3, 13, 11, 30, 0), + end: new Date(2015, 3, 13, 14, 0, 0), + }, + { + id: 11.3, + title: 'Quote Follow-up - Tea by Tina', + start: new Date(2015, 3, 13, 15, 30, 0), + end: new Date(2015, 3, 13, 16, 0, 0), + }, { id: 12, title: 'Late Night Event', diff --git a/src/Calendar.js b/src/Calendar.js index 81b75f9d4..94f703426 100644 --- a/src/Calendar.js +++ b/src/Calendar.js @@ -112,6 +112,29 @@ class Calendar extends React.Component { */ events: PropTypes.arrayOf(PropTypes.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.arrayOf(PropTypes.object), + /** * Accessor for the event title, used to display event information. Should * resolve to a `renderable` value. @@ -783,6 +806,7 @@ class Calendar extends React.Component { constructor(...args) { super(...args) + this.state = { context: this.getContext(this.props), } @@ -801,6 +825,7 @@ class Calendar extends React.Component { resourceIdAccessor, resourceTitleAccessor, eventPropGetter, + backgroundEventPropGetter, slotPropGetter, slotGroupPropGetter, dayPropGetter, @@ -820,6 +845,9 @@ class Calendar extends React.Component { getters: { eventProp: (...args) => (eventPropGetter && eventPropGetter(...args)) || {}, + backgroundEventProp: (...args) => + (backgroundEventPropGetter && backgroundEventPropGetter(...args)) || + {}, slotProp: (...args) => (slotPropGetter && slotPropGetter(...args)) || {}, slotGroupProp: (...args) => @@ -828,6 +856,7 @@ class Calendar extends React.Component { }, components: defaults(components[view] || {}, omit(components, names), { eventWrapper: NoopWrapper, + backgroundEventWrapper: NoopWrapper, eventContainerWrapper: NoopWrapper, dateCellWrapper: NoopWrapper, weekWrapper: NoopWrapper, @@ -885,6 +914,7 @@ class Calendar extends React.Component { view, toolbar, events, + backgroundEvents = [], style, className, elementProps, @@ -934,6 +964,7 @@ class Calendar extends React.Component {
- {this.renderEvents()} + {this.renderEvents({ + events: this.props.backgroundEvents, + isBackgroundEvent: true, + })} + {this.renderEvents({ events: this.props.events })}
@@ -174,9 +178,8 @@ class DayColumn extends React.Component { ) } - renderEvents = () => { + renderEvents = ({ events, isBackgroundEvent }) => { let { - events, rtl, selected, accessors, @@ -233,6 +236,7 @@ class DayColumn extends React.Component { selected={isSelected(event, selected)} onClick={e => this._select(event, e)} onDoubleClick={e => this._doubleClick(event, e)} + isBackgroundEvent={isBackgroundEvent} onKeyPress={e => this._keyPress(event, e)} resizable={resizable} /> @@ -382,6 +386,7 @@ class DayColumn extends React.Component { DayColumn.propTypes = { events: PropTypes.array.isRequired, + backgroundEvents: PropTypes.array.isRequired, step: PropTypes.number.isRequired, date: PropTypes.instanceOf(Date).isRequired, min: PropTypes.instanceOf(Date).isRequired, diff --git a/src/TimeGrid.js b/src/TimeGrid.js index 8911ca61d..38676bf3c 100644 --- a/src/TimeGrid.js +++ b/src/TimeGrid.js @@ -105,7 +105,7 @@ export default class TimeGrid extends Component { }) } - renderEvents(range, events, now) { + renderEvents(range, events, backgroundEvents, now) { let { min, max, @@ -117,6 +117,7 @@ export default class TimeGrid extends Component { const resources = this.memoizedResources(this.props.resources, accessors) const groupedEvents = resources.groupEvents(events) + const groupedBackgroundEvents = resources.groupEvents(backgroundEvents) return resources.map(([id, resource], i) => range.map((date, jj) => { @@ -129,6 +130,17 @@ export default class TimeGrid extends Component { ) ) + let daysBackgroundEvents = ( + groupedBackgroundEvents.get(id) || [] + ).filter(event => + dates.inRange( + date, + accessors.start(event), + accessors.end(event), + 'day' + ) + ) + return ( ) @@ -151,6 +164,7 @@ export default class TimeGrid extends Component { render() { let { events, + backgroundEvents, range, width, rtl, @@ -176,7 +190,8 @@ export default class TimeGrid extends Component { this.slots = range.length let allDayEvents = [], - rangeEvents = [] + rangeEvents = [], + rangeBackgroundEvents = [] events.forEach(event => { if (inRange(event, start, end, accessors)) { @@ -195,6 +210,12 @@ export default class TimeGrid extends Component { } }) + backgroundEvents.forEach(event => { + if (inRange(event, start, end, accessors)) { + rangeBackgroundEvents.push(event) + } + }) + allDayEvents.sort((a, b) => sortEvents(a, b, accessors)) return ( @@ -246,7 +267,12 @@ export default class TimeGrid extends Component { className="rbc-time-gutter" getters={getters} /> - {this.renderEvents(range, rangeEvents, getNow())} + {this.renderEvents( + range, + rangeEvents, + rangeBackgroundEvents, + getNow() + )} ) @@ -311,6 +337,7 @@ export default class TimeGrid extends Component { TimeGrid.propTypes = { events: PropTypes.array.isRequired, + backgroundEvents: PropTypes.array.isRequired, resources: PropTypes.array, step: PropTypes.number, diff --git a/src/TimeGridEvent.js b/src/TimeGridEvent.js index c50a06ab2..eaf7f9adf 100644 --- a/src/TimeGridEvent.js +++ b/src/TimeGridEvent.js @@ -20,6 +20,7 @@ function TimeGridEvent(props) { getters, onClick, onDoubleClick, + isBackgroundEvent, onKeyPress, components: { event: Event, eventWrapper: EventWrapper }, } = props @@ -40,29 +41,45 @@ function TimeGridEvent(props) { , ] + const eventStyle = isBackgroundEvent + ? { + ...userProps.style, + top: stringifyPercent(top), + height: stringifyPercent(height), + // Adding 10px to take events container right margin into account + width: `calc(${width} + 10px)`, + [rtl ? 'right' : 'left']: stringifyPercent(Math.max(0, xOffset)), + } + : { + ...userProps.style, + top: stringifyPercent(top), + width: stringifyPercent(width), + height: stringifyPercent(height), + [rtl ? 'right' : 'left']: stringifyPercent(xOffset), + } + return (
{inner}
diff --git a/src/less/time-column.less b/src/less/time-column.less index c04745c26..5a458cba1 100644 --- a/src/less/time-column.less +++ b/src/less/time-column.less @@ -1,6 +1,5 @@ @import './variables.less'; - .rbc-time-column { display: flex; flex-direction: column; @@ -11,7 +10,6 @@ } } - .rbc-timeslot-group { border-bottom: 1px solid @cell-border; min-height: 40px; @@ -56,6 +54,21 @@ position: absolute; } + .rbc-background-event { + border: none; + box-shadow: none; + margin: 0; + padding: @event-padding; + background-color: @background-event-bg; + background-color: red; + border-radius: 0; + color: @event-color; + cursor: pointer; + width: 100%; + text-align: left; + opacity: 0.5; + } + .rbc-event-label { flex: none; padding-right: 5px; @@ -106,10 +119,10 @@ } .rbc-header, - .rbc-day-bg, { + .rbc-day-bg { width: 140px; // min-width: 0; - flex: 1 1 0; + flex: 1 1 0; flex-basis: 0 px; } } diff --git a/src/less/variables.less b/src/less/variables.less index 87a54c074..0689bdb65 100644 --- a/src/less/variables.less +++ b/src/less/variables.less @@ -22,6 +22,8 @@ @event-padding: 2px 5px; @event-zindex: 4; +@background-event-bg: lighten(#3174ad, 20%); + @btn-color: #373a3c; @btn-bg: #fff; @btn-border: #ccc; diff --git a/src/sass/time-column.scss b/src/sass/time-column.scss index 75328c7c5..fce2d3eb4 100644 --- a/src/sass/time-column.scss +++ b/src/sass/time-column.scss @@ -54,6 +54,11 @@ overflow: hidden; position: absolute; } + + .rbc-background-event { + @extend .rbc-event; + opacity: 0.75; + } .rbc-event-label { flex: none; diff --git a/stories/Calendar.js b/stories/Calendar.js index e55dd7dac..06f3ca7a6 100644 --- a/stories/Calendar.js +++ b/stories/Calendar.js @@ -10,7 +10,7 @@ import demoEvents from '../examples/events' import createEvents from './helpers/createEvents' import customComponents from './helpers/customComponents' -import { events, Views, Calendar } from './helpers' +import { events, backgroundEvents, Calendar, Views } from './helpers' storiesOf('Big Calendar', module) .add('demo', () => ( @@ -207,3 +207,12 @@ storiesOf('Big Calendar', module) /> ) }) + .add('add background event', () => { + return ( + + ) + }) diff --git a/stories/helpers/index.js b/stories/helpers/index.js index f40ebf09d..047dbd3e2 100644 --- a/stories/helpers/index.js +++ b/stories/helpers/index.js @@ -113,3 +113,18 @@ export const events = [ allDay: false, }, ] + +export const backgroundEvents = [ + { + title: 'test background event', + start: moment() + .startOf('day') + .add(2, 'hours') + .toDate(), + end: moment() + .startOf('day') + .add(12, 'hours') + .toDate(), + allDay: false, + }, +]