Skip to content

Commit

Permalink
[SwipeableDrawer] Fix React 18 issues (mui#34505)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnajdova authored and Daniel Rabe committed Nov 29, 2022
1 parent 7f9436b commit 8b15a9e
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 2 deletions.
15 changes: 13 additions & 2 deletions packages/mui-material/src/SwipeableDrawer/SwipeableDrawer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import { flushSync } from 'react-dom';
import PropTypes from 'prop-types';
import { elementTypeAcceptingRef } from '@mui/utils';
import { useThemeProps } from '@mui/system';
Expand Down Expand Up @@ -234,7 +235,9 @@ const SwipeableDrawer = React.forwardRef(function SwipeableDrawer(inProps, ref)
}
claimedSwipeInstance = null;
touchDetected.current = false;
setMaybeSwiping(false);
flushSync(() => {
setMaybeSwiping(false);
});

// The swipe wasn't started.
if (!swipeInstance.current.isSwiping) {
Expand Down Expand Up @@ -488,7 +491,10 @@ const SwipeableDrawer = React.forwardRef(function SwipeableDrawer(inProps, ref)
swipeInstance.current.startX = currentX;
swipeInstance.current.startY = currentY;

setMaybeSwiping(true);
flushSync(() => {
setMaybeSwiping(true);
});

if (!open && paperRef.current) {
// The ref may be null when a parent component updates while swiping.
setPosition(
Expand Down Expand Up @@ -554,6 +560,11 @@ const SwipeableDrawer = React.forwardRef(function SwipeableDrawer(inProps, ref)
...BackdropProps,
ref: backdropRef,
},
// Ensures that paperRef.current will be defined inside the touch start event handler
// See https://github.com/mui/material-ui/issues/30414 for more information
...(variant === 'temporary' && {
keepMounted: true,
}),
...ModalPropsProp,
}}
hideBackdrop={hideBackdrop}
Expand Down
74 changes: 74 additions & 0 deletions packages/mui-material/src/SwipeableDrawer/SwipeableDrawer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,80 @@ describe('<SwipeableDrawer />', () => {
expect(handleClose.callCount).to.equal(1);
});

it('should open at correct position when swiping', function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
// Need layout
this.skip();
}
const handleClose = spy();
const handleOpen = spy();
const { getByTestId, setProps } = render(
<SwipeableDrawer
anchor={params.anchor}
onOpen={handleOpen}
onClose={handleClose}
open={false}
PaperProps={{ component: FakePaper }}
transitionDuration={0}
>
<div data-testid="drawer">SwipeableDrawer</div>
</SwipeableDrawer>,
);

const testParam = params.anchor === 'left' || params.anchor === 'right' ? 'x' : 'y';

const DRAG_STARTED_SIGNAL = 20; // Same as in SwipeableDrawer
const DRAWER_SIZE = 250;
const bodyMargin = document.body.getBoundingClientRect().x;
const absoluteBodyWidth = bodyWidth + bodyMargin * 2;

const swipeArea = document.querySelector('[class*=PrivateSwipeArea-root]');

fireEvent.touchStart(swipeArea, {
touches: [new Touch({ identifier: 0, target: swipeArea, ...params.openTouches[0] })],
});

let startPosition = -1 * (DRAWER_SIZE - DRAG_STARTED_SIGNAL); // default value for left & top anchor

if (params.anchor === 'right') {
startPosition = absoluteBodyWidth - DRAG_STARTED_SIGNAL;
}

if (params.anchor === 'bottom') {
startPosition = windowHeight - DRAG_STARTED_SIGNAL;
}
expect(getByTestId('drawer').getBoundingClientRect()[testParam]).to.equal(startPosition);

fireEvent.touchMove(swipeArea, {
touches: [new Touch({ identifier: 0, target: swipeArea, ...params.openTouches[1] })],
});

fireEvent.touchMove(swipeArea, {
touches: [new Touch({ identifier: 0, target: swipeArea, ...params.openTouches[2] })],
});

fireEvent.touchEnd(swipeArea, {
changedTouches: [
new Touch({ identifier: 0, target: swipeArea, ...params.openTouches[2] }),
],
});

expect(handleOpen.callCount).to.equal(1);
setProps({ open: true });

let endPosition = 0; // default value for left & top anchor

if (params.anchor === 'right') {
endPosition = absoluteBodyWidth - DRAWER_SIZE;
}

if (params.anchor === 'bottom') {
endPosition = windowHeight - DRAWER_SIZE;
}

expect(getByTestId('drawer').getBoundingClientRect()[testParam]).to.equal(endPosition);
});

it('should stay closed when not swiping far enough', () => {
// simulate open swipe that doesn't swipe far enough
const handleOpen = spy();
Expand Down

0 comments on commit 8b15a9e

Please sign in to comment.