Skip to content

Commit

Permalink
Event API: ensure calculateResponderRegion accounts for page offset (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
trueadm committed May 16, 2019
1 parent bb89b4e commit aad5a26
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 6 deletions.
31 changes: 25 additions & 6 deletions packages/react-events/src/Press.js
Expand Up @@ -428,6 +428,29 @@ function calculateDelayMS(delay: ?number, min = 0, fallback = 0) {
return Math.max(min, maybeNumber != null ? maybeNumber : fallback);
}

function getAbsoluteBoundingClientRect(
target: Element,
): {left: number, right: number, bottom: number, top: number} {
const clientRect = target.getBoundingClientRect();
let {left, right, bottom, top} = clientRect;
let node = target.parentNode;
let offsetX = 0;
let offsetY = 0;

// Traverse through all offset nodes
while (node != null && node.nodeType !== Node.DOCUMENT_NODE) {
offsetX += (node: any).scrollLeft;
offsetY += (node: any).scrollTop;
node = node.parentNode;
}
return {
left: left + offsetX,
right: right + offsetX,
bottom: bottom + offsetY,
top: top + offsetY,
};
}

// TODO: account for touch hit slop
function calculateResponderRegion(
context: ReactResponderContext,
Expand All @@ -440,12 +463,8 @@ function calculateResponderRegion(
props.pressRetentionOffset,
);

const clientRect = target.getBoundingClientRect();

let bottom = clientRect.bottom;
let left = clientRect.left;
let right = clientRect.right;
let top = clientRect.top;
const clientRect = getAbsoluteBoundingClientRect(target);
let {left, right, bottom, top} = clientRect;

if (pressRetentionOffset) {
if (pressRetentionOffset.bottom != null) {
Expand Down
51 changes: 51 additions & 0 deletions packages/react-events/src/__tests__/Press-test.internal.js
Expand Up @@ -1085,6 +1085,57 @@ describe('Event responder: Press', () => {
});
});

describe('the page offset changes', () => {
it('"onPress" is called on release', () => {
let events = [];
const ref = React.createRef();
const createEventHandler = msg => () => {
events.push(msg);
};

const element = (
<Press
onPress={createEventHandler('onPress')}
onPressChange={createEventHandler('onPressChange')}
onPressMove={createEventHandler('onPressMove')}
onPressStart={createEventHandler('onPressStart')}
onPressEnd={createEventHandler('onPressEnd')}>
<div ref={ref} />
</Press>
);

ReactDOM.render(element, container);

ref.current.getBoundingClientRect = getBoundingClientRectMock;
// Emulate the element being offset
document.body.scrollTop = 1000;
const updatedCoordinatesInside = {
pageX: coordinatesInside.pageX,
pageY: coordinatesInside.pageY + 1000,
};
ref.current.dispatchEvent(
createEvent('pointerdown', updatedCoordinatesInside),
);
container.dispatchEvent(
createEvent('pointermove', updatedCoordinatesInside),
);
container.dispatchEvent(
createEvent('pointerup', updatedCoordinatesInside),
);
jest.runAllTimers();
document.body.scrollTop = 0;

expect(events).toEqual([
'onPressStart',
'onPressChange',
'onPressMove',
'onPressEnd',
'onPressChange',
'onPress',
]);
});
});

describe('beyond bounds of hit rect', () => {
/** ┌──────────────────┐
* │ ┌────────────┐ │
Expand Down

0 comments on commit aad5a26

Please sign in to comment.