Skip to content

Commit 047b931

Browse files
committed
Use react-smooth-dnd to handle drag-n-drop. Implement card dnd
1 parent a76e8c2 commit 047b931

6 files changed

Lines changed: 112 additions & 128 deletions

File tree

package.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
"main": "dist/index.js",
55
"jsnext:main": "components/index.js",
66
"module": "components/index.js",
7-
"files": ["src", "dist", "README"],
7+
"files": [
8+
"src",
9+
"dist",
10+
"README"
11+
],
812
"scripts": {
913
"prepublish": "npm run build",
1014
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
@@ -23,7 +27,11 @@
2327
"type": "git",
2428
"url": "https://github.com/rcdexta/react-trello"
2529
},
26-
"keywords": ["react", "trello", "board"],
30+
"keywords": [
31+
"react",
32+
"trello",
33+
"board"
34+
],
2735
"author": "RC, Prakash",
2836
"license": "MIT",
2937
"bugs": {
@@ -36,6 +44,7 @@
3644
"prop-types": "^15.6.0",
3745
"react-beautiful-dnd": "^7.1.0",
3846
"react-redux": "^5.0.3",
47+
"react-smooth-dnd": "^0.3.6",
3948
"redux": "^3.6.0",
4049
"redux-actions": "^1.2.2",
4150
"redux-logger": "^3.0.6",

src/components/BoardContainer.js

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import Lane from './Lane'
99

1010
import * as boardActions from '../actions/BoardActions'
1111
import * as laneActions from '../actions/LaneActions'
12-
import {DragDropContext} from 'react-beautiful-dnd'
1312

1413
class BoardContainer extends Component {
1514
wireEventBus = () => {
@@ -56,24 +55,10 @@ class BoardContainer extends Component {
5655
}
5756
}
5857

59-
onDragStart = card => {
60-
const {handleDragStart} = this.props
61-
handleDragStart(card.draggableId, card.source.droppableId)
58+
getCardDetails = (laneId, cardIndex) => {
59+
return this.props.reducerData.lanes.find(lane => lane.id === laneId).cards[cardIndex]
6260
}
6361

64-
onDragEnd = result => {
65-
const {handleDragEnd} = this.props
66-
const {source, destination, draggableId} = result
67-
if (destination) {
68-
this.props.actions.moveCardAcrossLanes({
69-
fromLaneId: source.droppableId,
70-
toLaneId: destination.droppableId,
71-
cardId: draggableId,
72-
index: destination.index
73-
})
74-
handleDragEnd(draggableId, source.droppableId, destination.droppableId, destination.index)
75-
}
76-
}
7762

7863
render() {
7964
const {reducerData, style, ...otherProps} = this.props
@@ -94,18 +79,20 @@ class BoardContainer extends Component {
9479
'newCardTemplate',
9580
'customLaneHeader',
9681
'tagStyle',
82+
'handleDragStart',
83+
'handleDragEnd',
9784
'children'
9885
])
9986

10087
return (
101-
<DragDropContext onDragStart={this.onDragStart} onDragEnd={this.onDragEnd}>
102-
<BoardDiv style={style} {...otherProps}>
88+
<BoardDiv style={style} {...otherProps} draggable={false}>
10389
{reducerData.lanes.map((lane, index) => {
10490
const {id, droppable, ...otherProps} = lane
10591
return (
10692
<Lane
10793
key={id}
10894
id={id}
95+
getCardDetails={this.getCardDetails}
10996
index={index}
11097
droppable={droppable === undefined ? true : droppable}
11198
{...otherProps}
@@ -114,7 +101,6 @@ class BoardContainer extends Component {
114101
)
115102
})}
116103
</BoardDiv>
117-
</DragDropContext>
118104
)
119105
}
120106
}

src/components/Card.js

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
1-
import React, {Component} from 'react';
2-
import PropTypes from 'prop-types';
3-
import {
4-
CardHeader,
5-
CardRightContent,
6-
CardTitle,
7-
Detail,
8-
Footer,
9-
MovableCardWrapper,
10-
} from '../styles/Base';
11-
import Tag from './Tag';
12-
import DeleteButton from './widgets/DeleteButton';
13-
import {Draggable} from 'react-beautiful-dnd';
1+
import React, {Component} from 'react'
2+
import PropTypes from 'prop-types'
3+
import {CardHeader, CardRightContent, CardTitle, Detail, Footer, MovableCardWrapper} from '../styles/Base'
4+
import Tag from './Tag'
5+
import DeleteButton from './widgets/DeleteButton'
146

157
class Card extends Component {
168
removeCard = e => {
@@ -39,42 +31,20 @@ class Card extends Component {
3931
}
4032
}
4133

42-
getItemStyle = (isDragging, draggableStyle) => ({
43-
backgroundColor: isDragging ? '#fbfbbc' : '#fff',
44-
...draggableStyle,
45-
margin: '0px 0px 7px 0px',
46-
})
47-
4834
render() {
49-
const {id, index, cardStyle, draggable, editable, hideCardDeleteIcon, customCardLayout, ...otherProps} = this.props
35+
const {id, cardStyle, editable, hideCardDeleteIcon, customCardLayout, ...otherProps} = this.props
5036
const style = customCardLayout ? {...cardStyle, padding: 0} : cardStyle
51-
const isDragDisabled = !draggable
5237
return (
53-
<Draggable key={id} draggableId={id} type="card" index={index} isDragDisabled={isDragDisabled} disableInteractiveElementBlocking={true}>
54-
{(dragProvided, dragSnapshot) => {
55-
const draggablePropsStyle = dragProvided.draggableProps && dragProvided.draggableProps.style
56-
const dragStyle = this.getItemStyle(dragSnapshot.isDragging, draggablePropsStyle)
57-
return (
58-
<span>
59-
<MovableCardWrapper
60-
key={id}
61-
data-id={id}
62-
innerRef={dragProvided.innerRef}
63-
{...dragProvided.draggableProps}
64-
{...dragProvided.dragHandleProps}
65-
style={{
66-
...dragStyle,
67-
...style,
68-
}}
69-
{...otherProps}>
70-
{this.renderBody()}
71-
{editable && !hideCardDeleteIcon && <DeleteButton onClick={this.removeCard} />}
72-
</MovableCardWrapper>
73-
{dragProvided.placeholder}
74-
</span>
75-
)
38+
<MovableCardWrapper
39+
key={id}
40+
data-id={id}
41+
style={{
42+
...style
7643
}}
77-
</Draggable>
44+
{...otherProps}>
45+
{this.renderBody()}
46+
{editable && !hideCardDeleteIcon && <DeleteButton onClick={this.removeCard} />}
47+
</MovableCardWrapper>
7848
)
7949
}
8050
}

src/components/Lane.js

Lines changed: 69 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,13 @@ import PropTypes from 'prop-types'
33
import {bindActionCreators} from 'redux'
44
import {connect} from 'react-redux'
55
import isEqual from 'lodash/isEqual'
6-
import {Droppable} from 'react-beautiful-dnd'
6+
import {Container, Draggable} from 'react-smooth-dnd'
77
import uuidv1 from 'uuid/v1'
88

99
import Loader from './Loader'
1010
import Card from './Card'
1111
import NewCard from './NewCard'
12-
import {
13-
AddCardLink,
14-
LaneFooter,
15-
LaneHeader,
16-
RightContent,
17-
ScrollableLane,
18-
Section,
19-
Title
20-
} from '../styles/Base'
12+
import {AddCardLink, LaneFooter, LaneHeader, RightContent, ScrollableLane, Section, Title} from '../styles/Base'
2113

2214
import * as laneActions from '../actions/LaneActions'
2315
import {CollapseBtn, ExpandBtn} from '../styles/Elements'
@@ -88,6 +80,7 @@ class Lane extends Component {
8880
const {onCardClick} = this.props
8981
onCardClick && onCardClick(card.id, card.metadata, card.laneId)
9082
e.stopPropagation()
83+
e.preventDefault()
9184
}
9285

9386
showEditableCard = () => {
@@ -129,33 +122,71 @@ class Lane extends Component {
129122
}
130123
}
131124

125+
onDragStart = (index, payload) => {
126+
const {handleDragStart} = this.props
127+
handleDragStart && handleDragStart(payload.id, payload.laneId)
128+
}
129+
130+
onDragEnd = (laneId, result) => {
131+
const {handleDragEnd} = this.props
132+
const {addedIndex, payload} = result
133+
if (addedIndex != null) {
134+
this.props.actions.moveCardAcrossLanes({
135+
fromLaneId: payload.laneId,
136+
toLaneId: laneId,
137+
cardId: payload.id,
138+
index: addedIndex
139+
})
140+
handleDragEnd && handleDragEnd(payload.id, payload.laneId, laneId, addedIndex)
141+
}
142+
}
143+
132144
renderDragContainer = isDraggingOver => {
133-
const {laneSortFunction, editable, hideCardDeleteIcon, tagStyle, cardStyle, draggable, cards} = this.props
145+
const {
146+
laneSortFunction,
147+
editable,
148+
hideCardDeleteIcon,
149+
tagStyle,
150+
cardStyle,
151+
draggable,
152+
droppable,
153+
cards,
154+
id
155+
} = this.props
134156
const {addCardMode, collapsed} = this.state
135157

136158
const showableCards = collapsed ? [] : cards
137159

138-
const cardList = this.sortCards(showableCards, laneSortFunction).map((card, idx) => (
139-
<Card
140-
key={card.id}
141-
index={idx}
142-
customCardLayout={this.props.customCardLayout}
143-
customCard={this.props.children}
144-
tagStyle={tagStyle}
145-
cardStyle={cardStyle}
146-
removeCard={this.removeCard}
147-
onClick={e => this.handleCardClick(e, card)}
148-
onDelete={this.props.onCardDelete}
149-
draggable={draggable}
150-
editable={editable}
151-
hideCardDeleteIcon={hideCardDeleteIcon}
152-
{...card}
153-
/>
154-
))
160+
const cardList = this.sortCards(showableCards, laneSortFunction).map((card, idx) => {
161+
const cardToRender = (
162+
<Card
163+
key={card.id}
164+
index={idx}
165+
customCardLayout={this.props.customCardLayout}
166+
customCard={this.props.children}
167+
tagStyle={tagStyle}
168+
cardStyle={cardStyle}
169+
removeCard={this.removeCard}
170+
onClick={e => this.handleCardClick(e, card)}
171+
onDelete={this.props.onCardDelete}
172+
editable={editable}
173+
hideCardDeleteIcon={hideCardDeleteIcon}
174+
{...card}
175+
/>
176+
)
177+
return draggable ? <Draggable key={card.id}>{cardToRender}</Draggable> : <span>{cardToRender}</span>
178+
})
155179

156180
return (
157181
<ScrollableLane innerRef={this.laneDidMount} isDraggingOver={isDraggingOver}>
158-
<span>{cardList}</span>
182+
<Container
183+
groupName="TrelloLane"
184+
onDragStart={this.onDragStart}
185+
onDrop={e => this.onDragEnd(id, e)}
186+
shouldAcceptDrop={() => droppable}
187+
getChildPayload={index => this.props.getCardDetails(id, index)}>
188+
{cardList}
189+
</Container>
159190
{editable && !addCardMode && this.renderAddCardLink()}
160191
{addCardMode && this.renderNewCard()}
161192
</ScrollableLane>
@@ -171,9 +202,7 @@ class Lane extends Component {
171202
const {title, label, titleStyle, labelStyle} = this.props
172203
return (
173204
<LaneHeader onDoubleClick={this.toggleLaneCollapsed}>
174-
<Title style={titleStyle}>
175-
{title}
176-
</Title>
205+
<Title style={titleStyle}>{title}</Title>
177206
{label && (
178207
<RightContent>
179208
<span style={labelStyle}>{label}</span>
@@ -188,9 +217,7 @@ class Lane extends Component {
188217
const {collapsibleLanes, cards} = this.props
189218
const {collapsed} = this.state
190219
if (collapsibleLanes && cards.length > 0) {
191-
return <LaneFooter onClick={this.toggleLaneCollapsed}>
192-
{collapsed ? <ExpandBtn/> : <CollapseBtn/>}
193-
</LaneFooter>
220+
return <LaneFooter onClick={this.toggleLaneCollapsed}>{collapsed ? <ExpandBtn /> : <CollapseBtn />}</LaneFooter>
194221
}
195222
}
196223

@@ -200,33 +227,14 @@ class Lane extends Component {
200227

201228
render() {
202229
const {loading} = this.state
203-
const {id, onLaneClick, index, droppable, ...otherProps} = this.props
204-
const isDropDisabled = !droppable
230+
const {id, onLaneClick, ...otherProps} = this.props
205231
return (
206-
<Droppable
207-
droppableId={id}
208-
type="card"
209-
index={index}
210-
isDropDisabled={isDropDisabled}
211-
ignoreContainerClipping={false}>
212-
{(dropProvided, dropSnapshot) => {
213-
const isDraggingOver = dropSnapshot.isDraggingOver
214-
return (
215-
<Section
216-
{...otherProps}
217-
key={id}
218-
onClick={() => onLaneClick && onLaneClick(id)}
219-
innerRef={dropProvided.innerRef}
220-
isDraggingOver={isDraggingOver}
221-
{...dropProvided.draggableProps}>
222-
{this.renderHeader()}
223-
{this.renderDragContainer(isDraggingOver)}
224-
{loading && <Loader />}
225-
{this.renderFooter()}
226-
</Section>
227-
)
228-
}}
229-
</Droppable>
232+
<Section {...otherProps} key={id} onClick={() => onLaneClick && onLaneClick(id)} draggable={false}>
233+
{this.renderHeader()}
234+
{this.renderDragContainer(false)}
235+
{loading && <Loader />}
236+
{this.renderFooter()}
237+
</Section>
230238
)
231239
}
232240
}

stories/data/data-sort.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
{
23
"lanes": [
34
{

yarn.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7229,6 +7229,12 @@ react-simple-di@^1.2.0:
72297229
babel-runtime "6.x.x"
72307230
hoist-non-react-statics "1.x.x"
72317231

7232+
react-smooth-dnd@^0.3.6:
7233+
version "0.3.6"
7234+
resolved "https://registry.yarnpkg.com/react-smooth-dnd/-/react-smooth-dnd-0.3.6.tgz#754e4b3848dd8f8bcee6d25b276d55b863c47aab"
7235+
dependencies:
7236+
smooth-dnd "^0.3.7"
7237+
72327238
react-split-pane@^0.1.65:
72337239
version "0.1.66"
72347240
resolved "https://registry.yarnpkg.com/react-split-pane/-/react-split-pane-0.1.66.tgz#369085dd07ec1237bda123e73813dcc7dc6502c1"
@@ -8027,6 +8033,10 @@ slide@^1.1.3, slide@^1.1.5:
80278033
version "1.1.6"
80288034
resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
80298035

8036+
smooth-dnd@^0.3.7:
8037+
version "0.3.9"
8038+
resolved "https://registry.yarnpkg.com/smooth-dnd/-/smooth-dnd-0.3.9.tgz#f970a0df9e4da04682f97fe4980866e9d626d9cb"
8039+
80308040
sntp@0.2.x:
80318041
version "0.2.4"
80328042
resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900"

0 commit comments

Comments
 (0)