Coder Social home page Coder Social logo

nxtexe / react-motion-router Goto Github PK

View Code? Open in Web Editor NEW
148.0 3.0 3.0 21.37 MB

Declarative routing library for React โš› with page transitions and animations out of the box. Under Development ๐Ÿงช.

HTML 0.81% TypeScript 92.49% CSS 5.71% JavaScript 0.99%
router navigation animation transition shared-element shared-element-transition react routing history route

react-motion-router's Introduction

React Motion Router

Declarative routing library for React โš› with 60FPS page transitions and animations ๐Ÿš€. Out of the box support for Shared Element Transitions ๐Ÿคฉ. Under Development ๐Ÿงช. Based on React Router and React Navigation.

version downloads license

Table of Contents

Installation

npm install react-motion-router

Usage

Basic

Use the Router component to render your screens. Pass a React component to the component prop of Stack.Screen to be rendered when the path prop of the screen has been navigated to.

// ...
import {Router, Stack} from 'react-motion-router';

function Home() {
    return(
        <div className="Home">
            <h1>Hello World</h1>
        </div>
    );
}
function App() {
    return(
        <div className="app">
            <Router>
                <Stack.Screen path="/" component={Home} />
            </Router>
        </div>
    ):
}

// ...

You can also pass lazy loaded components to the screen along with an optional fallback component to be rendered while your component loads.

// ...
const Home = React.lazy(() => import('./Screens/Home'));
<Router>
    <Stack.Screen path="/" component={Home} fallback={<div className='screen-fallback home'></div>}>
</Router>
// ...

If a fallback component is provided the fallback component is animated in just like the actual component would and is even able to do gesture navigation all while your screen is loaded in asynchronously.

Navigation

Navigation is done through the navigation object exposed on your screen's props.

// ...
function Home(props) {
    return(
        <div>
            // ...
            <button onClick={() => {
                props.navigation.goBack();
            }}>BACK</button>
            <button
                onClick={() => {
                    props.navigation.navigate('/posts');
                }}>Posts</button>
            // ...
        </div>
    );
}
// ...

OR for a more declarative approach opt for the Anchor compoennt

<Anchor href="/posts">Posts</Anchor>

The navigation object also exposes information such as navigation.location. It's the same as window.location but it will always be up to date and correct regardless of if browser routing has been disabled.

Passing Parameters to Screens

To pass data to the next screen, pass a value to the navigate function.

props.navigation.navigate('/posts', {
    post: {
        title: "Post"
    }
});

// Or with Anchor component
<Anchor href="/posts" params={{
    post: {
        title: "Post"
    }
}}>Posts</Anchor> // For cross domain URLs the params are appended as search parameters.

To access this data on the next screen:

// Screen: POSTS
// ...
<h1>{props.route.params.post.title}</h1>
// ...

All data passed to the navigate function is accessible on the target screen through the route prop.

Parameters can also be parsed from URL parameters for example a pathname with a search part such as /slides?hero=0 will be parsed into an object with key hero and value 0. To customise this behaviour you can pass a custom deserializer or serializer function to the Router component which will be used to convert between URL parameters and React Motion Router parameters and vice-versa.

<Router
    config={{
        paramsSerializer: (params) => {
            const searchPart = new URLSearchParams(params).toString()

            return btoa(searchPart); // search encoded as Base64 string
        },
        paramsDeserializer: (b64SearchPart) => {
            const searchPart = atob(b64SearchPart.slice(1)); // start after the ?
            const searchParams = new URLSearchParams(searchPart);

            const params = {};
            for (let [key, value] of searchParams) {
                params[key] = value;
            }

            return params;
        }
    }}
>
// ...
</Router>

In this example /slides?hero=0 becomes /slides?aGVybz0w.

Default Parameters

A default parameter can be passed to the screen by passing a value to the defaultParams prop on Stack.Screen component.

// ...
<Stack.Screen path="/posts" component={Posts} defaultParams={{
    post: {
        title: "Default Title"
    }
}}/>
// ...

Transitions

Transitions are a feature baked into react-motion-router; hence the name... To transition between screens do:

<Router config={{
    animation: {
        type: "slide",
        direction: "right",
        duration: 300
    }
}}>
// ...
</Router>

You can provide custom keyframes and options to customise and extend the types of animations available.

<Router config={{
    animation: {
        in: {
            keyframes: [{opacity: 0}, {opacity: 1}],
            options: {
                duration: 350,
                easing: 'ease'
            }
        },
        out: {
            keyframes: [{opacity: 1}, {opacity: 0}],
            options: {
                duration: 350,
                easing: 'ease-out'
            }
        }
    }
}}>
// ...
</Router>

You can subscribe to the transition progress by using the motion consumer component.

import {Motion} from 'react-motion-router';

// ...
<Motion.Consumer>
    {(progress) => {
        return (
            <div>{progress}</div>
        );
    }}
</Motion.Consumer>

// OR Class.contextType

static contextType = Motion;

The progress is updated as the animation plays and can be used to interpolate DOM style attributes or control playback of an animation.

