From cdc4b98b62b43d4e7253f731f2028e45d669acf5 Mon Sep 17 00:00:00 2001 From: sreetej1998 <41690429+sreetej1998@users.noreply.github.com> Date: Tue, 22 Oct 2019 15:59:22 +0530 Subject: [PATCH] [Modal] Improve Gatsby support (#17972) --- .../src/pages/components/modal/ServerModal.js | 7 +- .../pages/components/modal/ServerModal.tsx | 7 +- .../src/pages/components/modal/SpringModal.js | 2 +- .../pages/components/modal/SpringModal.tsx | 2 +- .../pages/components/popper/SpringPopper.js | 2 +- .../pages/components/popper/SpringPopper.tsx | 2 +- .../tree-view/CustomizedTreeView.js | 2 +- .../tree-view/CustomizedTreeView.tsx | 2 +- .../ClickAwayListener.test.js | 6 +- packages/material-ui/src/Modal/Modal.test.js | 40 ++++++---- .../material-ui/src/Modal/ModalManager.js | 76 ++++++++++--------- .../material-ui/src/Popover/Popover.test.js | 16 ++-- .../material-ui/src/Popper/Popper.test.js | 2 +- .../material-ui/src/Snackbar/Snackbar.test.js | 2 +- .../material-ui/src/test-utils/createMount.js | 4 +- 15 files changed, 100 insertions(+), 72 deletions(-) diff --git a/docs/src/pages/components/modal/ServerModal.js b/docs/src/pages/components/modal/ServerModal.js index 0a99b62fa43482..f2584c39dde9b0 100644 --- a/docs/src/pages/components/modal/ServerModal.js +++ b/docs/src/pages/components/modal/ServerModal.js @@ -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', diff --git a/docs/src/pages/components/modal/ServerModal.tsx b/docs/src/pages/components/modal/ServerModal.tsx index c5eb2ea4c9e5b5..369b9e68339da7 100644 --- a/docs/src/pages/components/modal/ServerModal.tsx +++ b/docs/src/pages/components/modal/ServerModal.tsx @@ -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', diff --git a/docs/src/pages/components/modal/SpringModal.js b/docs/src/pages/components/modal/SpringModal.js index 5e38c9f6c9a3be..89b0a4ba3bd360 100644 --- a/docs/src/pages/components/modal/SpringModal.js +++ b/docs/src/pages/components/modal/SpringModal.js @@ -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'; // web.cjs is required for IE 11 support const useStyles = makeStyles(theme => ({ modal: { diff --git a/docs/src/pages/components/modal/SpringModal.tsx b/docs/src/pages/components/modal/SpringModal.tsx index 368d8f5462046b..c862f3e45aa86e 100644 --- a/docs/src/pages/components/modal/SpringModal.tsx +++ b/docs/src/pages/components/modal/SpringModal.tsx @@ -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({ diff --git a/docs/src/pages/components/popper/SpringPopper.js b/docs/src/pages/components/popper/SpringPopper.js index bcd94c6756fea4..41008e9ddfe958 100644 --- a/docs/src/pages/components/popper/SpringPopper.js +++ b/docs/src/pages/components/popper/SpringPopper.js @@ -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: { diff --git a/docs/src/pages/components/popper/SpringPopper.tsx b/docs/src/pages/components/popper/SpringPopper.tsx index 985de853278e36..e01fc1b8e87220 100644 --- a/docs/src/pages/components/popper/SpringPopper.tsx +++ b/docs/src/pages/components/popper/SpringPopper.tsx @@ -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({ diff --git a/docs/src/pages/components/tree-view/CustomizedTreeView.js b/docs/src/pages/components/tree-view/CustomizedTreeView.js index ad5330374c2635..cc933bbe824a27 100644 --- a/docs/src/pages/components/tree-view/CustomizedTreeView.js +++ b/docs/src/pages/components/tree-view/CustomizedTreeView.js @@ -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 ( diff --git a/docs/src/pages/components/tree-view/CustomizedTreeView.tsx b/docs/src/pages/components/tree-view/CustomizedTreeView.tsx index d4ed966af0ace3..e828c971bcef25 100644 --- a/docs/src/pages/components/tree-view/CustomizedTreeView.tsx +++ b/docs/src/pages/components/tree-view/CustomizedTreeView.tsx @@ -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) { diff --git a/packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js b/packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js index 2dbad01b48891d..b574922d91c44f 100644 --- a/packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js +++ b/packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js @@ -77,13 +77,13 @@ describe('', () => { , ); 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); }); }); diff --git a/packages/material-ui/src/Modal/Modal.test.js b/packages/material-ui/src/Modal/Modal.test.js index 4c39193249e403..a0ec1ff7e04808 100644 --- a/packages/material-ui/src/Modal/Modal.test.js +++ b/packages/material-ui/src/Modal/Modal.test.js @@ -49,8 +49,18 @@ describe('', () => { ); 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( @@ -620,11 +630,11 @@ describe('', () => { }; const wrapper = mount(); - 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 => { @@ -649,17 +659,17 @@ describe('', () => { 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(); - assert.strictEqual(document.body.style.overflow, ''); + assert.strictEqual(document.body.parentNode.style.overflow, ''); wrapper.setProps({ open: true }); }); }); @@ -711,23 +721,23 @@ describe('', () => { 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( , ); - assert.strictEqual(document.body.style.overflow, ''); + assert.strictEqual(document.body.parentNode.style.overflow, ''); wrapper.setProps({ open: true }); }); @@ -754,23 +764,23 @@ describe('', () => { 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( , ); - assert.strictEqual(document.body.style.overflow, ''); + assert.strictEqual(document.body.parentNode.style.overflow, ''); wrapper.setProps({ open: true }); }); }); diff --git a/packages/material-ui/src/Modal/ModalManager.js b/packages/material-ui/src/Modal/ModalManager.js index a0e9dc0a281ea4..2cbf3c8c66058d 100644 --- a/packages/material-ui/src/Modal/ModalManager.js +++ b/packages/material-ui/src/Modal/ModalManager.js @@ -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; @@ -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) => { @@ -59,24 +53,42 @@ function findIndexOf(containerInfo, callback) { } function handleContainer(containerInfo, props) { - const restoreStyle = {}; - const style = {}; + const restoreStyle = []; const restorePaddings = []; + const container = containerInfo.container; let fixedNodes; if (!props.disableScrollLock) { - restoreStyle.overflow = containerInfo.container.style.overflow; - restoreStyle['padding-right'] = containerInfo.container.style.paddingRight; - style.overflow = 'hidden'; + const overflowing = isOverflowing(container); - if (isOverflowing(containerInfo.container)) { + // Improve Gatsby support + // https://css-tricks.com/snippets/css/force-vertical-scrollbar/ + const parent = container.parentElement; + const scrollContainer = parent.nodeName === 'HTML' ? parent : container; + + restoreStyle.push({ + value: scrollContainer.style.overflow, + key: 'overflow', + el: scrollContainer, + }); + + // Block the scroll even if no scrollbar is visible to account for mobile keyboard + // screensize shrink. + scrollContainer.style.overflow = 'hidden'; + + if (overflowing) { const scrollbarSize = getScrollbarSize(); + 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. - style['padding-right'] = `${getPaddingRight(containerInfo.container) + scrollbarSize}px`; + container.style['padding-right'] = `${getPaddingRight(container) + scrollbarSize}px`; // .mui-fixed is a global helper. - fixedNodes = ownerDocument(containerInfo.container).querySelectorAll('.mui-fixed'); + fixedNodes = ownerDocument(container).querySelectorAll('.mui-fixed'); [].forEach.call(fixedNodes, node => { restorePaddings.push(node.style.paddingRight); node.style.paddingRight = `${getPaddingRight(node) + scrollbarSize}px`; @@ -84,10 +96,6 @@ function handleContainer(containerInfo, props) { } } - Object.keys(style).forEach(key => { - containerInfo.container.style[key] = style[key]; - }); - const restore = () => { if (fixedNodes) { [].forEach.call(fixedNodes, (node, i) => { @@ -99,11 +107,11 @@ function handleContainer(containerInfo, props) { }); } - Object.keys(restoreStyle).forEach(key => { - if (restoreStyle[key]) { - containerInfo.container.style.setProperty(key, restoreStyle[key]); + restoreStyle.forEach(({ value, el, key }) => { + if (value) { + el.style.setProperty(key, value); } else { - containerInfo.container.style.removeProperty(key); + el.style.removeProperty(key); } }); }; @@ -230,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; } } diff --git a/packages/material-ui/src/Popover/Popover.test.js b/packages/material-ui/src/Popover/Popover.test.js index c8ad9224242c61..b43630e04dd673 100644 --- a/packages/material-ui/src/Popover/Popover.test.js +++ b/packages/material-ui/src/Popover/Popover.test.js @@ -336,7 +336,7 @@ describe('', () => { before(() => { openPopover = anchorOrigin => { if (!anchorEl) { - anchorEl = window.document.createElement('div'); + anchorEl = document.createElement('div'); } const css = (element, styles) => { @@ -352,7 +352,7 @@ describe('', () => { top: '100px', left: '100px', }); - window.document.body.appendChild(anchorEl); + document.body.appendChild(anchorEl); return new Promise(resolve => { const component = ( @@ -362,7 +362,7 @@ describe('', () => { anchorOrigin={anchorOrigin} transitionDuration={0} onEntered={() => { - popoverEl = window.document.querySelector('[data-mui-test="Popover"]'); + popoverEl = document.querySelector('[data-mui-test="Popover"]'); resolve(); }} > @@ -392,7 +392,7 @@ describe('', () => { after(() => { if (anchorEl) { - window.document.body.removeChild(anchorEl); + document.body.removeChild(anchorEl); } }); @@ -449,7 +449,7 @@ describe('', () => { it('should pass through container prop if container and anchorEl props are provided', () => { const container = document.createElement('div'); - const wrapper2 = mount(); + const wrapper2 = mount(); assert.strictEqual(wrapper2.find(Modal).props().container, container); }); @@ -458,7 +458,7 @@ describe('', () => { await openPopover(undefined); assert.strictEqual( wrapper.find(Modal).props().container, - window.document.body, + document.body, "should use anchorEl's parent body as Modal container", ); }); @@ -516,7 +516,7 @@ describe('', () => { anchorOrigin={anchorOrigin} transitionDuration={0} onEntered={() => { - popoverEl = window.document.querySelector('[data-mui-test="Popover"]'); + popoverEl = document.querySelector('[data-mui-test="Popover"]'); resolve(); }} > @@ -568,7 +568,7 @@ describe('', () => { anchorReference="none" transitionDuration={0} onEntered={() => { - popoverEl = window.document.querySelector('[data-mui-test="Popover"]'); + popoverEl = document.querySelector('[data-mui-test="Popover"]'); resolve(); }} PaperProps={{ diff --git a/packages/material-ui/src/Popper/Popper.test.js b/packages/material-ui/src/Popper/Popper.test.js index f6e351d5ce25b2..39002ee20e1007 100644 --- a/packages/material-ui/src/Popper/Popper.test.js +++ b/packages/material-ui/src/Popper/Popper.test.js @@ -14,7 +14,7 @@ describe('', () => { let mount; const render = createClientRender({ strict: true }); const defaultProps = { - anchorEl: () => window.document.createElement('svg'), + anchorEl: () => document.createElement('svg'), children: Hello World, open: true, }; diff --git a/packages/material-ui/src/Snackbar/Snackbar.test.js b/packages/material-ui/src/Snackbar/Snackbar.test.js index 5ad26e05250cc6..1d84fe249b1237 100644 --- a/packages/material-ui/src/Snackbar/Snackbar.test.js +++ b/packages/material-ui/src/Snackbar/Snackbar.test.js @@ -38,7 +38,7 @@ describe('', () => { mount(); const event = new window.Event('click', { view: window, bubbles: true, cancelable: true }); - window.document.body.dispatchEvent(event); + document.body.dispatchEvent(event); assert.strictEqual(handleClose.callCount, 1); assert.deepEqual(handleClose.args[0], [event, 'clickaway']); diff --git a/packages/material-ui/src/test-utils/createMount.js b/packages/material-ui/src/test-utils/createMount.js index 3a4c14c6d5d8df..eaaa7d57f6e031 100644 --- a/packages/material-ui/src/test-utils/createMount.js +++ b/packages/material-ui/src/test-utils/createMount.js @@ -35,10 +35,10 @@ class Mode extends React.Component { export default function createMount(options = {}) { const { mount = enzymeMount, strict: globalStrict, ...globalEnzymeOptions } = options; - const attachTo = window.document.createElement('div'); + const attachTo = document.createElement('div'); attachTo.className = 'app'; attachTo.setAttribute('id', 'app'); - window.document.body.insertBefore(attachTo, window.document.body.firstChild); + document.body.insertBefore(attachTo, document.body.firstChild); const mountWithContext = function mountWithContext(node, localOptions = {}) { const { disableUnnmount = false, strict = globalStrict, ...localEnzymeOptions } = localOptions;