Skip to content

Commit

Permalink
[Modal] Remove scroll even if no overflow to account for mobile keyboard
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviertassinari committed Oct 21, 2019
1 parent 580cbf9 commit d27ff2c
Show file tree
Hide file tree
Showing 15 changed files with 99 additions and 82 deletions.
7 changes: 6 additions & 1 deletion docs/src/pages/components/modal/ServerModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ import Modal from '@material-ui/core/Modal';

const useStyles = makeStyles(theme => ({
root: {
transform: 'translateZ(0)',
height: 300,
flexGrow: 1,
transform: 'translateZ(0)',
// The position fixed scoping doesn't work in IE 11.
// Disable this demo to preserve the others.
'@media all and (-ms-high-contrast: none)': {
display: 'none',
},
},
modal: {
display: 'flex',
Expand Down
7 changes: 6 additions & 1 deletion docs/src/pages/components/modal/ServerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ import Modal from '@material-ui/core/Modal';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
transform: 'translateZ(0)',
height: 300,
flexGrow: 1,
transform: 'translateZ(0)',
// The position fixed scoping doesn't work in IE 11.
// Disable this demo to preserve the others.
'@media all and (-ms-high-contrast: none)': {
display: 'none',
},
},
modal: {
display: 'flex',
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/components/modal/SpringModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Modal from '@material-ui/core/Modal';
import Backdrop from '@material-ui/core/Backdrop';
import { useSpring, animated } from 'react-spring';
import { useSpring, animated } from 'react-spring/web.cjs';

const useStyles = makeStyles(theme => ({
modal: {
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/components/modal/SpringModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
import Modal from '@material-ui/core/Modal';
import Backdrop from '@material-ui/core/Backdrop';
import { useSpring, animated } from 'react-spring';
import { useSpring, animated } from 'react-spring/web.cjs' // web.cjs is required for IE 11 support

const useStyles = makeStyles((theme: Theme) =>
createStyles({
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/components/popper/SpringPopper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Popper from '@material-ui/core/Popper';
import { useSpring, animated } from 'react-spring';
import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support

const useStyles = makeStyles(theme => ({
paper: {
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/components/popper/SpringPopper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React from 'react';
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
import Popper from '@material-ui/core/Popper';
import { useSpring, animated } from 'react-spring';
import { useSpring, animated } from 'react-spring/web.cjs' // web.cjs is required for IE 11 support

const useStyles = makeStyles((theme: Theme) =>
createStyles({
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/components/tree-view/CustomizedTreeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { fade, makeStyles, withStyles } from '@material-ui/core/styles';
import TreeView from '@material-ui/lab/TreeView';
import TreeItem from '@material-ui/lab/TreeItem';
import Collapse from '@material-ui/core/Collapse';
import { useSpring, animated } from 'react-spring';
import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support

function MinusSquare(props) {
return (
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/components/tree-view/CustomizedTreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { fade, makeStyles, withStyles, Theme, createStyles } from '@material-ui/
import TreeView from '@material-ui/lab/TreeView';
import TreeItem, { TreeItemProps } from '@material-ui/lab/TreeItem';
import Collapse from '@material-ui/core/Collapse';
import { useSpring, animated } from 'react-spring';
import { useSpring, animated } from 'react-spring/web.cjs' // web.cjs is required for IE 11 support
import { TransitionProps } from '@material-ui/core/transitions';

function MinusSquare(props: SvgIconProps) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ describe('<ClickAwayListener />', () => {
</ClickAwayListener>,
);
const preventDefault = event => event.preventDefault();
window.document.body.addEventListener('click', preventDefault);
document.body.addEventListener('click', preventDefault);

const event = new window.Event('click', { view: window, bubbles: true, cancelable: true });
window.document.body.dispatchEvent(event);
document.body.dispatchEvent(event);
assert.strictEqual(handleClickAway.callCount, 0);

window.document.body.removeEventListener('click', preventDefault);
document.body.removeEventListener('click', preventDefault);
});
});

Expand Down
40 changes: 25 additions & 15 deletions packages/material-ui/src/Modal/Modal.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,18 @@ describe('<Modal />', () => {
);

describe('props', () => {
let container;

before(() => {
container = document.createElement('div');
document.body.appendChild(container);
});

after(() => {
document.body.removeChild(container);
});

it('should consume theme default props', () => {
const container = document.createElement('div');
const theme = createMuiTheme({ props: { MuiModal: { container } } });
mount(
<ThemeProvider theme={theme}>
Expand Down Expand Up @@ -620,11 +630,11 @@ describe('<Modal />', () => {
};

const wrapper = mount(<TestCase open={false} />);
assert.strictEqual(document.body.style.overflow, '');
assert.strictEqual(document.body.parentNode.style.overflow, '');
wrapper.setProps({ open: true });
assert.strictEqual(document.body.style.overflow, 'hidden');
assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
wrapper.setProps({ open: false });
assert.strictEqual(document.body.style.overflow, '');
assert.strictEqual(document.body.parentNode.style.overflow, '');
});

it('should open and close with Transitions', done => {
Expand All @@ -649,17 +659,17 @@ describe('<Modal />', () => {

let wrapper;
const onEntered = () => {
assert.strictEqual(document.body.style.overflow, 'hidden');
assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
wrapper.setProps({ open: false });
};

const onExited = () => {
assert.strictEqual(document.body.style.overflow, '');
assert.strictEqual(document.body.parentNode.style.overflow, '');
done();
};

wrapper = mount(<TestCase onEntered={onEntered} onExited={onExited} open={false} />);
assert.strictEqual(document.body.style.overflow, '');
assert.strictEqual(document.body.parentNode.style.overflow, '');
wrapper.setProps({ open: true });
});
});
Expand Down Expand Up @@ -711,23 +721,23 @@ describe('<Modal />', () => {

let wrapper;
const onEntered = () => {
assert.strictEqual(document.body.style.overflow, 'hidden');
assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
wrapper.setProps({ open: false });
};

const onExited = () => {
assert.strictEqual(document.body.style.overflow, '');
assert.strictEqual(document.body.parentNode.style.overflow, '');
done();
};

const onExiting = () => {
assert.strictEqual(document.body.style.overflow, 'hidden');
assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
};

wrapper = mount(
<TestCase onEntered={onEntered} onExiting={onExiting} onExited={onExited} open={false} />,
);
assert.strictEqual(document.body.style.overflow, '');
assert.strictEqual(document.body.parentNode.style.overflow, '');
wrapper.setProps({ open: true });
});

Expand All @@ -754,23 +764,23 @@ describe('<Modal />', () => {

let wrapper;
const onEntered = () => {
assert.strictEqual(document.body.style.overflow, 'hidden');
assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
wrapper.setProps({ open: false });
};

const onExited = () => {
assert.strictEqual(document.body.style.overflow, '');
assert.strictEqual(document.body.parentNode.style.overflow, '');
done();
};

const onExiting = () => {
assert.strictEqual(document.body.style.overflow, '');
assert.strictEqual(document.body.parentNode.style.overflow, '');
};

wrapper = mount(
<TestCase onEntered={onEntered} onExiting={onExiting} onExited={onExited} open={false} />,
);
assert.strictEqual(document.body.style.overflow, '');
assert.strictEqual(document.body.parentNode.style.overflow, '');
wrapper.setProps({ open: true });
});
});
Expand Down
85 changes: 41 additions & 44 deletions packages/material-ui/src/Modal/ModalManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import getScrollbarSize from '../utils/getScrollbarSize';
import ownerDocument from '../utils/ownerDocument';
import ownerWindow from '../utils/ownerWindow';

// Do we have a vertical scrollbar?
// Is a vertical scrollbar displayed?
function isOverflowing(container) {
const doc = ownerDocument(container);

if (doc.body === container) {
const win = ownerWindow(doc);
return win.innerWidth > doc.documentElement.clientWidth;
return ownerWindow(doc).innerWidth > doc.documentElement.clientWidth;
}

return container.scrollHeight > container.clientHeight;
Expand All @@ -26,26 +25,21 @@ function getPaddingRight(node) {
return parseInt(window.getComputedStyle(node)['padding-right'], 10) || 0;
}

const BLACKLIST = ['template', 'script', 'style'];

function isHideable(node) {
return node.nodeType === 1 && BLACKLIST.indexOf(node.tagName.toLowerCase()) === -1;
}

function siblings(container, mount, currentNode, nodesToExclude, callback) {
const blacklist = [mount, currentNode, ...nodesToExclude];
function ariaHiddenSiblings(container, mountNode, currentNode, nodesToExclude = [], show) {
const blacklist = [mountNode, currentNode, ...nodesToExclude];
const blacklistTagNames = ['TEMPLATE', 'SCRIPT', 'STYLE'];

[].forEach.call(container.children, node => {
if (blacklist.indexOf(node) === -1 && isHideable(node)) {
callback(node);
if (
node.nodeType === 1 &&
blacklist.indexOf(node) === -1 &&
blacklistTagNames.indexOf(node.tagName) === -1
) {
ariaHidden(node, show);
}
});
}

function ariaHiddenSiblings(container, mountNode, currentNode, nodesToExclude = [], show) {
siblings(container, mountNode, currentNode, nodesToExclude, node => ariaHidden(node, show));
}

function findIndexOf(containerInfo, callback) {
let idx = -1;
containerInfo.some((item, index) => {
Expand All @@ -64,39 +58,42 @@ function handleContainer(containerInfo, props) {
const container = containerInfo.container;
let fixedNodes;

if (!props.disableScrollLock && isOverflowing(container)) {
if (!props.disableScrollLock) {
const overflowing = isOverflowing(container);

// Improve Gatsby support
// https://css-tricks.com/snippets/css/force-vertical-scrollbar/
const parent = container.parentElement;
if (parent.nodeName === 'HTML') {
restoreStyle.push({
value: parent.style.overflow,
key: 'overflow',
el: parent,
});
parent.style.overflow = 'hidden';
}
const scrollContainer = parent.nodeName === 'HTML' ? parent : container;

restoreStyle.push({
value: container.style.overflow,
value: scrollContainer.style.overflow,
key: 'overflow',
el: container,
el: scrollContainer,
});
restoreStyle.push({
value: container.style.paddingRight,
key: 'padding-right',
el: container,
});
container.style.overflow = 'hidden';

const scrollbarSize = getScrollbarSize();
// Block the scroll even if no scrollbar is visible to account for mobile keyboard
// screensize shrink.
scrollContainer.style.overflow = 'hidden';

// Use computed style, here to get the real padding to add our scrollbar width.
container.style['padding-right'] = `${getPaddingRight(container) + scrollbarSize}px`;
if (overflowing) {
const scrollbarSize = getScrollbarSize();

// .mui-fixed is a global helper.
fixedNodes = ownerDocument(container).querySelectorAll('.mui-fixed');
[].forEach.call(fixedNodes, node => {
restorePaddings.push(node.style.paddingRight);
node.style.paddingRight = `${getPaddingRight(node) + scrollbarSize}px`;
});
restoreStyle.push({
value: container.style.paddingRight,
key: 'padding-right',
el: container,
});
// Use computed style, here to get the real padding to add our scrollbar width.
container.style['padding-right'] = `${getPaddingRight(container) + scrollbarSize}px`;

// .mui-fixed is a global helper.
fixedNodes = ownerDocument(container).querySelectorAll('.mui-fixed');
[].forEach.call(fixedNodes, node => {
restorePaddings.push(node.style.paddingRight);
node.style.paddingRight = `${getPaddingRight(node) + scrollbarSize}px`;
});
}
}

const restore = () => {
Expand Down Expand Up @@ -241,6 +238,6 @@ export default class ModalManager {
}

isTopModal(modal) {
return !!this.modals.length && this.modals[this.modals.length - 1] === modal;
return this.modals.length > 0 && this.modals[this.modals.length - 1] === modal;
}
}
Loading

0 comments on commit d27ff2c

Please sign in to comment.