Skip to content

Commit f7df5a4

Browse files
committed
Allow controlled components to be moved, but they revert to position onStop.
1 parent da38df4 commit f7df5a4

File tree

2 files changed

+52
-10
lines changed

2 files changed

+52
-10
lines changed

example/index.html

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@
106106
this.setState({controlledPosition: {x, y: y - 10}});
107107
},
108108

109+
onControlledDrag: function(e, position) {
110+
const {x, y} = position;
111+
this.setState({controlledPosition: {x, y}});
112+
},
113+
109114
onControlledDragStop: function(e, position) {
110115
const {x, y} = position;
111116
this.setState({controlledPosition: {x, y}});
@@ -188,9 +193,22 @@ <h1>React Draggable</h1>
188193
{"I have a default position of {x: 25, y: 25}, so I'm slightly offset."}
189194
</div>
190195
</Draggable>
191-
<Draggable zIndex={100} position={controlledPosition} {...dragHandlers} onDragStop={this.onControlledDragStop}>
196+
<Draggable zIndex={100} position={controlledPosition} {...dragHandlers} onDrag={this.onControlledDrag}>
197+
<div className="box">
198+
My position can be changed programmatically. <br />
199+
I have a drag handler to sync state.
200+
<p>
201+
<a href="#" onClick={this.adjustXPos}>Adjust x ({controlledPosition.x})</a>
202+
</p>
203+
<p>
204+
<a href="#" onClick={this.adjustYPos}>Adjust y ({controlledPosition.y})</a>
205+
</p>
206+
</div>
207+
</Draggable>
208+
<Draggable zIndex={100} position={controlledPosition} {...dragHandlers} onStop={this.onControlledDragStop}>
192209
<div className="box">
193-
My position can be changed programmatically.
210+
My position can be changed programmatically. <br />
211+
I have a dragStop handler to sync state.
194212
<p>
195213
<a href="#" onClick={this.adjustXPos}>Adjust x ({controlledPosition.x})</a>
196214
</p>
@@ -199,6 +217,7 @@ <h1>React Draggable</h1>
199217
</p>
200218
</div>
201219
</Draggable>
220+
202221
</div>
203222
);
204223
}

lib/Draggable.es6

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,15 @@ export default class Draggable extends React.Component {
163163
isElementSVG: false
164164
};
165165

166+
componentWillMount() {
167+
if (this.props.position && !(this.props.onDrag || this.props.onStop)) {
168+
// eslint-disable-next-line
169+
console.warn('A `position` was applied to this <Draggable>, without drag handlers. This will make this ' +
170+
'component effectively undraggable. Please attach `onDrag` or `onStop` handlers so you can adjust the ' +
171+
'`position` of this element.');
172+
}
173+
}
174+
166175
componentDidMount() {
167176
// Check to see if the element passed is an instanceof SVGElement
168177
if(ReactDOM.findDOMNode(this) instanceof SVGElement) {
@@ -250,30 +259,40 @@ export default class Draggable extends React.Component {
250259

251260
log('Draggable: onDragStop: %j', coreData);
252261

253-
this.setState({
262+
const newState: $Shape<DraggableState> = {
254263
dragging: false,
255264
slackX: 0,
256265
slackY: 0
257-
});
266+
};
267+
268+
// If this is a controlled component, the result of this operation will be to
269+
// revert back to the old position. We expect a handler on `onDragStop`, at the least.
270+
const controlled = Boolean(this.props.position);
271+
if (controlled) {
272+
const {x, y} = this.props.position;
273+
newState.x = x;
274+
newState.y = y;
275+
}
276+
277+
this.setState(newState);
258278
};
259279

260280
render(): React.Element {
261281
let style = {}, svgTransform = null;
262282

263-
// Add a CSS transform to move the element around. This allows us to move the element around
264-
// without worrying about whether or not it is relatively or absolutely positioned.
265-
// If the item you are dragging already has a transform set, wrap it in a <span> so <Draggable>
266-
// has a clean slate.
283+
// If this is controlled, we don't want to move it - unless it's dragging.
267284
const controlled = Boolean(this.props.position);
285+
const draggable = !controlled || this.state.dragging;
286+
268287
const position = this.props.position || this.props.defaultPosition;
269288
const transformOpts = {
270289
// Set left if horizontal drag is enabled
271-
x: canDragX(this) && !controlled ?
290+
x: canDragX(this) && draggable ?
272291
this.state.x :
273292
position.x,
274293

275294
// Set top if vertical drag is enabled
276-
y: canDragY(this) && !controlled ?
295+
y: canDragY(this) && draggable ?
277296
this.state.y :
278297
position.y
279298
};
@@ -282,6 +301,10 @@ export default class Draggable extends React.Component {
282301
if (this.state.isElementSVG) {
283302
svgTransform = createSVGTransform(transformOpts);
284303
} else {
304+
// Add a CSS transform to move the element around. This allows us to move the element around
305+
// without worrying about whether or not it is relatively or absolutely positioned.
306+
// If the item you are dragging already has a transform set, wrap it in a <span> so <Draggable>
307+
// has a clean slate.
285308
style = createCSSTransform(transformOpts);
286309
}
287310

0 commit comments

Comments
 (0)