Shared Element Transition

To do a shared element transition wrap the component you would like shared between screens and supply it with a unique ID prop.

// Screen: HOME
// ...
<SharedElement id="post">
    <h1>Post</h1>
</SharedElement>
// ...

and on another screen:

Screen: POSTS
// ...
<SharedElement id="post">
    <h1>Post</h1>
</SharedElement>
// ...

That's it! The element will transition from one screen to the next seemlessly. They can even do layered animations.

<SharedELement id="post" config={{
    x: {
        duration: 100
    },
    y: {
        duration: 300
    }
}}>
    <h1>Post</h1>
</SharedElement>

This way the X and Y axis are animated independently and can alter the path of the shared element while transitioning. Note that these durations are clamped to the overall router transition duration.

API Documentation

Stack.Screen

Prop Type Description
path string Pathname of the screen.
component JSXElementConstructor A valid React Component or React lazy loaded Component to be rendered.
fallback ReactNode A valid React Node to be rendered while the real component is suspended (lazy loading).
defaultParams Object A dictionary of parameters that can be accessed by the rendered component.
config Object A dictionary of options to alter the behaviour of the screen.

Stack.Screen Config

Property Type Description
animation AnimationConfig or AnimationConfigFactory AnimationConfig object or function that returns an AnimationConfig object. This config object is used to modify the router's transition behaviour. In and out animation can also be set independently.
disableDiscovery boolean Option to disable gesture navigation.
swipeAreaWidth number Area in pixels from the edge of the screen that gesture navigation can be triggered from.
hysteresis number Percent from 0-100 which specifies minimum gesture progress before navigation is triggered.
minFlingVelocity number Minimum average velocity of swipe gesture before navigation is triggered even if hysteresis was not reached.
keepAlive boolean If true the current screen will remain in the DOM tree after you navigate to another screen.
swipeDirection "left", "right", "up" or "down" The direction to swipe in order to trigger a gesture navigation.

Router Config

Property Type Description
defaultRoute string If the user navigates directly to a route other than the default and navigate.goBack() is called the app will navigate to the default route instead of leaving the website.
disableDiscovery boolean Option to disable gesture navigation.
disableBrowserRouting boolean Option to avoid updating browser native history stack and rely completely on memory routing.
animation AnimationConfig Config object used to modify the router's global transition behaviour. In and out animation can also be set independently.
swipeAreaWidth number Area in pixels from the edge of the screen that gesture navigation can be triggered from.
hysteresis number Percent from 0-100 which specifies minimum gesture progress before navigation is triggered.
minFlingVelocity number Minimum average velocity of swipe gesture before navigation is triggered even if hysteresis was not reached.
swipeDirection "left", "right", "up" or "down" The direction to swipe in order to trigger a gesture navigation.
paramsDeserializer Function A function that takes a URL search part string as input and outputs a valid JavaScript object.
paramsSerializer Function A function that takes a valid JavaScript object as input and outputs a URL search part string.

AnimationConfig

Property Type Description
type "slide", "fade", "zoom" or "none" The animation type used for page transitions.
duration number The time in milliseconds for how long page transitions are from start to end.
direction "left", "right", "up", "down", "in" or "out" The direction used for slide transitions. The direction is swapped automatically on back navigation. i.e. The user presses their browser back button or navigation.goBack() is called.

SharedElement

Prop Type Description
id string or number The unique ID used to keep track of the element in the scene. The IDs must match in each screen for a transition to occur.
children React.ReactChild A single React element which will be displayed between transitions.
config Object Config object used to alter the behaviour of the shared element.

SharedElement Config

Property Type Description
type "morph", "fade", "fade-through" or "cross-fade" Type of transition.
transformOrigin TransformOrigin Changes transform alignment of shared element.
duration number The time in milliseconds for how long the shared element transition is from start to end
easingFunction CSS <easing-function> Denotes a mathematical function that describes the rate at which a numerical value changes.1

It is useful to note that the duration and easing function properties can also be set on the X and Y axis as independent values by specifying an X or Y property on the shared element config object.

// ...
config={{
    x: {
        easingFunction: "ease-in-out",
        duration: 500
    }
}}
// ...

Remarks

This is a work in progress and elements of this solution are subject to change. There are a few limitations to be aware of for example there is:

  • no analogue for HashRouter in this solution.
  • no nested routing although there are plans to add this eventually.

Credits

Shoutout to @IzjerenHein whose react-native-shared-element was a source of great inspiration for this project ๐Ÿ™.

Other Relevant Resources

  1. material.io
  2. react-native-magic-move
  3. Hein Rutjes React Europe Talk
  4. Shared Element Transitions for Web

react-motion-router's People

Contributors

nxtedecoy avatar nxtexe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

react-motion-router's Issues

Demo page broken on Safari

Hi there! Cool library. I noticed the demo page is showing blank on Safari. Works fine for me on Chrome.

CleanShot 2022-02-24 at 11 34 26@2x

CleanShot 2022-02-24 at 11 36 03@2x

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.