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.
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()
targetis a fresh element that becomes the view. Zumly gives it thez-viewclass; add your own classes or a size to it if the view should not fill the canvas.propsholds the trigger'sdata-*attributes.data-id="42"arrives asprops.id, a string.onCleanupruns once, when the view is discarded. Unmount there; removing the DOM alone does not.
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
- The views behind the current one stay mounted, so their component state survives a zoom in and out. Nothing renders again.
- If something changed meanwhile (a store, a fetch), repaint in
onActivate(fn), which runs each time the view becomes current again. - Siblings you leave are discarded, unless
lateralNav: { keepAlive: true }keeps them while you stay at that level.
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
destroy()takes its views with it, so the component that creates Zumly can mount again (hot reload, an{#if}) on a clean canvas.- Do not render another
z-viewinsidetarget:targetalready is the view. Zumly warns in the console if you do. - Views are plain DOM, not Shadow DOM: your global styles apply inside them.
- Zumly ships its own types;
ViewFunctionandViewContexttype the view context.
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