Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bounds="selector" functionality when in a Shadow DOM tree. #763

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/utils/positionFns.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.');
}
Expand Down
123 changes: 123 additions & 0 deletions specs/draggable.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<Draggable onDrag={onDrag} bounds="parent" defaultPosition={{x:50,y:50}}>
<div style={{position: 'relative', width:'100px', height:'100px'}} />
</Draggable>
);
const node = ReactDOM.findDOMNode(drag);

// Create a parent container.
const fragment = fragmentFromString(`
<div style="position: relative; width: 200px; height: 200px;">
</div>
`);
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(
<Draggable onDrag={onDrag} bounds="parent" defaultPosition={{x:50,y:50}}>
<div style={{position: 'relative', width:'100px', height:'100px'}} />
</Draggable>
);
const node = ReactDOM.findDOMNode(drag);

// Create a parent container.
const fragment = fragmentFromString(`
<div style="position: relative; width: 200px; height: 200px;">
</div>
`);

// 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(
<Draggable onDrag={onDrag} bounds="#container" defaultPosition={{x:50,y:50}}>
<div style={{position: 'relative', width:'100px', height:'100px'}} />
</Draggable>
);
const node = ReactDOM.findDOMNode(drag);

// Create a parent container.
const fragment = fragmentFromString(`
<div id="container" style="position: relative; width: 200px; height: 200px;">
</div>
`);
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(
<Draggable onDrag={onDrag} bounds="#container" defaultPosition={{x:50,y:50}}>
<div style={{position: 'relative', width:'100px', height:'100px'}} />
</Draggable>
);
const node = ReactDOM.findDOMNode(drag);

// Create a parent container.
const fragment = fragmentFromString(`
<div id="container" style="position: relative; width: 200px; height: 200px;">
</div>
`);

// 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);
Expand Down