Skip to content

Commit d2e02c4

Browse files
authored
feat: revamp Drag and drop
Revamps the internals of drag-and-drop BREAKING CHANGE: Calendar wrapper components props have changed BREAKING CHANGE: react-dnd is no longer used internally with no external API
1 parent 630b630 commit d2e02c4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+3624
-2753
lines changed

.eslintrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@ extends:
55

66
rules:
77
global-require: off
8+
no-unused-vars: [2, {
9+
vars: all,
10+
args: after-used,
11+
varsIgnorePattern: ^_,
12+
argsIgnorePattern: ^_,
13+
}]

examples/App.js

Lines changed: 48 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import { render } from 'react-dom'
77
import localizer from 'react-big-calendar/lib/localizers/globalize'
88
import globalize from 'globalize'
99

10-
localizer(globalize)
11-
1210
import 'bootstrap/dist/css/bootstrap.min.css'
1311
import 'font-awesome/css/font-awesome.min.css'
1412

@@ -25,13 +23,40 @@ import Resource from './demos/resource'
2523
import DndResource from './demos/dndresource'
2624
import Timeslots from './demos/timeslots'
2725
import Dnd from './demos/dnd'
26+
import Dropdown from 'react-bootstrap/lib/Dropdown'
27+
import MenuItem from 'react-bootstrap/lib/MenuItem'
28+
29+
const globalizeLocalizer = localizer(globalize)
2830

2931
let demoRoot =
3032
'https://github.com/intljusticemission/react-big-calendar/tree/master/examples/demos'
3133

