Skip to content

Instantly share code, notes, and snippets.

@elmasse
Created February 6, 2018 12:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elmasse/74e69130c879dbbf5f1ff12d1d51187a to your computer and use it in GitHub Desktop.
Save elmasse/74e69130c879dbbf5f1ff12d1d51187a to your computer and use it in GitHub Desktop.
Exploring Next animated transitions
import React, { Component } from 'react'
import Router from 'next/router'
import { parse, format } from 'url'
import raf from 'raf'
Router.ready(function() {
// monkey patching Router.router
const router = Router.router
if (!router.__patched) {
const _change = router.change
router.change = async (method, _url, _as, options) => {
const url = typeof _url === 'object' ? format(_url) : _url
const { pathname } = parse(url, true)
router.__nextRoute = pathname
return await _change.call(router, method, _url, _as, options)
}
router.__patched = true
}
})
const animations = {
enter: undefined,
leave: undefined,
deferred: false
}
const updateLeaveAnimation = (instance) => {
const all = Router.components
const route = Object
.keys(all)
.filter((key) => instance instanceof all[key].Component)[0]
const { leave } = Router.components[route].Component.animations
animations.leave = leave
}
const updateEnterAnimation = (instance) => {
const all = Router.components
const route = Object
.keys(all)
.filter((key) => instance instanceof all[key].Component)[0]
const { animations: pageAnimations = {} } = Router.components[route].Component
const { enter } = pageAnimations
animations.enter = enter
performAnimation()
animations.deferred = false
}
Router.onRouteChangeStart = (as) => {
const route = Router.router.__nextRoute
const routerObject = Router.components[route]
if (Router.route === route) return
if (!routerObject) {
animations.deferred = true
} else {
const { animations: pageAnimations = {} } = routerObject.Component
const { enter } = pageAnimations
animations.enter = enter
performAnimation()
}
}
const performAnimation = () => {
const { enter, leave } = animations
const appContainer = document.getElementById('__next')
const root = appContainer.querySelector('[data-reactroot]')
const exiting = root.firstChild.cloneNode(true)
raf(() => {
appContainer.insertBefore(exiting, root)
exiting.classList.add(leave)
root.classList.add(enter)
})
exiting.addEventListener('animationend', () => {
appContainer.removeChild(exiting)
}, { once: true })
root.addEventListener('animationend', () => {
root.classList.remove(enter)
}, { once: true })
}
export default ({ enter, leave }) => (WrappedComponent) => {
const displayName = WrappedComponent.displayName || WrappedComponent.name || 'Unknown'
return class extends Component {
static displayName = `PageTransition(${displayName})`
static animations = {enter, leave}
static getInitialProps = WrappedComponent.getInitialProps
constructor (props) {
super(props)
if (animations.deferred) {
updateEnterAnimation(this)
}
}
componentDidMount () {
updateLeaveAnimation(this)
}
render () {
return (<WrappedComponent {...this.props} />)
}
}
}
import withPageTransition from '../components/page-transition'
export default withPageTransition({enter: 'animate-in', leave: 'animate-out'})(
() => <div> Hello, Index</div>
)
/*animations*/
@keyframes animateIn {
from {
transform: translate3d(140vw, 0, 0);
/* transform: scale(1.2); */
opacity: 0.5;
}
to {
transform: translate3d(0, 0, 0);
/* transform: scale(1); */
opacity: 1;
}
}
@keyframes animateOut {
to {
transform: scale(.85);
opacity: 0;
}
}
@keyframes slideOut {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(-100vw, 0, 0);
}
}
@keyframes fadeIn {
to {
opacity: 1;
}
}
/* ------------------------------------------- */
[class*="animate-"] {
position: fixed;
transform-origin: center;
background: #fff;
width: 100vw;
height: 100vh;
}
.animate-in {
animation: animateIn .75s ease-in-out forwards;
}
.animate-out {
animation: animateOut .5s ease-out forwards;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment