diff --git a/lib/utils/positionFns.js b/lib/utils/positionFns.js
index 74b57e5a..248d4d0b 100644
--- a/lib/utils/positionFns.js
+++ b/lib/utils/positionFns.js
@@ -22,8 +22,14 @@ export function getBoundPosition(draggable: Draggable, x: number, y: number): [n
if (bounds === 'parent') {
boundNode = node.parentNode;
} else {
- boundNode = ownerDocument.querySelector(bounds);
+ // Flow assigns the wrong return type (Node) for getRootNode(),
+ // so we cast it to one of the correct types (Element).
+ // The others are Document and ShadowRoot.
+ // All three implement querySelector() so it's safe to call.
+ const rootNode = (((node.getRootNode()): any): Element);
+ boundNode = rootNode.querySelector(bounds);
}
+
if (!(boundNode instanceof ownerWindow.HTMLElement)) {
throw new Error('Bounds selector "' + bounds + '" could not find an element.');
}
diff --git a/specs/draggable.spec.jsx b/specs/draggable.spec.jsx
index 143eae96..cd014f78 100644
--- a/specs/draggable.spec.jsx
+++ b/specs/draggable.spec.jsx
@@ -807,6 +807,129 @@ describe('react-draggable', function () {
});
+ it('should clip dragging to parent, with bounds set to "parent"', function(done){
+ function onDrag(event, data) {
+ assert.equal(data.x, 100);
+ assert.equal(data.y, 100);
+ assert.equal(data.deltaX, 50);
+ assert.equal(data.deltaY, 50);
+ done();
+ }
+ drag = TestUtils.renderIntoDocument(
+
+
+
+ );
+ const node = ReactDOM.findDOMNode(drag);
+
+ // Create a parent container.
+ const fragment = fragmentFromString(`
+
+
+ `);
+ transplantNodeInto(node, fragment, (f) => f);
+
+
+ // (element, fromX, fromY, toX, toY)
+ simulateMovementFromTo(drag, 50, 50, 350, 350);
+
+ });
+
+ it('should clip dragging to parent, with bounds set to "parent", in a shadow tree', function(done){
+ function onDrag(event, data) {
+ assert.equal(data.x, 100);
+ assert.equal(data.y, 100);
+ assert.equal(data.deltaX, 50);
+ assert.equal(data.deltaY, 50);
+ done();
+ }
+ drag = TestUtils.renderIntoDocument(
+
+
+
+ );
+ const node = ReactDOM.findDOMNode(drag);
+
+ // Create a parent container.
+ const fragment = fragmentFromString(`
+
+
+ `);
+
+ // Add the parent fragment to a shadow root
+ const div = document.createElement('div');
+ const shadowRoot = div.attachShadow({mode: 'open'});
+ shadowRoot.appendChild(fragment);
+
+ transplantNodeInto(node, shadowRoot, (f) => f.children[0]);
+
+
+ // (element, fromX, fromY, toX, toY)
+ simulateMovementFromTo(drag, 50, 50, 350, 350);
+
+ });
+
+ it('should clip dragging to parent, with bounds set to selector', function(done){
+ function onDrag(event, data) {
+ assert.equal(data.x, 100);
+ assert.equal(data.y, 100);
+ assert.equal(data.deltaX, 50);
+ assert.equal(data.deltaY, 50);
+ done();
+ }
+ drag = TestUtils.renderIntoDocument(
+
+
+
+ );
+ const node = ReactDOM.findDOMNode(drag);
+
+ // Create a parent container.
+ const fragment = fragmentFromString(`
+
+
+ `);
+ transplantNodeInto(node, fragment, (f) => f);
+
+
+ // (element, fromX, fromY, toX, toY)
+ simulateMovementFromTo(drag, 50, 50, 350, 350);
+
+ });
+
+ it('should clip dragging to parent, with bounds set to selector, in a shadow tree', function(done){
+ function onDrag(event, data) {
+ assert.equal(data.x, 100);
+ assert.equal(data.y, 100);
+ assert.equal(data.deltaX, 50);
+ assert.equal(data.deltaY, 50);
+ done();
+ }
+ drag = TestUtils.renderIntoDocument(
+
+
+
+ );
+ const node = ReactDOM.findDOMNode(drag);
+
+ // Create a parent container.
+ const fragment = fragmentFromString(`
+
+
+ `);
+
+ // Add the parent fragment to a shadow root
+ const div = document.createElement('div');
+ const shadowRoot = div.attachShadow({mode: 'open'});
+ shadowRoot.appendChild(fragment);
+
+ transplantNodeInto(node, shadowRoot, (f) => f.children[0]);
+
+ // (element, fromX, fromY, toX, toY)
+ simulateMovementFromTo(drag, 50, 50, 350, 350);
+
+ });
+
it('should call back with offset left/top, not client', function(done) {
function onDrag(event, data) {
assert.equal(data.x, 100);