34+
const EXAMPLES = {
35+
basic: 'Basic Calendar',
36+
selectable: 'Create events',
37+
cultures: 'Localization',
38+
popup: 'Show more via a popup',
39+
timeslots: 'Custom Time Grids',
40+
rendering: 'Customized Component Rendering',
41+
customView: 'Custom Calendar Views',
42+
resource: 'Resource Scheduling',
43+
dnd: 'Addon: Drag and drop',
44+
}
45+
3246
class Example extends React.Component {
33-
state = { selected: 'basic' }
47+
constructor(...args) {
48+
super(...args)
3449

50+
const hash = (window.location.hash || '').slice(1)
51+
52+
this.state = {
53+
selected: EXAMPLES[hash] ? hash : 'basic',
54+
}
55+
}
56+
57+
select = selected => {
58+
this.setState({ selected })
59+
}
3560
render() {
3661
let selected = this.state.selected
3762
let Current = {
@@ -74,70 +99,30 @@ class Example extends React.Component {
7499
</div>
75100
</div>
76101
<div className="examples">
77-
<header>
78-
<ul className="examples--list list-unstyled">
79-
<li className={cn({ active: selected === 'basic' })}>
80-
<a href="#" onClick={this.select.bind(null, 'basic')}>
81-
Basic
82-
</a>
83-
</li>
84-
<li className={cn({ active: selected === 'selectable' })}>
85-
<a href="#" onClick={this.select.bind(null, 'selectable')}>
86-
Selectable
87-
</a>
88-
</li>
89-
<li className={cn({ active: selected === 'cultures' })}>
90-
<a href="#" onClick={this.select.bind(null, 'cultures')}>
91-
I18n and Locales
92-
</a>
93-
</li>
94-
<li className={cn({ active: selected === 'popup' })}>
95-
<a href="#" onClick={this.select.bind(null, 'popup')}>
96-
Popup
97-
</a>
98-
</li>
99-
<li className={cn({ active: selected === 'timeslots' })}>
100-
<a href="#" onClick={this.select.bind(null, 'timeslots')}>
101-
Timeslots
102-
</a>
103-
</li>
104-
<li className={cn({ active: selected === 'rendering' })}>
105-
<a href="#" onClick={this.select.bind(null, 'rendering')}>
106-
Custom rendering
107-
</a>
108-
</li>
109-
<li className={cn({ active: selected === 'customView' })}>
110-
<a href="#" onClick={this.select.bind(null, 'customView')}>
111-
Custom View
112-
</a>
113-
</li>
114-
<li className={cn({ active: selected === 'Resource' })}>
115-
<a href="#" onClick={this.select.bind(null, 'resource')}>
116-
Resource columns
117-
</a>
118-
</li>
119-
<li className={cn({ active: selected === 'dnd' })}>
120-
<a href="#" onClick={this.select.bind(null, 'dnd')}>
121-
Drag and Drop
122-
</a>
123-
</li>
124-
<li className={cn({ active: selected === 'dndresource' })}>
125-
<a href="#" onClick={this.select.bind(null, 'dndresource')}>
126-
D'n'D Resource columns
127-
</a>
128-
</li>
129-
</ul>
130-
</header>
131-
<div className="example">
132-
<div className="view-source">
102+
<header className="examples--header">
103+
<div className="examples--view-source">
133104
<a target="_blank" href={demoRoot + '/' + selected + '.js'}>
134105
<strong>
135106
<i className="fa fa-code" />
136107
{' View example source code'}
137108
</strong>
138109
</a>
139110
</div>
140-
<Current />
111+
<Dropdown className="examples--dropdown" pullRight>
112+
<Dropdown.Toggle bsStyle="link" className="dropdown--toggle ">
113+
{EXAMPLES[selected]}
114+
</Dropdown.Toggle>
115+
<Dropdown.Menu>
116+
{Object.entries(EXAMPLES).map(([key, title]) => (
117+
<MenuItem href={`#${key}`} onClick={() => this.select(key)}>
118+
{title}
119+
</MenuItem>
120+
))}
121+
</Dropdown.Menu>
122+
</Dropdown>
123+
</header>
124+
<div className="example">
125+
<Current localizer={globalizeLocalizer} />
141126
</div>
142127
</div>
143128
<div className="docs">
@@ -149,11 +134,8 @@ class Example extends React.Component {
149134
</div>
150135
)
151136
}
152-
153-
select = (selected, e) => {
154-
e.preventDefault()
155-
this.setState({ selected })
156-
}
157137
}
158138

159-
render(<Example />, document.getElementById('app'))
139+
document.addEventListener('DOMContentLoaded', () => {
140+
render(<Example />, document.getElementById('app'))
141+
})

examples/Intro.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ import moment from 'moment'
2222

2323
// Setup the localizer by providing the moment (or globalize) Object
2424
// to the correct localizer.
25-
BigCalendar.momentLocalizer(moment) // or globalizeLocalizer
25+
const localizer = BigCalendar.momentLocalizer(moment) // or globalizeLocalizer
2626

2727
const MyCalendar = props => (
2828
<div>
2929
<BigCalendar
30+
localizer={localizer}
3031
events={myEventsList}
3132
startAccessor="start"
3233
endAccessor="end"

examples/bundle.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4045,7 +4045,7 @@ object-assign
40454045
exports.__esModule = true
40464046
exports.isSelected = isSelected
40474047
exports.slotWidth = slotWidth
4048-
exports.getCellAtX = getCellAtX
4048+
exports.getSlotAtX = getSlotAtX
40494049
exports.pointInBox = pointInBox
40504050
exports.dateCellSelection = dateCellSelection
40514051
function isSelected(event, selected) {
@@ -4060,7 +4060,7 @@ object-assign
40604060
return cellWidth
40614061
}
40624062

4063-
function getCellAtX(rowBox, x, cellWidth, rtl, slots) {
4063+
function getSlotAtX(rowBox, x, cellWidth, rtl, slots) {
40644064
return rtl
40654065
? slots - 1 - Math.floor((x - rowBox.left) / cellWidth)
40664066
: Math.floor((x - rowBox.left) / cellWidth)
@@ -4083,7 +4083,7 @@ object-assign
40834083
var cellWidth = slotWidth(rowBox, slots)
40844084

40854085
// cell under the mouse
4086-
var currentSlot = getCellAtX(rowBox, box.x, cellWidth, rtl, slots)
4086+
var currentSlot = getSlotAtX(rowBox, box.x, cellWidth, rtl, slots)
40874087

40884088
// Identify row as either the initial row
40894089
// or the row under the current mouse point
@@ -52224,7 +52224,7 @@ object-assign
5222452224
(0, _Selection.getBoundsForNode)(node),
5222552225
range.length
5222652226
)
52227-
var currentCell = (0, _selection.getCellAtX)(
52227+
var currentCell = (0, _selection.getSlotAtX)(
5222852228
rowBox,
5222952229
point.x,
5223052230
width,

examples/demos/basic.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import React from 'react'
22
import BigCalendar from 'react-big-calendar'
33
import events from '../events'
4+
import dates from '../../src/utils/dates'
45

56
let allViews = Object.keys(BigCalendar.Views).map(k => BigCalendar.Views[k])
67

7-
let Basic = () => (
8+
let Basic = ({ localizer }) => (
89
<BigCalendar
910
events={events}
1011
views={allViews}
1112
step={60}
1213
showMultiDayTimes
14+
max={dates.add(dates.endOf(new Date(2015, 17, 1), 'day'), -1, 'hours')}
1315
defaultDate={new Date(2015, 3, 1)}
16+
localizer={localizer}
1417
/>
1518
)
1619

examples/demos/cultures.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ class Cultures extends React.Component {
1111
state = { culture: 'fr' }
1212

1313
render() {
14+
const { localizer } = this.props
1415
let cultures = ['en', 'en-GB', 'es', 'fr', 'ar-AE']
1516
let rtl = this.state.culture === 'ar-AE'
1617

1718
return (
1819
<React.Fragment>
19-
<h3 className="callout">
20+
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
2021
<label>Select a Culture</label>{' '}
2122
<select
2223
className="form-control"
@@ -30,12 +31,13 @@ class Cultures extends React.Component {
3031
</option>
3132
))}
3233
</select>
33-
</h3>
34+
</div>
3435
<BigCalendar
3536
rtl={rtl}
3637
events={events}
3738
culture={this.state.culture}
3839
defaultDate={new Date(2015, 3, 1)}
40+
localizer={localizer}
3941
/>
4042
</React.Fragment>
4143
)

examples/demos/customHeader.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ let MyCustomHeader = ({ label }) => (
1212
</div>
1313
)
1414

15-
let CustomHeader = () => (
15+
let CustomHeader = ({ localizer }) => (
1616
<BigCalendar
1717
events={events}
18+
localizer={localizer}
1819
defaultDate={new Date(2015, 3, 1)}
1920
components={{
2021
day: { header: MyCustomHeader },

examples/demos/customView.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@ MyWeek.title = date => {
4646
return `My awesome week: ${date.toLocaleDateString()}`
4747
}
4848

49-
let CustomView = () => (
49+
let CustomView = ({ localizer }) => (
5050
<BigCalendar
5151
events={events}
52+
localizer={localizer}
5253
defaultView={BigCalendar.Views.WEEK}
5354
defaultDate={new Date(2015, 3, 1)}
5455
views={{ month: true, week: MyWeek }}

examples/demos/dnd.js

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import React from 'react'
22
import events from '../events'
3-
import HTML5Backend from 'react-dnd-html5-backend'
4-
import { DragDropContext } from 'react-dnd'
53
import BigCalendar from 'react-big-calendar'
64
import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop'
75

@@ -16,15 +14,23 @@ class Dnd extends React.Component {
1614
events: events,
1715
}
1816

19-
this.moveEvent = this.moveEvent.bind(this);
20-
this.newEvent = this.newEvent.bind(this);
17+
this.moveEvent = this.moveEvent.bind(this)
18+
this.newEvent = this.newEvent.bind(this)
2119
}
2220

23-
moveEvent({ event, start, end }) {
21+
moveEvent({ event, start, end, isAllDay: droppedOnAllDaySlot }) {
2422
const { events } = this.state
2523

2624
const idx = events.indexOf(event)
27-
const updatedEvent = { ...event, start, end }
25+
let allDay = event.allDay
26+
27+
if (!event.allDay && droppedOnAllDaySlot) {
28+
allDay = true
29+
} else if (event.allDay && !droppedOnAllDaySlot) {
30+
allDay = false
31+
}
32+
33+
const updatedEvent = { ...event, start, end, allDay }
2834

2935
const nextEvents = [...events]
3036
nextEvents.splice(idx, 1, updatedEvent)
@@ -33,10 +39,10 @@ class Dnd extends React.Component {
3339
events: nextEvents,
3440
})
3541

36-
alert(`${event.title} was dropped onto ${event.start}`)
42+
// alert(`${event.title} was dropped onto ${updatedEvent.start}`)
3743
}
3844

39-
resizeEvent = (resizeType, { event, start, end }) => {
45+
resizeEvent = ({ event, start, end }) => {
4046
const { events } = this.state
4147

4248
const nextEvents = events.map(existingEvent => {
@@ -49,38 +55,39 @@ class Dnd extends React.Component {
4955
events: nextEvents,
5056
})
5157

52-
alert(`${event.title} was resized to ${start}-${end}`)
58+
//alert(`${event.title} was resized to ${start}-${end}`)
5359
}
5460

5561
newEvent(event) {
56-
let idList = this.state.events.map((a) => a.id);
57-
let newId = Math.max(...idList) + 1;
58-
let hour = {
59-
id: newId,
60-
title: 'New Event',
61-
allDay: event.slots.length == 1,
62-
start: event.start,
63-
end: event.end,
64-
}
65-
this.setState({
66-
events: this.state.events.concat([hour])
67-
});
62+
// let idList = this.state.events.map(a => a.id)
63+
// let newId = Math.max(...idList) + 1
64+
// let hour = {
65+
// id: newId,
66+
// title: 'New Event',
67+
// allDay: event.slots.length == 1,
68+
// start: event.start,
69+
// end: event.end,
70+
// }
71+
// this.setState({
72+
// events: this.state.events.concat([hour]),
73+
// })
6874
}
6975

7076
render() {
7177
return (
7278
<DragAndDropCalendar
7379
selectable
80+
localizer={this.props.localizer}
7481
events={this.state.events}
7582
onEventDrop={this.moveEvent}
7683
resizable
7784
onEventResize={this.resizeEvent}
7885
onSelectSlot={this.newEvent}
79-
defaultView={BigCalendar.Views.WEEK}
86+
defaultView={BigCalendar.Views.MONTH}
8087
defaultDate={new Date(2015, 3, 12)}
8188
/>
8289
)
8390
}
8491
}
8592

86-
export default DragDropContext(HTML5Backend)(Dnd)
93+
export default Dnd

0 commit comments

Comments
 (0)