Skip to content

Commit

Permalink
feat: revamp Drag and drop
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jquense committed Jul 25, 2018
1 parent 630b630 commit d2e02c4
Show file tree
Hide file tree
Showing 85 changed files with 3,624 additions and 2,753 deletions.
6 changes: 6 additions & 0 deletions .eslintrc
Expand Up @@ -5,3 +5,9 @@ extends:

rules:
global-require: off
no-unused-vars: [2, {
vars: all,
args: after-used,
varsIgnorePattern: ^_,
argsIgnorePattern: ^_,
}]
114 changes: 48 additions & 66 deletions examples/App.js
Expand Up @@ -7,8 +7,6 @@ import { render } from 'react-dom'
import localizer from 'react-big-calendar/lib/localizers/globalize'
import globalize from 'globalize'

localizer(globalize)

import 'bootstrap/dist/css/bootstrap.min.css'
import 'font-awesome/css/font-awesome.min.css'

Expand All @@ -25,13 +23,40 @@ import Resource from './demos/resource'
import DndResource from './demos/dndresource'
import Timeslots from './demos/timeslots'
import Dnd from './demos/dnd'
import Dropdown from 'react-bootstrap/lib/Dropdown'
import MenuItem from 'react-bootstrap/lib/MenuItem'

const globalizeLocalizer = localizer(globalize)

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

const EXAMPLES = {
basic: 'Basic Calendar',
selectable: 'Create events',
cultures: 'Localization',
popup: 'Show more via a popup',
timeslots: 'Custom Time Grids',
rendering: 'Customized Component Rendering',
customView: 'Custom Calendar Views',
resource: 'Resource Scheduling',
dnd: 'Addon: Drag and drop',
}

