From 58456e43567213ac8031264c0fa3738db6694314 Mon Sep 17 00:00:00 2001 From: "\"Helen V. Holmes\"" Date: Thu, 7 Jul 2016 06:32:00 +0200 Subject: [PATCH] Bug 1266414 - device modal fades in/out, r=jryans Device modal can be closed with escape and outside click --- .../components/device-modal.js | 115 +++++++++++------- devtools/client/responsive.html/index.css | 62 ++++++++-- 2 files changed, 124 insertions(+), 53 deletions(-) diff --git a/devtools/client/responsive.html/components/device-modal.js b/devtools/client/responsive.html/components/device-modal.js index 123b8f2291cc..4514aa56c3d5 100644 --- a/devtools/client/responsive.html/components/device-modal.js +++ b/devtools/client/responsive.html/components/device-modal.js @@ -25,6 +25,10 @@ module.exports = createClass({ return {}; }, + componentDidMount() { + window.addEventListener("keydown", this.onKeyDown, true); + }, + componentWillReceiveProps(nextProps) { let { devices, @@ -39,6 +43,10 @@ module.exports = createClass({ } }, + componentWillUnmount() { + window.removeEventListener("keydown", this.onKeyDown, true); + }, + onDeviceCheckboxClick({ target }) { this.setState({ [target.value]: !this.state[target.value] @@ -78,18 +86,25 @@ module.exports = createClass({ onUpdateDeviceModalOpen(false); }, + onKeyDown(event) { + if (!this.props.devices.isModalOpen) { + return; + } + // Escape keycode + if (event.keyCode === 27) { + let { + onUpdateDeviceModalOpen + } = this.props; + onUpdateDeviceModalOpen(false); + } + }, + render() { let { devices, onUpdateDeviceModalOpen, } = this.props; - let modalClass = "device-modal container"; - - if (!devices.isModalOpen) { - modalClass += " hidden"; - } - const sortedDevices = {}; for (let type of devices.types) { sortedDevices[type] = Object.assign([], devices[type]) @@ -98,54 +113,66 @@ module.exports = createClass({ return dom.div( { - className: modalClass, + id: "device-modal-wrapper", + className: this.props.devices.isModalOpen ? "opened" : "closed", }, - dom.button({ - id: "device-close-button", - className: "toolbar-button devtools-button", - onClick: () => onUpdateDeviceModalOpen(false), - }), dom.div( { - className: "device-modal-content", + className: "device-modal container", }, - devices.types.map(type => { - return dom.div( - { - className: "device-type", - key: type, - }, - dom.header( + dom.button({ + id: "device-close-button", + className: "toolbar-button devtools-button", + onClick: () => onUpdateDeviceModalOpen(false), + }), + dom.div( + { + className: "device-modal-content", + }, + devices.types.map(type => { + return dom.div( { - className: "device-header", + className: "device-type", + key: type, }, - type - ), - sortedDevices[type].map(device => { - return dom.label( + dom.header( { - className: "device-label", - key: device.name, + className: "device-header", }, - dom.input({ - className: "device-input-checkbox", - type: "checkbox", - value: device.name, - checked: this.state[device.name], - onChange: this.onDeviceCheckboxClick, - }), - device.name - ); - }) - ); - }) + type + ), + sortedDevices[type].map(device => { + return dom.label( + { + className: "device-label", + key: device.name, + }, + dom.input({ + className: "device-input-checkbox", + type: "checkbox", + value: device.name, + checked: this.state[device.name], + onChange: this.onDeviceCheckboxClick, + }), + device.name + ); + }) + ); + }) + ), + dom.button( + { + id: "device-submit-button", + onClick: this.onDeviceModalSubmit, + }, + getStr("responsive.done") + ) ), - dom.button( + dom.div( { - id: "device-submit-button", - onClick: this.onDeviceModalSubmit, - }, - getStr("responsive.done") + className: "modal-overlay", + onClick: () => onUpdateDeviceModalOpen(false), + } ) ); }, diff --git a/devtools/client/responsive.html/index.css b/devtools/client/responsive.html/index.css index 7275ac648e8d..0e7cd3b9f0f7 100644 --- a/devtools/client/responsive.html/index.css +++ b/devtools/client/responsive.html/index.css @@ -39,6 +39,7 @@ #root, html, body { + height: 100%; margin: 0; } @@ -47,12 +48,10 @@ html, body { display: flex; align-items: center; flex-direction: column; - height: 100vh; - - /* Snap to the top of the app when there isn't enough vertical space anymore - to center the viewports (so we don't lose the global toolbar) */ - position: sticky; - top: 0; + padding-top: 15px; + padding-bottom: 1%; + position: relative; + height: 100%; } /** @@ -86,7 +85,7 @@ html, body { color: var(--theme-body-color-alt); border-radius: 2px; box-shadow: var(--rdm-box-shadow); - margin: 10% 0 30px 0; + margin: 0 0 15px 0; padding: 4px 5px; display: inline-flex; -moz-user-select: none; @@ -336,9 +335,33 @@ html, body { * Device Modal */ +@keyframes fade-in-and-up { + 0% { + opacity: 0; + transform: translateY(5px); + } + 100% { + opacity: 1; + transform: translateY(0px); + } +} + +@keyframes fade-down-and-out { + 0% { + opacity: 1; + transform: translateY(0px); + } + 100% { + opacity: 0; + transform: translateY(5px); + visibility: hidden; + } +} + .device-modal { border-radius: 2px; box-shadow: var(--rdm-box-shadow); + display: none; position: absolute; margin: auto; top: 0; @@ -347,10 +370,31 @@ html, body { right: 0; width: 642px; height: 612px; + z-index: 1; } -.device-modal.hidden { - display: none; +/* Handles the opening/closing of the modal */ +#device-modal-wrapper.opened .device-modal { + animation: fade-in-and-up 0.3s ease; + animation-fill-mode: forwards; + display: block; +} + +#device-modal-wrapper.closed .device-modal { + animation: fade-down-and-out 0.3s ease; + animation-fill-mode: forwards; + display: block; +} + +#device-modal-wrapper.opened .modal-overlay { + background-color: var(--theme-splitter-color); + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + z-index: 0; + opacity: 0.5; } .device-modal-content {