Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use strict';

let ReactFiberConfigDOM;

beforeEach(() => {
jest.resetModules();
ReactFiberConfigDOM = require('../client/ReactFiberConfigDOM');
});

test('measureClonedInstance adjusts x using RTL sign', () => {
const instance = document.createElement('div');
// Simulate the element being moved out of viewport by +20000 in RTL
document.documentElement.dir = 'rtl';
instance.getBoundingClientRect = () => new DOMRect(20100, 150, 50, 20);
const measurement = ReactFiberConfigDOM.measureClonedInstance(instance);
// Expect the x to be adjusted back to original (20100 - 20000)
expect(measurement.rect.x).toBe(100);
expect(measurement.rect.y).toBe(150 + 20000);

// LTR case
document.documentElement.dir = 'ltr';
instance.getBoundingClientRect = () => new DOMRect(-19900, 250, 30, 10);
const measurement2 = ReactFiberConfigDOM.measureClonedInstance(instance);
expect(measurement2.rect.x).toBe(100);
expect(measurement2.rect.y).toBe(250 + 20000);
});

test('moveOldFrameIntoViewport uses RTL-aware horizontal offset', () => {
const keyframe = {transform: 'none'};
const targetElement = document.createElement('div');

document.documentElement.dir = 'ltr';
ReactFiberConfigDOM.moveOldFrameIntoViewport(keyframe, targetElement);
expect(keyframe.transform.startsWith('translate(20000px, 20000px)')).toBe(true);

keyframe.transform = 'none';
document.documentElement.dir = 'rtl';
ReactFiberConfigDOM.moveOldFrameIntoViewport(keyframe, targetElement);
expect(keyframe.transform.startsWith('translate(-20000px, 20000px)')).toBe(true);
});
38 changes: 30 additions & 8 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -1722,18 +1722,26 @@ function moveOutOfViewport(
// other transforms. That's why we need to merge the long form properties.
// TODO: Ideally we'd adjust for the parent's rotate/scale. Otherwise when
// we move back the ::view-transition-group we might overshoot or undershoot.
element.style.transform = 'translate(-20000px, -20000px) ' + transform;
const ownerDoc = element.ownerDocument;
const isRTL = ownerDoc && ownerDoc.documentElement && ownerDoc.documentElement.dir === 'rtl';
const translateX = isRTL ? '20000px' : '-20000px';
element.style.transform = 'translate(' + translateX + ', -20000px) ' + transform;
}

function moveOldFrameIntoViewport(keyframe: any): void {
export function moveOldFrameIntoViewport(keyframe: any, targetElement: ?HTMLElement): void {
// In the resulting View Transition Animation, the first frame will be offset.
const computedTransform: ?string = keyframe.transform;
if (computedTransform != null) {
let transform = computedTransform === 'none' ? '' : computedTransform;
transform = 'translate(20000px, 20000px) ' + transform;
const isRTL =
targetElement &&
targetElement.ownerDocument &&
targetElement.ownerDocument.documentElement.dir === 'rtl';
const dx = isRTL ? '-20000px' : '20000px';
transform = 'translate(' + dx + ', 20000px) ' + transform;
keyframe.transform = transform;
}
}
}

export function cloneRootViewTransitionContainer(
rootContainer: Container,
Expand Down Expand Up @@ -1942,8 +1950,12 @@ export function measureClonedInstance(instance: Instance): InstanceMeasurement {
const measuredRect = instance.getBoundingClientRect();
// Adjust the DOMRect based on the translate that put it outside the viewport.
// TODO: This might not be completely correct if the parent also has a transform.
const isRTL =
instance &&
instance.ownerDocument &&
instance.ownerDocument.documentElement.dir === 'rtl';
const rect = new DOMRect(
measuredRect.x + 20000,
measuredRect.x + (isRTL ? -20000 : 20000),
measuredRect.y + 20000,
measuredRect.width,
measuredRect.height,
Expand Down Expand Up @@ -2426,14 +2438,24 @@ function animateGesture(
targetElement,
pseudoElement,
): any).translate;
const isRTL =
targetElement &&
targetElement.ownerDocument &&
targetElement.ownerDocument.documentElement.dir === 'rtl';
const translateToAdd = isRTL ? '-20000px 20000px' : '20000px 20000px';
keyframe.translate = mergeTranslate(
elementTranslate,
'20000px 20000px',
translateToAdd,
);
} else {
const isRTL =
targetElement &&
targetElement.ownerDocument &&
targetElement.ownerDocument.documentElement.dir === 'rtl';
const translateToAdd = isRTL ? '-20000px 20000px' : '20000px 20000px';
keyframe.translate = mergeTranslate(
keyframe.translate,
'20000px 20000px',
translateToAdd,
);
}
}
Expand All @@ -2444,7 +2466,7 @@ function animateGesture(
// from the old position, we need to adjust it from the out of viewport
// position. If this is going from old to new it only applies to first
// keyframe. Otherwise it applies to every keyframe.
moveOldFrameIntoViewport(keyframes[0]);
moveOldFrameIntoViewport(keyframes[0], targetElement);
}
if (unchangedDimensions && width !== undefined && height !== undefined) {
// Read the underlying width/height of the pseudo-element. The previous animation
Expand Down