class Example extends React.Component {
state = { selected: 'basic' }
constructor(...args) {
super(...args)

const hash = (window.location.hash || '').slice(1)

this.state = {
selected: EXAMPLES[hash] ? hash : 'basic',
}
}

select = selected => {
this.setState({ selected })
}
render() {
let selected = this.state.selected
let Current = {
Expand Down Expand Up @@ -74,70 +99,30 @@ class Example extends React.Component {
</div>
</div>
<div className="examples">
<header>
<ul className="examples--list list-unstyled">
<li className={cn({ active: selected === 'basic' })}>
<a href="#" onClick={this.select.bind(null, 'basic')}>
Basic
</a>
</li>
<li className={cn({ active: selected === 'selectable' })}>
<a href="#" onClick={this.select.bind(null, 'selectable')}>
Selectable
</a>
</li>
<li className={cn({ active: selected === 'cultures' })}>
<a href="#" onClick={this.select.bind(null, 'cultures')}>
I18n and Locales
</a>
</li>
<li className={cn({ active: selected === 'popup' })}>
<a href="#" onClick={this.select.bind(null, 'popup')}>
Popup
</a>
</li>
<li className={cn({ active: selected === 'timeslots' })}>
<a href="#" onClick={this.select.bind(null, 'timeslots')}>
Timeslots
</a>
</li>
<li className={cn({ active: selected === 'rendering' })}>
<a href="#" onClick={this.select.bind(null, 'rendering')}>
Custom rendering
</a>
</li>
<li className={cn({ active: selected === 'customView' })}>
<a href="#" onClick={this.select.bind(null, 'customView')}>
Custom View
</a>
</li>
<li className={cn({ active: selected === 'Resource' })}>
<a href="#" onClick={this.select.bind(null, 'resource')}>
Resource columns
</a>
</li>
<li className={cn({ active: selected === 'dnd' })}>
<a href="#" onClick={this.select.bind(null, 'dnd')}>
Drag and Drop
</a>
</li>
<li className={cn({ active: selected === 'dndresource' })}>
<a href="#" onClick={this.select.bind(null, 'dndresource')}>
D'n'D Resource columns
</a>
</li>
</ul>
</header>
<div className="example">
<div className="view-source">
<header className="examples--header">
<div className="examples--view-source">
<a target="_blank" href={demoRoot + '/' + selected + '.js'}>
<strong>
<i className="fa fa-code" />
{' View example source code'}
</strong>
</a>
</div>
<Current />
<Dropdown className="examples--dropdown" pullRight>
<Dropdown.Toggle bsStyle="link" className="dropdown--toggle ">
{EXAMPLES[selected]}
</Dropdown.Toggle>
<Dropdown.Menu>
{Object.entries(EXAMPLES).map(([key, title]) => (
<MenuItem href={`#${key}`} onClick={() => this.select(key)}>
{title}
</MenuItem>
))}
</Dropdown.Menu>
</Dropdown>
</header>
<div className="example">
<Current localizer={globalizeLocalizer} />
</div>
</div>
<div className="docs">
Expand All @@ -149,11 +134,8 @@ class Example extends React.Component {
</div>
)
}

select = (selected, e) => {
e.preventDefault()
this.setState({ selected })
}
}

render(<Example />, document.getElementById('app'))
document.addEventListener('DOMContentLoaded', () => {
render(<Example />, document.getElementById('app'))
})
3 changes: 2 additions & 1 deletion examples/Intro.md
Expand Up @@ -22,11 +22,12 @@ import moment from 'moment'

// Setup the localizer by providing the moment (or globalize) Object
// to the correct localizer.
BigCalendar.momentLocalizer(moment) // or globalizeLocalizer
const localizer = BigCalendar.momentLocalizer(moment) // or globalizeLocalizer

const MyCalendar = props => (
<div>
<BigCalendar
localizer={localizer}
events={myEventsList}
startAccessor="start"
endAccessor="end"
Expand Down
8 changes: 4 additions & 4 deletions examples/bundle.js
Expand Up @@ -4045,7 +4045,7 @@ object-assign
exports.__esModule = true
exports.isSelected = isSelected
exports.slotWidth = slotWidth
exports.getCellAtX = getCellAtX
exports.getSlotAtX = getSlotAtX
exports.pointInBox = pointInBox
exports.dateCellSelection = dateCellSelection
function isSelected(event, selected) {
Expand All @@ -4060,7 +4060,7 @@ object-assign
return cellWidth
}

function getCellAtX(rowBox, x, cellWidth, rtl, slots) {
function getSlotAtX(rowBox, x, cellWidth, rtl, slots) {
return rtl
? slots - 1 - Math.floor((x - rowBox.left) / cellWidth)
: Math.floor((x - rowBox.left) / cellWidth)
Expand All @@ -4083,7 +4083,7 @@ object-assign
var cellWidth = slotWidth(rowBox, slots)

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

// Identify row as either the initial row
// or the row under the current mouse point
Expand Down Expand Up @@ -52224,7 +52224,7 @@ object-assign
(0, _Selection.getBoundsForNode)(node),
range.length
)
var currentCell = (0, _selection.getCellAtX)(
var currentCell = (0, _selection.getSlotAtX)(
rowBox,
point.x,
width,
Expand Down
5 changes: 4 additions & 1 deletion examples/demos/basic.js
@@ -1,16 +1,19 @@
import React from 'react'
import BigCalendar from 'react-big-calendar'
import events from '../events'
import dates from '../../src/utils/dates'

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

let Basic = () => (
let Basic = ({ localizer }) => (
<BigCalendar
events={events}
views={allViews}
step={60}
showMultiDayTimes
max={dates.add(dates.endOf(new Date(2015, 17, 1), 'day'), -1, 'hours')}
defaultDate={new Date(2015, 3, 1)}
localizer={localizer}
/>
)

Expand Down
6 changes: 4 additions & 2 deletions examples/demos/cultures.js
Expand Up @@ -11,12 +11,13 @@ class Cultures extends React.Component {
state = { culture: 'fr' }

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

return (
<React.Fragment>
<h3 className="callout">
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<label>Select a Culture</label>{' '}
<select
className="form-control"
Expand All @@ -30,12 +31,13 @@ class Cultures extends React.Component {
</option>
))}
</select>
</h3>
</div>
<BigCalendar
rtl={rtl}
events={events}
culture={this.state.culture}
defaultDate={new Date(2015, 3, 1)}
localizer={localizer}
/>
</React.Fragment>
)
Expand Down
3 changes: 2 additions & 1 deletion examples/demos/customHeader.js
Expand Up @@ -12,9 +12,10 @@ let MyCustomHeader = ({ label }) => (
</div>
)

let CustomHeader = () => (
let CustomHeader = ({ localizer }) => (
<BigCalendar
events={events}
localizer={localizer}
defaultDate={new Date(2015, 3, 1)}
components={{
day: { header: MyCustomHeader },
Expand Down
3 changes: 2 additions & 1 deletion examples/demos/customView.js
Expand Up @@ -46,9 +46,10 @@ MyWeek.title = date => {
return `My awesome week: ${date.toLocaleDateString()}`
}

let CustomView = () => (
let CustomView = ({ localizer }) => (
<BigCalendar
events={events}
localizer={localizer}
defaultView={BigCalendar.Views.WEEK}
defaultDate={new Date(2015, 3, 1)}
views={{ month: true, week: MyWeek }}
Expand Down
53 changes: 30 additions & 23 deletions examples/demos/dnd.js
@@ -1,7 +1,5 @@
import React from 'react'
import events from '../events'
import HTML5Backend from 'react-dnd-html5-backend'
import { DragDropContext } from 'react-dnd'
import BigCalendar from 'react-big-calendar'
import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop'

Expand All @@ -16,15 +14,23 @@ class Dnd extends React.Component {
events: events,
}

this.moveEvent = this.moveEvent.bind(this);
this.newEvent = this.newEvent.bind(this);
this.moveEvent = this.moveEvent.bind(this)
this.newEvent = this.newEvent.bind(this)
}

moveEvent({ event, start, end }) {
moveEvent({ event, start, end, isAllDay: droppedOnAllDaySlot }) {
const { events } = this.state

const idx = events.indexOf(event)
const updatedEvent = { ...event, start, end }
let allDay = event.allDay

if (!event.allDay && droppedOnAllDaySlot) {
allDay = true
} else if (event.allDay && !droppedOnAllDaySlot) {
allDay = false
}

const updatedEvent = { ...event, start, end, allDay }

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

alert(`${event.title} was dropped onto ${event.start}`)
// alert(`${event.title} was dropped onto ${updatedEvent.start}`)
}

resizeEvent = (resizeType, { event, start, end }) => {
resizeEvent = ({ event, start, end }) => {
const { events } = this.state

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

alert(`${event.title} was resized to ${start}-${end}`)
//alert(`${event.title} was resized to ${start}-${end}`)
}

newEvent(event) {
let idList = this.state.events.map((a) => a.id);
let newId = Math.max(...idList) + 1;
let hour = {
id: newId,
title: 'New Event',
allDay: event.slots.length == 1,
start: event.start,
end: event.end,
}
this.setState({
events: this.state.events.concat([hour])
});
// let idList = this.state.events.map(a => a.id)
// let newId = Math.max(...idList) + 1
// let hour = {
// id: newId,
// title: 'New Event',
// allDay: event.slots.length == 1,
// start: event.start,
// end: event.end,
// }
// this.setState({
// events: this.state.events.concat([hour]),
// })
}

render() {
return (
<DragAndDropCalendar
selectable
localizer={this.props.localizer}
events={this.state.events}
onEventDrop={this.moveEvent}
resizable
onEventResize={this.resizeEvent}
onSelectSlot={this.newEvent}
defaultView={BigCalendar.Views.WEEK}
defaultView={BigCalendar.Views.MONTH}
defaultDate={new Date(2015, 3, 12)}
/>
)
}
}

export default DragDropContext(HTML5Backend)(Dnd)
export default Dnd

0 comments on commit d2e02c4

Please sign in to comment.