Event API: ensure calculateResponderRegion accounts for page offset (#15671)
This commit is contained in:
parent
bb89b4eacc
commit
aad5a264d2
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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', () => {
|
||||
/** ┌──────────────────┐
|
||||
* │ ┌────────────┐ │
|
||||
|
|
Loading…
Reference in New Issue