Skip to content

Commit

Permalink
feat: DnD support for custom DropWrapper components (dayWrapper and d…
Browse files Browse the repository at this point in the history
…ateCellWrapper) (jquense#843)

* Added DnD support for custom DateCellWrapper and DayWrapper components

* Code cleanup

Fixed all hardcoded `defaultView` prop strings to use the Views
constants

* Custom DropWrapper fixes

- Pass through range and value props to match non-dnd component props
- Added `customComponents` utility file for use with stories
- Clarified comment in `withDragAndDrop`
  • Loading branch information
amkoehler authored and jquense committed Jun 18, 2018
1 parent 7411386 commit d372f0d
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 26 deletions.
2 changes: 1 addition & 1 deletion examples/demos/customView.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ MyWeek.title = date => {
let CustomView = () => (
<BigCalendar
events={events}
defaultView="week"
defaultView={BigCalendar.Views.WEEK}
defaultDate={new Date(2015, 3, 1)}
views={{ month: true, week: MyWeek }}
/>
Expand Down
2 changes: 1 addition & 1 deletion examples/demos/dnd.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class Dnd extends React.Component {
onEventDrop={this.moveEvent}
resizable
onEventResize={this.resizeEvent}
defaultView="week"
defaultView={BigCalendar.Views.WEEK}
defaultDate={new Date(2015, 3, 12)}
/>
)
Expand Down
2 changes: 1 addition & 1 deletion examples/demos/rendering.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ let Rendering = () => (
<BigCalendar
events={events}
defaultDate={new Date(2015, 3, 1)}
defaultView="agenda"
defaultView={BigCalendar.Views.AGENDA}
dayPropGetter={customDayPropGetter}
slotPropGetter={customSlotPropGetter}
components={{
Expand Down
2 changes: 1 addition & 1 deletion examples/demos/resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const resourceMap = [
let Resource = () => (
<BigCalendar
events={events}
defaultView="day"
defaultView={BigCalendar.Views.DAY}
views={['day', 'work_week']}
step={60}
defaultDate={new Date(2018, 0, 29)}
Expand Down
2 changes: 1 addition & 1 deletion examples/demos/selectable.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let Selectable = () => (
<BigCalendar
selectable
events={events}
defaultView="week"
defaultView={BigCalendar.Views.WEEK}
scrollToTime={new Date(1970, 1, 1, 6)}
defaultDate={new Date(2015, 3, 12)}
onSelectEvent={event => alert(event.title)}
Expand Down
2 changes: 1 addition & 1 deletion examples/demos/timeslots.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let Timeslots = () => (
events={events}
step={15}
timeslots={8}
defaultView="week"
defaultView={BigCalendar.Views.WEEK}
defaultDate={new Date(2015, 3, 12)}
/>
)
Expand Down
35 changes: 28 additions & 7 deletions src/addons/dragAndDrop/DropWrappers.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ function getEventDropProps(start, end, dropDate, droppedInAllDay) {
/*
* If the event is dropped in a "Day" cell, preserve an event's start time by extracting the hours and minutes off
* the original start date and add it to newDate.value
*
*
* note: this behavior remains for backward compatibility, but might be counter-intuitive to some:
* dragging an event from the grid to the day header might more commonly mean "make this an allDay event
* on that day" - but the behavior here implements "keep the times of the event, but move it to the
* new day".
*
*
* To permit either interpretation, we embellish a new `allDay` parameter which determines whether the
* event was dropped on the day header or not.
*/
Expand All @@ -39,13 +39,16 @@ function getEventDropProps(start, end, dropDate, droppedInAllDay) {
class DropWrapper extends React.Component {
static propTypes = {
connectDropTarget: PropTypes.func.isRequired,
type: PropTypes.string,
isOver: PropTypes.bool,
range: PropTypes.arrayOf(PropTypes.instanceOf(Date)),
type: PropTypes.string,
value: PropTypes.instanceOf(Date),
}

static contextTypes = {
onEventDrop: PropTypes.func,
onEventResize: PropTypes.func,
components: PropTypes.object,
dragDropManager: PropTypes.object,
startAccessor: accessor,
endAccessor: accessor,
Expand Down Expand Up @@ -98,17 +101,35 @@ class DropWrapper extends React.Component {
// };

render() {
const { connectDropTarget, children, type, isOver } = this.props
const BackgroundWrapper = BigCalendar.components[type]
const {
connectDropTarget,
children,
isOver,
range,
type,
value,
} = this.props

// Check if wrapper component of this type was passed in, otherwise use library default
const { components } = this.context
const BackgroundWrapper = components[type] || BigCalendar.components[type]
const backgroundWrapperProps = {
value,
}

if (range) {
backgroundWrapperProps.range = range
}

let resultingChildren = children
if (isOver)
if (isOver) {
resultingChildren = React.cloneElement(children, {
className: cn(children.props.className, 'rbc-addons-dnd-over'),
})
}

return (
<BackgroundWrapper>
<BackgroundWrapper {...backgroundWrapperProps}>
{connectDropTarget(resultingChildren)}
</BackgroundWrapper>
)
Expand Down
8 changes: 6 additions & 2 deletions src/addons/dragAndDrop/withDragAndDrop.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ try {
* If you care about these corner cases, you can examine the `allDay` param suppled
* in the callback to determine how the user dropped or resized the event.
*
* Note: you cannot use custom `EventWrapper`, `DayWrapper` or `DateCellWrapper`
* components when using this HOC as they are overwritten here.
* Note: you cannot use custom `EventWrapper` components when using this HOC as it
* is overwritten here.
*
*
* @param {*} Calendar
* @param {*} backend
Expand All @@ -79,6 +80,7 @@ export default function withDragAndDrop(

static defaultProps = {
// TODO: pick these up from Calendar.defaultProps
components: {},
startAccessor: 'start',
endAccessor: 'end',
allDayAccessor: 'allDay',
Expand All @@ -94,6 +96,7 @@ export default function withDragAndDrop(
static childContextTypes = {
onEventDrop: PropTypes.func,
onEventResize: PropTypes.func,
components: PropTypes.object,
startAccessor: accessor,
endAccessor: accessor,
draggableAccessor: accessor,
Expand All @@ -105,6 +108,7 @@ export default function withDragAndDrop(
return {
onEventDrop: this.props.onEventDrop,
onEventResize: this.props.onEventResize,
components: this.props.components,
startAccessor: this.props.startAccessor,
endAccessor: this.props.endAccessor,
step: this.props.step,
Expand Down
85 changes: 74 additions & 11 deletions stories/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import '../src/less/styles.less'
import '../src/addons/dragAndDrop/styles.less'
import demoEvents from '../examples/events'
import createEvents from './createEvents'
import customComponents from './customComponents'
import resources from './resourceEvents'
import withDragAndDrop from '../src/addons/dragAndDrop'

Expand Down Expand Up @@ -119,7 +120,7 @@ storiesOf('module.Calendar.week', module)
return (
<div style={{ height: 600 }}>
<Calendar
defaultView="week"
defaultView={Calendar.Views.WEEK}
min={moment('12:00am', 'h:mma').toDate()}
max={moment('11:59pm', 'h:mma').toDate()}
events={events}
Expand All @@ -133,7 +134,7 @@ storiesOf('module.Calendar.week', module)
return (
<div style={{ height: 600 }}>
<DragableCalendar
defaultView="day"
defaultView={Calendar.Views.DAY}
min={moment('12:00am', 'h:mma').toDate()}
max={moment('11:59pm', 'h:mma').toDate()}
events={[
Expand Down Expand Up @@ -181,7 +182,7 @@ storiesOf('module.Calendar.week', module)
return (
<div style={{ height: 600 }}>
<Calendar
defaultView="week"
defaultView={Calendar.Views.WEEK}
selectable
min={moment('12:00am', 'h:mma').toDate()}
max={moment('11:59pm', 'h:mma').toDate()}
Expand All @@ -197,7 +198,7 @@ storiesOf('module.Calendar.week', module)
return (
<div style={{ height: 600 }}>
<Calendar
defaultView="week"
defaultView={Calendar.Views.WEEK}
selectable
timeslots={4}
step={15}
Expand All @@ -215,7 +216,7 @@ storiesOf('module.Calendar.week', module)
return (
<div style={{ height: 600 }}>
<Calendar
defaultView="week"
defaultView={Calendar.Views.WEEK}
selectable
timeslots={6}
step={10}
Expand All @@ -233,7 +234,7 @@ storiesOf('module.Calendar.week', module)
return (
<div style={{ height: 600 }}>
<Calendar
defaultView="week"
defaultView={Calendar.Views.WEEK}
selectable
timeslots={6}
step={5}
Expand All @@ -251,7 +252,7 @@ storiesOf('module.Calendar.week', module)
return (
<div style={{ height: 600 }}>
<Calendar
defaultView="week"
defaultView={Calendar.Views.WEEK}
selectable
timeslots={3}
getNow={() => moment('9:30am', 'h:mma').toDate()}
Expand Down Expand Up @@ -372,6 +373,32 @@ storiesOf('module.Calendar.week', module)
</div>
)
})
.add('add custom dateCellWrapper', () => {
return (
<div style={{ height: 600 }}>
<Calendar
defaultView={Calendar.Views.MONTH}
events={events}
components={{
dateCellWrapper: customComponents.dateCellWrapper,
}}
/>
</div>
)
})
.add('add custom dayWrapper', () => {
return (
<div style={{ height: 600 }}>
<Calendar
defaultView={Calendar.Views.DAY}
events={events}
components={{
dayWrapper: customComponents.dayWrapper,
}}
/>
</div>
)
})
.add('no duration', () => {
return (
<div style={{ height: 600 }}>
Expand Down Expand Up @@ -505,7 +532,7 @@ storiesOf('module.Calendar.week', module)
return (
<div style={{ height: 600 }}>
<Calendar
defaultView="week"
defaultView={Calendar.Views.WEEK}
getNow={customNow}
min={moment('12:00am', 'h:mma').toDate()}
max={moment('11:59pm', 'h:mma').toDate()}
Expand All @@ -521,7 +548,7 @@ storiesOf('module.Calendar.week', module)
<div style={{ height: 600 }}>
<DragAndDropCalendar
defaultDate={new Date()}
defaultView="week"
defaultView={Calendar.Views.WEEK}
events={events}
resizable
onEventDrop={action('event dropped')}
Expand All @@ -535,7 +562,7 @@ storiesOf('module.Calendar.week', module)
<div style={{ height: 600 }}>
<DragAndDropCalendar
defaultDate={new Date()}
defaultView="week"
defaultView={Calendar.Views.WEEK}
events={events}
resizable
step={15}
Expand All @@ -551,7 +578,43 @@ storiesOf('module.Calendar.week', module)
<div style={{ height: 600 }}>
<DragAndDropCalendar
defaultDate={new Date()}
defaultView="week"
defaultView={Calendar.Views.WEEK}
events={events}
resizable
showMultiDayTimes
onEventDrop={action('event dropped')}
onEventResize={action('event resized')}
/>
</div>
)
})
.add('draggable and resizable with custom dateCellWrapper', () => {
return (
<div style={{ height: 600 }}>
<DragAndDropCalendar
components={{
dateCellWrapper: customComponents.dateCellWrapper,
}}
defaultDate={new Date()}
defaultView={Calendar.Views.MONTH}
events={events}
resizable
showMultiDayTimes
onEventDrop={action('event dropped')}
onEventResize={action('event resized')}
/>
</div>
)
})
.add('draggable and resizable with custom dayWrapper', () => {
return (
<div style={{ height: 600 }}>
<DragAndDropCalendar
components={{
dayWrapper: customComponents.dayWrapper,
}}
defaultDate={new Date()}
defaultView={Calendar.Views.WEEK}
events={events}
resizable
showMultiDayTimes
Expand Down
49 changes: 49 additions & 0 deletions stories/customComponents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react'
import { action } from '@storybook/react'

const customComponents = {
dateCellWrapper: dateCellWrapperProps => {
// Show 'click me' text in arbitrary places by using the range prop
const hasAlert = dateCellWrapperProps.range
? dateCellWrapperProps.range.some(date => {
return date.getDate() % 12 === 0
})
: false

const style = {
display: 'flex',
flex: 1,
borderLeft: '1px solid #DDD',
backgroundColor: hasAlert ? '#f5f5dc' : '#fff',
}
return (
<div style={style}>
{hasAlert && (
<a onClick={action('custom dateCellWrapper component clicked')}>
Click me
</a>
)}
{dateCellWrapperProps.children}
</div>
)
},
dayWrapper: dayWrapperProps => {
// Show different styles at arbitrary time
const hasCustomInfo = dayWrapperProps.value
? dayWrapperProps.value.getHours() === 4
: false
const style = {
display: 'flex',
flex: 1,
backgroundColor: hasCustomInfo ? '#f5f5dc' : '#fff',
}
return (
<div style={style}>
{hasCustomInfo && 'Custom Day Wrapper'}
{dayWrapperProps.children}
</div>
)
},
}

export default customComponents

0 comments on commit d372f0d

Please sign in to comment.