Skip to content
This repository was archived by the owner on Jan 11, 2023. It is now read-only.

Handling different kinds of page transitions #295

Open
2 of 6 tasks
Rich-Harris opened this issue Jun 26, 2018 · 1 comment
Open
2 of 6 tasks

Handling different kinds of page transitions #295

Rich-Harris opened this issue Jun 26, 2018 · 1 comment

Comments

@Rich-Harris
Copy link
Member

Bear with me while I try and get my thoughts in order — this isn't a particular bug or a concrete proposal, just a few things I'm thinking about around the ways in which we need to improve or flesh out Sapper's behaviour around page transitions.

A typical App.html looks like this:

<Nav path={props.path}/>

<main>
  <svelte:component this={Page} {...props}/>
</main>

<style>
  main {
    position: relative;
    background-color: white;
    padding: 2em;
    margin: 0 auto;
    box-sizing: border-box;
  }
</style>

<script>
  import Nav from '../components/Nav.html';

  export default {
    components: {
      Nav
    }
  };
</script>

Navigating to a new page

When you navigate from (say) / to /about, the value of Page changes from the component defined by routes/index.html to the component defined by routes/about/index.html. At the same time, props becomes a new object.

  • this works well if there are no transitions involved
  • if / has outro transitions, they are not played
  • if /about has intro transitions, they are not played if skipIntroByDefault is true, even though it's not the initial render

This works well; the index page is destroyed, and the about page is recreated. Any transitions on the two pages are disregarded, however.

Navigating to the 'same' page

A trickier case is when you navigate from e.g. /posts/first-post to /posts/second-post, where the component in question is routes/posts/[slug].html. In this case, the value of Page is unchanged. Consequently, while the page's preload function is invoked, any component data that is not determined by preload is retained, and lifecycle hooks are ignored.

We could solve this like so...

app.set({ Page: null });
app.set({ Page });

...which would cause the page to be destroyed and recreated. But we'd need to make sure that intros and outros still worked in that context.

Another consideration: maybe we don't want the page to be destroyed in that context. Maybe the page is routes/settings/[submenu].html and we're navigating from /settings to /settings/notifications, and the appropriate thing to do is to keep the settings page intact while showing the submenu. (Perhaps there's an <input> with some data that we don't want to lose, or something.)

So we have a few 'same page' transition categories to support:

  • data changed, but we don't want to destroy/recreate
  • data changed, we want to destroy/recreate
  • data changed, we want to destroy/recreate and we have transitions

The distinction between the two cases (destroy vs persist) might even vary within the app. So it's possible that it can't be handled with configuration.

I would argue that destroy/recreate should be the default behaviour.

Transition modes

When the page you're navigating from and the page you're navigating to both have transitions, you might sometimes want the outro to happen before the intro. Other times you might want them to happen simultaneously.

I'm not sure what the best way to express that would be (again, it might differ within an app).

Thoughts

  • A related question is how we handle nested routes.
  • Perhaps we could determine whether to persist or destroy the page like this:
// app/client.js
init({
  target: document.querySelector('#sapper'),
  routes,
  App,
  persist: ({ oldPath, newPath }) => {
    // this is invoked when the user navigates
    // but Page is unchanged
    return newPath.startsWith('settings');
  }
});
  • The details of that are probably something we can worry about later.
  • We'll need to update the behaviour of <svelte:component> to handle transitions
@Rich-Harris
Copy link
Member Author

I believe most of the questions here are answered by #262 (notwithstanding the implementation challenges) — the out-then-in or out-and-in-simultaneously question is the tricky remaining one.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants