diff --git a/CHANGELOG.md b/CHANGELOG.md index 55a87301e..386fe6462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,7 +125,7 @@ To Be Released: 2018-05-31. - [ ] providers: select files only after “select” is pressed, don’t add them right away when they are checked (keep a list of fileIds in state?); better UI + solves issue with autoProceed uploading in background, which is weird; re-read https://github.com/transloadit/uppy/pull/419#issuecomment-345210519 (@arturi, @goto-bus-stop) - [x] tus: add `filename` and `filetype`, so that tus servers knows what headers to set https://github.com/tus/tus-js-client/commit/ebc5189eac35956c9f975ead26de90c896dbe360 (#844 / @vith) - [ ] core: look into utilizing https://github.com/que-etc/resize-observer-polyfill for responsive components. See also https://github.com/transloadit/uppy/issues/750 -- [x] core: ⚠️ **breaking** removed .run() (to solve issues like #756), update ddocs (#793 / goto-bus-stop) +- [x] core: ⚠️ **breaking** removed .run() (to solve issues like #756), update docs (#793 / goto-bus-stop) - [ ] core: use Browserslist config to share between PostCSS, Autoprefixer and Babel https://github.com/browserslist/browserslist, https://github.com/amilajack/eslint-plugin-compat (@arturi) - [ ] core: utilize https://github.com/jonathantneal/postcss-preset-env, maybe https://github.com/jonathantneal/postcss-normalize (@arturi) - [ ] core: addFile not passing restrictions shouldn’t throw when called from UI diff --git a/src/plugins/Dashboard/Dashboard.js b/src/plugins/Dashboard/Dashboard.js index 6878b9ca9..488bbf760 100644 --- a/src/plugins/Dashboard/Dashboard.js +++ b/src/plugins/Dashboard/Dashboard.js @@ -23,7 +23,7 @@ const PanelContent = (props) => { } const poweredByUppy = (props) => { - return Powered by Uppy } @@ -33,6 +33,8 @@ module.exports = function Dashboard (props) { { 'uppy-Root': props.isTargetDOMEl }, 'uppy-Dashboard', { 'Uppy--isTouchDevice': isTouchDevice() }, + { 'uppy-Dashboard--animateOpenClose': props.animateOpenClose }, + { 'uppy-Dashboard--isClosing': props.isClosing }, { 'uppy-Dashboard--modal': !props.inline }, { 'uppy-Dashboard--wide': props.isWide } ) diff --git a/src/plugins/Dashboard/index.js b/src/plugins/Dashboard/index.js index 49370dd37..7aa3286d0 100644 --- a/src/plugins/Dashboard/index.js +++ b/src/plugins/Dashboard/index.js @@ -13,19 +13,22 @@ const { defaultTabIcon } = require('./icons') // MIT licence, https://github.com/ghosh/micromodal/blob/master/LICENSE.md // Copyright (c) 2017 Indrashish Ghosh const FOCUSABLE_ELEMENTS = [ - 'a[href]', - 'area[href]', - 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])', - 'select:not([disabled]):not([aria-hidden])', - 'textarea:not([disabled]):not([aria-hidden])', - 'button:not([disabled]):not([aria-hidden])', - 'iframe', - 'object', - 'embed', - '[contenteditable]', - '[tabindex]:not([tabindex^="-"])' + 'a[href]:not([tabindex^="-"]):not([inert]):not([aria-hidden])', + 'area[href]:not([tabindex^="-"]):not([inert]):not([aria-hidden])', + 'input:not([disabled]):not([inert]):not([aria-hidden])', + 'select:not([disabled]):not([inert]):not([aria-hidden])', + 'textarea:not([disabled]):not([inert]):not([aria-hidden])', + 'button:not([disabled]):not([inert]):not([aria-hidden])', + 'iframe:not([tabindex^="-"]):not([inert]):not([aria-hidden])', + 'object:not([tabindex^="-"]):not([inert]):not([aria-hidden])', + 'embed:not([tabindex^="-"]):not([inert]):not([aria-hidden])', + '[contenteditable]:not([tabindex^="-"]):not([inert]):not([aria-hidden])', + '[tabindex]:not([tabindex^="-"]):not([inert]):not([aria-hidden])' ] +const TAB_KEY = 9 +const ESC_KEY = 27 + /** * Dashboard UI with previews, metadata editing, tabs for various services and more */ @@ -106,6 +109,7 @@ module.exports = class Dashboard extends Plugin { disableInformer: false, disableThumbnailGenerator: false, disablePageScrollWhenModalOpen: true, + animateOpenClose: true, proudlyDisplayPoweredByUppy: true, onRequestCloseModal: () => this.closeModal(), locale: defaultLocale @@ -242,23 +246,43 @@ module.exports = class Dashboard extends Plugin { this.savedActiveElement = document.activeElement if (this.opts.disablePageScrollWhenModalOpen) { - document.body.classList.add('uppy-Dashboard-isOpen') + document.body.classList.add('uppy-Dashboard-isFixed') } + // handle ESC and TAB keys in modal dialog + document.addEventListener('keydown', this.onKeydown) + this.rerender(this.uppy.getState()) this.updateDashboardElWidth() this.setFocusToBrowse() } closeModal () { - this.setPluginState({ - isHidden: true - }) - if (this.opts.disablePageScrollWhenModalOpen) { - document.body.classList.remove('uppy-Dashboard-isOpen') + document.body.classList.remove('uppy-Dashboard-isFixed') } + if (this.opts.animateOpenClose) { + this.setPluginState({ + isClosing: true + }) + const handler = () => { + this.setPluginState({ + isHidden: true, + isClosing: false + }) + this.el.removeEventListener('animationend', handler, false) + } + this.el.addEventListener('animationend', handler, false) + } else { + this.setPluginState({ + isHidden: true + }) + } + + // handle ESC and TAB keys in modal dialog + document.removeEventListener('keydown', this.onKeydown) + this.savedActiveElement.focus() } @@ -268,9 +292,9 @@ module.exports = class Dashboard extends Plugin { onKeydown (event) { // close modal on esc key press - if (event.keyCode === 27) this.requestCloseModal(event) + if (event.keyCode === ESC_KEY) this.requestCloseModal(event) // maintainFocus on tab key press - if (event.keyCode === 9) this.maintainFocus(event) + if (event.keyCode === TAB_KEY) this.maintainFocus(event) } handleClickOutside () { @@ -323,10 +347,6 @@ module.exports = class Dashboard extends Plugin { this.uppy.log('Dashboard modal trigger not found. Make sure `trigger` is set in Dashboard options unless you are planning to call openModal() method yourself') } - if (!this.opts.inline) { - document.addEventListener('keydown', this.onKeydown) - } - // Drag Drop this.removeDragDropListener = dragDrop(this.el, (files) => { this.handleDrop(files) @@ -342,10 +362,6 @@ module.exports = class Dashboard extends Plugin { showModalTrigger.forEach(trigger => trigger.removeEventListener('click', this.openModal)) } - if (!this.opts.inline) { - document.removeEventListener('keydown', this.onKeydown) - } - this.removeDragDropListener() window.removeEventListener('resize', this.updateDashboardElWidth) } @@ -456,6 +472,8 @@ module.exports = class Dashboard extends Plugin { totalProgress: state.totalProgress, acquirers: acquirers, activePanel: pluginState.activePanel, + animateOpenClose: this.opts.animateOpenClose, + isClosing: pluginState.isClosing, getPlugin: this.uppy.getPlugin, progressindicators: progressindicators, autoProceed: this.uppy.opts.autoProceed, diff --git a/src/scss/_animation.scss b/src/scss/_animation.scss index bc81ed482..e69de29bb 100644 --- a/src/scss/_animation.scss +++ b/src/scss/_animation.scss @@ -1,23 +0,0 @@ -// Animation - -@keyframes zoomOutLeft { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(.1) translate3d(-2000px, 0, 0); - transform: scale(.1) translate3d(-2000px, 0, 0); - -webkit-transform-origin: left center; - transform-origin: left center; - } -} - -.UppyAnimation-zoomOutLeft { - animation-name: zoomOutLeft; - animation-duration: 1s; - animation-fill-mode: both; -} diff --git a/src/scss/_dashboard.scss b/src/scss/_dashboard.scss index 189e8ad37..b4828ee2e 100644 --- a/src/scss/_dashboard.scss +++ b/src/scss/_dashboard.scss @@ -1,17 +1,51 @@ .uppy-Dashboard--modal { z-index: $zIndex-2; - // transition: transform 0.2s ease-in-out; - // transform: none; - // -webkit-overflow-scrolling: touch; } -.uppy-Dashboard--modal[aria-hidden=true] { - display: none; - // transform: translateY(-50%); -} + .uppy-Dashboard--modal[aria-hidden=true] { + display: none; + } + + // Modal open/close animations + + @keyframes uppy-Dashboard-fadeIn { + from { opacity: 0; } + to { opacity: 1; } + } + + @keyframes uppy-Dashboard-fadeOut { + from { opacity: 1; } + to { opacity: 0; } + } + + @keyframes uppy-Dashboard-slideDownAndFadeIn { + from { transform: translate3d(-50%, -70%, 0); opacity: 0; } + to { transform: translate3d(-50%, -50%, 0); opacity: 1; } + } + + @keyframes uppy-Dashboard-slideUpFadeOut { + from { transform: translate3d(-50%, -50%, 0); opacity: 1; } + to { transform: translate3d(-50%, -70%, 0); opacity: 0; } + } + + .uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose > .uppy-Dashboard-inner { + animation: uppy-Dashboard-slideDownAndFadeIn 0.3s cubic-bezier(0, 0, .2, 1); + } + + .uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose > .uppy-Dashboard-overlay { + animation: uppy-Dashboard-fadeIn 0.3s cubic-bezier(0, 0, .2, 1); + } + + .uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing > .uppy-Dashboard-inner { + animation: uppy-Dashboard-slideUpFadeOut 0.3s cubic-bezier(0, 0, .2, 1); + } + + .uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing > .uppy-Dashboard-overlay { + animation: uppy-Dashboard-fadeOut 0.3s cubic-bezier(0, 0, .2, 1); + } // Added to body to prevent the page from scrolling when Modal is open -.uppy-Dashboard-isOpen { +.uppy-Dashboard-isFixed { overflow: hidden; height: 100vh; } @@ -289,48 +323,31 @@ font-size: 16px; line-height: 50px; max-width: 300px; - // top: 15px; } } -.uppy-DashboardContent-titleFile { - // text-decoration: underline; -} - .uppy-DashboardContent-back { @include reset-button; - // position: absolute; - // top: 0; - // left: 15px; font-size: 14px; - // line-height: 40px; font-weight: 500; cursor: pointer; color: $color-cornflower-blue; .uppy-Dashboard--wide & { font-size: 15px; - // line-height: 50px; } } -// .uppy-DashboardContent-back .UppyIcon { -// position: relative; -// margin-right: 3px; -// } - .uppy-DashboardContent-panel { position: absolute; top: 0; bottom: 0; left: 0; right: 0; - transform: translateY(-105%); + transform: translate3d(0, -105%, 0); transition: transform 0.2s ease-in-out; - will-change: transform; background-color: darken($color-white, 4%); box-shadow: 0 0 10px 5px rgba($color-black, 0.15); - // padding: 15px; padding-top: 40px; overflow: hidden; z-index: $zIndex-4; @@ -338,14 +355,10 @@ .uppy-Dashboard--wide & { padding-top: 50px; } - - // .uppy-Dashboard--modal & { - // z-index: $zIndex-4; - // } } .uppy-DashboardContent-panel[aria-hidden=false] { - transform: none; + transform: translate3d(0, 0, 0); } // Progress bar placeholder @@ -429,29 +442,6 @@ border-color: darken($color-white, 20%); } -// .uppy-Dashboard-bgIcon { - // width: 100%; - // max-width: 460px; - // position: absolute; - // top: 50%; - // left: 50%; - // transform: translate(-50%, -50%); - // opacity: 0.7; - // transition: all 0.3s; - // padding: 0 20px; -// } - -// .uppy-Dashboard-bgIcon .UppyIcon { -// width: 100%; -// height: 80px; -// fill: none; -// stroke: $color-asphalt-gray; - -// .uppy-Dashboard--wide & { -// height: 110px; -// } -// } - .uppy-Dashboard-bgIcon { height: 100%; display: flex; @@ -1012,8 +1002,9 @@ // .uppy-DashboardFileCard { - transform: translateY(0); - transition: all 0.25s ease-in-out; + transform: translate3d(0, 0, 0); + transition: transform 0.2s ease-in-out; + width: 100%; height: 100%; position: absolute; @@ -1026,9 +1017,9 @@ background-color: $color-white; } -.uppy-DashboardFileCard[aria-hidden=true] { - transform: translateY(-105%); -} + .uppy-DashboardFileCard[aria-hidden=true] { + transform: translate3d(0, -105%, 0); + } .uppy-DashboardFileCard-inner { display: flex; @@ -1093,3 +1084,6 @@ vertical-align: middle; width: 78%; } + + + diff --git a/website/src/docs/dashboard.md b/website/src/docs/dashboard.md index d2bc8b23a..b18e37005 100644 --- a/website/src/docs/dashboard.md +++ b/website/src/docs/dashboard.md @@ -138,6 +138,10 @@ Set to true to automatically close the modal when the user clicks outside of it. By default when Dashboard modal is open, it will disable page scrolling, so when you scroll a list of files in Uppy the website in the background stays still. Set to false to override this behaviour and leave page scrolling intact. +## `animateOpenClose: true` + +Add light animations when modal dialog is open or closed, for more satisfying user experience. + ### `proudlyDisplayPoweredByUppy: true` Uppy is provided for the world for free by the [Transloadit team](https://transloadit.com). In return, we ask that you consider keeping a tiny Uppy logo at the bottom of the Dashboard, so that more people can discover and use Uppy.