Guide · Svelte

Zumly with Svelte

A view can be a Svelte component. Zumly hands you an empty element; you mount the component in it and unmount it when the view goes away.

Live example · SvelteOpen ↗

Each planet and the list are Svelte components in their own views. Like a few times, open a planet, then come back: the count is still there. Here the components compile in the browser; in an app, your bundler does that.

The pattern

Make the view a function. It receives a context; mount a component in target.

import Zumly from 'zumly'
import 'zumly/style.css'
import { mount, unmount } from 'svelte'
import Detail from './Detail.svelte'

const app = new Zumly({
  mount: '.canvas',
  initialView: 'home',
  views: {
    home: '<div class="z-view"><div class="zoom-me" data-to="detail" data-id="42">Open</div></div>',
    detail: ({ target, props, onCleanup }) => {
      const view = mount(Detail, { target, props: { id: props.id } })
      onCleanup(() => unmount(view))
    }
  }
})
app.init()

A list that opens a detail

Zumly is created once, in the component that owns the canvas, and destroyed with it. The list renders the triggers; any element with zoom-me and data-to works, whoever rendered it.

App.svelte

<script>
  import { onMount } from 'svelte'
  import { mount, unmount } from 'svelte'
  import Zumly from 'zumly'
  import 'zumly/style.css'
  import List from './List.svelte'
  import Detail from './Detail.svelte'

  // Each view mounts its own component
  const mountView = (component, toProps = () => ({})) => ({ target, props, onCleanup }) => {
    const view = mount(component, { target, props: toProps(props) })
    onCleanup(() => unmount(view))
  }

  let canvas

  onMount(() => {
    const app = new Zumly({
      mount: canvas,
      initialView: 'list',
      views: {
        list: mountView(List),
        detail: mountView(Detail, props => ({ id: props.id }))
      }
    })
    app.init()
    return () => app.destroy()   // removes its views too
  })
</script>

<!-- The canvas fills its nearest positioned ancestor: give that a height -->
<div style="position: relative; height: 100vh">
  <div bind:this={canvas} class="zumly-canvas"></div>
</div>

List.svelte

<script>
  const items = [
    { id: '1', name: 'Engine' },
    { id: '2', name: 'Battery' },
    { id: '3', name: 'Brakes' }
  ]
</script>

<div class="list">
  <h1>Subsystems</h1>
  {#each items as item (item.id)}
    <div class="zoom-me" data-to="detail" data-id={item.id}>{item.name}</div>
  {/each}
</div>

When a view comes back

Sharing services and state

Pass stores or shared state once in componentContext; every view receives them as context and can hand them to its component as props.

const app = new Zumly({
  ...,
  componentContext: { user },
  views: {
    detail: ({ target, props, context, onCleanup }) => {
      const view = mount(Detail, { target, props: { id: props.id, user: context.user } })
      onCleanup(() => unmount(view))
    }
  }
})

Things to know

import { mount, unmount } from 'svelte'
import type { ViewFunction } from 'zumly'

const detail: ViewFunction = ({ target, props, onCleanup }) => {
  const view = mount(Detail, { target, props: { id: String(props.id) } })
  onCleanup(() => unmount(view))
}

Next

Where views come from, in step 4. The same pattern for React · Vue · Angular, and for radial layouts with Orbit.

Open this example ↗ Learn in six steps