@steveruizok

Experiment with stacked navigation flow, kind of like Framer Classic’s FlowController. Much refactored.

Changelog

27/6
Rewrites how pages are shown. In previous versions the component would unmount components that don’t need to be shown, keeping track of only the current and previous page. In this version, all pages in the stack are kept until removed from the stack.

For example, if we navigate to PageA, PageB, and then PageC, all three pages will remain mounted. If we show previous, our position will move to PageB but PageC will remain mounted. If we then navigate from PageB to PageA, PageC will be unmounted and we’ll mount a second (but separate) PageA.

This is useful for cases where pages have content (such as form fields, scroll positions, or interaction states) that need to be maintained. Traveling “back” to a previously visited screen will restore that screen exactly as the user had left it.

This is also useful for navigation flows that load different versions of the same page, such as articles with different content but the same “page”. (More on this in future updates).

Tips

A link’s target can either be the name of a Frame (so long as it’s connected to the Flow component) or the name of a Marker that you’ve added to one of your connected Frames.

You can navigate from code, too. Click here to see a basic code component that will work with the Flow package.

You can navigate from Overrides, too.

import { Override } from framer"
// @ts-ignore
import { showNext, showPrevious } from "@framer/steveruizok.flow/code"

export function Button(): Override {
    return {
        onTap: () => showNext(screen_a)
    }
}

export function BackButton(): Override {
    return {
        onTap: () => showPrevious()
    }
}

onChangePage

You can override the onChangePage event to get the name of the current page.

1
2
3
4
5
6
7
8
9
import { Override } from framer

export function ChangePage(): Override {
    return {
        onChangePage: (name, position, stack) => {
            console.log(name, position, stack)
        }
    }
}

Transitions

If you want to tweak the component’s transitions, override the variants prop. It takes three variants: behind, current, and ahead.

import { Override } from framer"

export function VerticalPush(): Override {
    return {
        unmountHidden: true,
        variants: {
            behind: {
                y: "-100%"
            },
            current: {
                y: 0%
            },
            ahead: {
                y: 100%
            },
        },
    }
}

When moving “up” the stack, the new Frame will start at ahead and move to current, while the previous Frame moves from current to behind. When moving “down” the stack, the current Frame will move from behind to current, while the previous Frame will move from current to above.

An “instant” set of transitions would look like this:

import { Override } from framer

export function Instant(): Override {
    return {
        variants: {
            behind: {},
            current: {},
            ahead: {},
        },
    }
}

See the defaultProps at the bottom of this page for the default animation variants.

Unmount Hidden

By default, the component will preserve all of the Frames in the stack. They’ll stay mounted, so you won’t lose any data state or scroll positions. However, you might also want to just instantly snap between pages, unmounting all but the currently shown page. (You’d probably want to use the “instant” transitions, too).

import { Override } from framer

export function InstantUnmount(): Override {
    return {
        unmountHidden: true,
        variants: {
            behind: {},
            current: {},
            ahead: {},
        },
    }
}

Swiping

1
2
3
4
5
6
7
8
9
import { Override } from framer"
// @ts-ignore
import { showPrevious } from "@framer/steveruizok.flow/code”

export function Instant(): Override {
    return {
        onSwipeRight: showPrevious()
    }
}

defaultProps

Here are all of the component’s default props.

export function Instant(): Override {
    return {
        unmountHidden: false,
        stackPosition: 0,
        current: 0,
        pages: [],
        swipe: true,
        swipeDistance: 32,
        onSwipeLeft: () => null,
        onSwipeRight: () => null,
        onSwipeUp: () => null,
        onSwipeDown: () => null,
        onChangePage: (name, position, stack) => null,
        background: "none",
        variants: {
            behind: {
                x: "0%",
                filter: "brightness(50%)",
                transition: {
                    ease: [0.23, -0.04, 0.31, 1.01],
                    duration: 0.36,
                },
            },
            current: {
                x: "0%",
                filter: "brightness(100%)",
                transition: {
                    ease: [0.23, -0.04, 0.31, 1.01],
                    duration: 0.36,
                },
            },
            ahead: {
                x: "100%",
                filter: "brightness(100%)",
                transition: {
                    ease: [0.23, -0.04, 0.31, 1.01],
                    duration: 0.28,
                },
            },
        },
    }
}
Edit
Pub: 27 Jun 2019 16:51 UTC
Views: 296