From 8f12cdfc6ddf73ff76387b2ac49d018b7425e1bf Mon Sep 17 00:00:00 2001 From: Brian Clifton Date: Sat, 18 Nov 2017 00:51:57 -0700 Subject: [PATCH] Merge pull request #11818 from brave/issue-11813 Avoid 'flashes of white' when tabs open or close --- app/renderer/components/frame/frame.js | 19 ++++++- app/renderer/components/main/main.js | 23 +++++++-- js/about/newprivatetab.js | 15 +++++- js/about/newtab.js | 2 +- less/about/newtab.less | 11 ++++ less/window.less | 71 ++++++++++++++++++++------ package-lock.json | 31 +++++++++++ package.json | 1 + 8 files changed, 148 insertions(+), 25 deletions(-) diff --git a/app/renderer/components/frame/frame.js b/app/renderer/components/frame/frame.js index 890ebf8ea5a..13feeebe783 100644 --- a/app/renderer/components/frame/frame.js +++ b/app/renderer/components/frame/frame.js @@ -860,12 +860,15 @@ class Frame extends React.Component { const props = {} // used in renderer + props.transitionState = ownProps.transitionState props.partition = frameStateUtil.getPartition(frame) props.isFullScreen = frame.get('isFullScreen') props.isPreview = frame.get('key') === currentWindow.get('previewFrameKey') props.isActive = frameStateUtil.isFrameKeyActive(currentWindow, frame.get('key')) props.showFullScreenWarning = frame.get('showFullScreenWarning') props.location = location + props.isDefaultNewTabLocation = location === 'about:newtab' + props.isBlankLocation = location === 'about:blank' props.tabId = tabId props.showMessageBox = tabMessageBoxState.hasMessageBoxDetail(state, tabId) @@ -906,13 +909,27 @@ class Frame extends React.Component { return props } + getTransitionStateClassName (stateName) { + // handle missing data + if (!stateName) { + return null + } + // convert Transition element state string to a more consistent css classname + return `is${stateName[0].toUpperCase()}${stateName.slice(1)}` + } + render () { + const transitionClassName = this.getTransitionStateClassName(this.props.transitionState) return
{ this.props.isFullScreen && this.props.showFullScreenWarning diff --git a/app/renderer/components/main/main.js b/app/renderer/components/main/main.js index 1081a69a9a1..207089d5e46 100644 --- a/app/renderer/components/main/main.js +++ b/app/renderer/components/main/main.js @@ -17,6 +17,7 @@ const contextMenus = require('../../../../js/contextMenus') const {getSetting} = require('../../../../js/settings') // Components +const { Transition, TransitionGroup } = require('react-transition-group') const Navigator = require('../navigation/navigator') const Frame = require('../frame/frame') const TabPages = require('../tabs/tabPages') @@ -699,15 +700,27 @@ class Main extends React.Component { }
-
+ { this.props.sortedFrames.map((frameKey) => - ) + // after how long (ms) + // should the state 'entering' switch to 'entered' + // and also how long should state switch from 'exiting' + // to the component actually being removed + timeout={150}> + { + (transitionState) => + + } + + ) } -
+
{ this.props.showDownloadBar diff --git a/js/about/newprivatetab.js b/js/about/newprivatetab.js index e4d752de2be..53b6797316e 100644 --- a/js/about/newprivatetab.js +++ b/js/about/newprivatetab.js @@ -40,7 +40,20 @@ const styles = StyleSheet.create({ newPrivateTab: { background: `linear-gradient( ${globalStyles.color.privateTabBackgroundActive}, - ${globalStyles.color.black100})`, + #000 + )`, + backgroundAttachment: 'fixed', + // fade in from the new tab background color + animationName: { + '0%': { + opacity: '0' + }, + '100%': { + opacity: '1' + } + }, + animationDuration: `0.35s`, + animationTiming: 'ease-out', display: 'flex', flexDirection: 'column', alignItems: 'flex-start', diff --git a/js/about/newtab.js b/js/about/newtab.js index bd329541129..ae1f37c9244 100644 --- a/js/about/newtab.js +++ b/js/about/newtab.js @@ -284,7 +284,7 @@ class NewTabPage extends React.Component { backgroundLoaded: this.state.imageLoadComplete, showImages: this.showImages })}> -
+
diff --git a/less/about/newtab.less b/less/about/newtab.less index 34a557285e1..04182b4382c 100644 --- a/less/about/newtab.less +++ b/less/about/newtab.less @@ -9,12 +9,23 @@ box-sizing: border-box; } +// match private tab js-css values +@newTabAnimationDuration: 0.5s; +@newTabAnimationEasing: ease-out; + strong, div, span, li, em, p, a { font-family: "Helvetica Neue", Arial, sans-serif; font-weight: 400; -webkit-font-smoothing: antialiased; } +.newTabDashboard +{ + animation: fadeIn; + animation-duration: .3s; + animation-timing-function: ease-out; +} + .copyrightNotice { user-select: none; cursor: default; diff --git a/less/window.less b/less/window.less index a55ee98fa55..0c5231f376e 100644 --- a/less/window.less +++ b/less/window.less @@ -63,16 +63,68 @@ html, .frameWrapper { height: 100%; width: 100%; - z-index: @zindexWindow; + position: absolute; top: 0; left: 0; // Needed to be able to click and drag to select content in pages. user-select: none; + // default frame background + // TODO: use theme.frame.defaultBackground + --frame-bg: #fff; + // custom frame background(s) + &.isDefaultNewTabLocation { + // matches tab dashboard background + // will also show when about:newtab === about:blank or is Private Tab + // TODO: use theme.frame.newTabBackground + --frame-bg: #222; + } + // Webviews can cause flickers w/ Chrome v49 if left visible + // in the background. This also has a major benefit for background + // tabs that have video and animations in them. + visibility: hidden; + // delay frames getting hidden when new tabs show up + // in order to avoid showing 0 frames and just the window + // background + // whilst this does also affect visibility when switching tabs, + // z-index ensures the delayed-hidden tab is not visible + // Note that this value can be as large as we want, it does not + // need to match the timeout specified in the frame's element + // (in renderer main.js). However, there is no reason to set it higher than that. + transition: visibility 0s linear 150ms; + // 1000 + z-index: @zindexWindow; + &:not(.isActive) { + // 900 + z-index: @zindexWindowNotActive; + } + &.isPreview { + background: #222; + // 1100 + z-index: @zindexWindowIsPreview; + } + // show frame when active or preview + &.isActive, + &.isPreview, + // keep window contents around when exiting, to allow + // time for next active frame to be shown + &.isExiting { + visibility: visible; + // show instantly + transition-delay: 0s; + } + // hide frame whilst it's figuring out which location to be + // note: that isEntering is timed-out at a value set in renderer main.js + // but isBlankLocation will change at the exact moment that the frame + // has an actual location + &.isEntering.isBlankLocation { + visibility: hidden; + transition-delay: 0s; + } webview { - background-color: #fff; + background-color: var(--frame-bg); border: 0; height: 100%; outline: none; @@ -90,21 +142,6 @@ html, } } - &:not(.isActive) { - z-index: @zindexWindowNotActive; - - &.isPreview { - background: gray; - z-index: @zindexWindowIsPreview; - } - - // Webviews can cause flickers w/ Chrome v49 if left visible - // in the background. This also has a major benefit for background - // tabs that have video and animations in them. - &:not(.isPreview) { - visibility: hidden; - } - } } .hrefPreview { diff --git a/package-lock.json b/package-lock.json index 441b95fe47a..b9dfa332b12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2753,6 +2753,11 @@ "integrity": "sha1-CdekApCKpw39vq1T5YU/x50+8hw=", "dev": true }, + "chain-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chain-function/-/chain-function-1.0.0.tgz", + "integrity": "sha1-DUqzfn4Y6tC9xHuSB2QRjOWHM9w=" + }, "chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", @@ -4821,6 +4826,11 @@ } } }, + "dom-helpers": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.2.1.tgz", + "integrity": "sha1-MgPgf+0he9H0JLAZc1WC/Deyglo=" + }, "dom-serializer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", @@ -16908,6 +16918,19 @@ "object-assign": "4.1.1" } }, + "react-transition-group": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.2.1.tgz", + "integrity": "sha512-q54UBM22bs/CekG8r3+vi9TugSqh0t7qcEVycaRc9M0p0aCEu+h6rp/RFiW7fHfgd1IKpd9oILFTl5QK+FpiPA==", + "requires": { + "chain-function": "1.0.0", + "classnames": "2.2.5", + "dom-helpers": "3.2.1", + "loose-envify": "1.3.1", + "prop-types": "15.6.0", + "warning": "3.0.0" + } + }, "read-all-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", @@ -19998,6 +20021,14 @@ "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=", "dev": true }, + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "1.3.1" + } + }, "ware": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz", diff --git a/package.json b/package.json index 396044c873c..0956c5ecd7f 100644 --- a/package.json +++ b/package.json @@ -121,6 +121,7 @@ "react-dnd-html5-backend": "^2.1.2", "react-dom": "^15.5.4", "react-select": "^0.9.1", + "react-transition-group": "^2.2.1", "snazzy": "^7.0.0", "string.prototype.endswith": "^0.2.0", "string.prototype.startswith": "^0.2.0",