Skip to content

Commit aa0a6b4

Browse files
tnrichSTRML
authored andcommitted
feat(defaultPosition): now allows strings (#361)
* defaultPosition now allows strings * fixing flow linting by adding new DefaultControlPosition type, fixing createSVGTransform to use calc with defaultPosition, adding a test for the new functionality * updating createCSSTransform and createSVGTransform to use two translates instead of a calc function do to IE incompatibility; updating spec to reflect changes * using DefaultControlPosition; fixing svg transform units issue; improving readability * types(domFns): use `ControlPosition`
1 parent 8c3083c commit aa0a6b4

File tree

6 files changed

+53
-15
lines changed

6 files changed

+53
-15
lines changed

example/example.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ var App = React.createClass({
137137
{"I have a default position of {x: 25, y: 25}, so I'm slightly offset."}
138138
</div>
139139
</Draggable>
140+
<Draggable defaultPosition={{x: '-10%', y: '-10%'}} {...dragHandlers}>
141+
<div className="box">
142+
{'I have a default position based on percents {x: \'-10%\', y: \'-10%\'}, so I\'m slightly offset.'}
143+
</div>
144+
</Draggable>
140145
<Draggable position={controlledPosition} {...dragHandlers} onDrag={this.onControlledDrag}>
141146
<div className="box">
142147
My position can be changed programmatically. <br />

lib/Draggable.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {createCSSTransform, createSVGTransform} from './utils/domFns';
77
import {canDragX, canDragY, createDraggableData, getBoundPosition} from './utils/positionFns';
88
import {dontSetMe} from './utils/shims';
99
import DraggableCore from './DraggableCore';
10-
import type {ControlPosition, DraggableBounds, DraggableCoreProps} from './DraggableCore';
10+
import type {ControlPosition, DefaultControlPosition, DraggableBounds, DraggableCoreProps} from './DraggableCore';
1111
import log from './utils/log';
1212
import type {DraggableEventHandler} from './utils/types';
1313
import type {Element as ReactElement} from 'react';
@@ -27,7 +27,7 @@ export type DraggableProps = {
2727
defaultClassName: string,
2828
defaultClassNameDragging: string,
2929
defaultClassNameDragged: string,
30-
defaultPosition: ControlPosition,
30+
defaultPosition: DefaultControlPosition,
3131
position: ControlPosition,
3232
scale: number
3333
};
@@ -118,8 +118,8 @@ export default class Draggable extends React.Component<DraggableProps, Draggable
118118
* ```
119119
*/
120120
defaultPosition: PropTypes.shape({
121-
x: PropTypes.number,
122-
y: PropTypes.number
121+
x: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
122+
y: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
123123
}),
124124

125125
/**
@@ -178,8 +178,8 @@ export default class Draggable extends React.Component<DraggableProps, Draggable
178178
dragged: false,
179179

180180
// Current transform x and y.
181-
x: props.position ? props.position.x : props.defaultPosition.x,
182-
y: props.position ? props.position.y : props.defaultPosition.y,
181+
x: props.position ? props.position.x : 0,
182+
y: props.position ? props.position.y : 0,
183183

184184
// Used for compensating for out-of-bounds drags
185185
slackX: 0, slackY: 0,
@@ -311,7 +311,7 @@ export default class Draggable extends React.Component<DraggableProps, Draggable
311311
const controlled = Boolean(this.props.position);
312312
const draggable = !controlled || this.state.dragging;
313313

314-
const position = this.props.position || this.props.defaultPosition;
314+
const position = this.props.position || {x:0, y:0};
315315
const transformOpts = {
316316
// Set left if horizontal drag is enabled
317317
x: canDragX(this) && draggable ?
@@ -326,13 +326,13 @@ export default class Draggable extends React.Component<DraggableProps, Draggable
326326

327327
// If this element was SVG, we use the `transform` attribute.
328328
if (this.state.isElementSVG) {
329-
svgTransform = createSVGTransform(transformOpts);
329+
svgTransform = createSVGTransform(transformOpts, this.props.defaultPosition);
330330
} else {
331331
// Add a CSS transform to move the element around. This allows us to move the element around
332332
// without worrying about whether or not it is relatively or absolutely positioned.
333333
// If the item you are dragging already has a transform set, wrap it in a <span> so <Draggable>
334334
// has a clean slate.
335-
style = createCSSTransform(transformOpts);
335+
style = createCSSTransform(transformOpts, this.props.defaultPosition);
336336
}
337337

338338
const {

lib/DraggableCore.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export type DraggableData = {
5252
export type DraggableEventHandler = (e: MouseEvent, data: DraggableData) => void;
5353

5454
export type ControlPosition = {x: number, y: number};
55+
export type DefaultControlPosition = {x: number|string, y: number|string};
5556

5657
export type DraggableCoreProps = {
5758
allowAnyClick: boolean,

lib/utils/domFns.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import {findInArray, isFunction, int} from './shims';
33
import browserPrefix, {browserPrefixToKey} from './getPrefix';
44

5-
import type {ControlPosition, MouseTouchEvent} from './types';
5+
import type {ControlPosition, DefaultControlPosition, MouseTouchEvent} from './types';
66

77
let matchesSelectorFunc = '';
88
export function matchesSelector(el: Node, selector: string): boolean {
@@ -109,13 +109,28 @@ export function offsetXYFromParent(evt: {clientX: number, clientY: number}, offs
109109
return {x, y};
110110
}
111111

112-
export function createCSSTransform({x, y}: {x: number, y: number}): Object {
113-
// Replace unitless items with px
114-
return {[browserPrefixToKey('transform', browserPrefix)]: 'translate(' + x + 'px,' + y + 'px)'};
112+
export function createCSSTransform({x, y}: ControlPosition, defaultPosition: DefaultControlPosition): Object {
113+
let translation;
114+
if (defaultPosition && (defaultPosition.x !== 0 || defaultPosition.y !== 0)) {
115+
const defaultX = `${(typeof defaultPosition.x === 'string') ? defaultPosition.x : defaultPosition.x + 'px'}`;
116+
const defaultY = `${(typeof defaultPosition.y === 'string') ? defaultPosition.y : defaultPosition.y + 'px'}`;
117+
translation = `translate(${defaultX}, ${defaultY}) translate(${x}px,${y}px)`;
118+
} else {
119+
translation = `translate(${x}px,${y}px)`;
120+
}
121+
return {[browserPrefixToKey('transform', browserPrefix)]: translation };
115122
}
116123

117-
export function createSVGTransform({x, y}: {x: number, y: number}): string {
118-
return 'translate(' + x + ',' + y + ')';
124+
export function createSVGTransform({x, y}: ControlPosition, defaultPosition: DefaultControlPosition): string {
125+
let translation;
126+
if (defaultPosition && (defaultPosition.x !== 0 || defaultPosition.y !== 0)) {
127+
const defaultX = (typeof defaultPosition.x === 'string') ? defaultPosition.x : defaultPosition.x;
128+
const defaultY = (typeof defaultPosition.y === 'string') ? defaultPosition.y : defaultPosition.y;
129+
translation = `translate(${defaultX}, ${defaultY}) translate(${x},${y})`;
130+
} else {
131+
translation = `translate(${x},${y})`;
132+
}
133+
return translation;
119134
}
120135

121136
export function getTouch(e: MouseTouchEvent, identifier: number): ?{clientX: number, clientY: number} {

lib/utils/types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type Bounds = {
1414
left: number, top: number, right: number, bottom: number
1515
};
1616
export type ControlPosition = {x: number, y: number};
17+
export type DefaultControlPosition = {x: number|string, y: number|string};
1718
export type EventHandler<T> = (e: T) => void | false;
1819

1920
// Missing in Flow

specs/draggable.spec.jsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,22 @@ describe('react-draggable', function () {
257257
assert(style.indexOf('transform: translate(100px, 100px);') >= 0);
258258
});
259259

260+
it('should render with defaultPosition set as string transform and handle subsequent translate() for DOM nodes', function () {
261+
let dragged = false;
262+
drag = TestUtils.renderIntoDocument(
263+
<Draggable defaultPosition={{x: '10%', y: '10%'}} onDrag={function() { dragged = true; }}>
264+
<div />
265+
</Draggable>
266+
);
267+
268+
const node = ReactDOM.findDOMNode(drag);
269+
simulateMovementFromTo(drag, 0, 0, 100, 100);
270+
271+
const style = node.getAttribute('style');
272+
assert(dragged === true);
273+
assert(style.indexOf('translate(10%, 10%) translate(100px, 100px);') >= 0);
274+
});
275+
260276
it('should honor "x" axis', function () {
261277
let dragged = false;
262278
drag = TestUtils.renderIntoDocument(

0 commit comments

Comments
 (0)