[]previous and next page

Svelte

Use CanvasFlow in Svelte 3, 4 or 5 with an action that mounts the canvas and stores that follow the editor.

Svelte components are compiled, so canvasflow/svelte does not ship one. It gives you what Svelte is best at instead: an action that mounts the canvas into any element, and stores that follow the editor. It works with Svelte 3, 4 and 5 and needs no peer, because the stores follow Svelte's store contract.

A board in a few lines#

Board.sveltesvelte
<script>
  import { createFlow } from 'canvasflow/svelte'

  const flow = createFlow()
</script>

<div use:flow.action={{ persistenceKey: 'board' }} style="height: 100vh"></div>

createFlow() makes one canvas for the component. Its action mounts the canvas and the default UI into the element and removes them when the element goes away. Give the element a height, because an editor needs room.

Options#

The action takes everything createCanvasFlow accepts (persistenceKey, dir, readonly, themes, plugins, shapes, tools, storage…), plus:

Option What it does
ui false for no default UI, or an object that configures it (see Customizing the UI).
onMount Called once with (editor, app, ui). Return a function and it runs as a cleanup.

Options are read once, when the canvas mounts. dir and readonly follow later changes, so use:flow.action={{ dir }} follows a variable.

Follow the editor#

flow.value(selector) returns a store of any value of the editor. It is undefined until the canvas has mounted, and it updates only when the result changes.

Board.sveltesvelte
<script>
  import { createFlow } from 'canvasflow/svelte'

  const flow = createFlow()
  const selected = flow.value((editor) => editor.getSelectedIds().length)
  const shapes = flow.value((editor) => editor.getCurrentPageShapes().length)
</script>

<div use:flow.action={{ persistenceKey: 'board' }} style="height: 100vh"></div>
<p>{$selected ?? 0} selected of {$shapes ?? 0}</p>

flow.editor, flow.app and flow.ui are stores too (null until mounted). flow.on('tool', handler) listens to an event for as long as the canvas is mounted. flowStores(flow) returns ready-made stores for selectedIds, tool, camera, canUndo, canRedo, theme and direction.

Headless#

createFlowCanvas() is the same without the default UI, and never references it, so your bundle does not carry the toolbar. Build your own:

Board.sveltesvelte
<script>
  import { createFlowCanvas, flowStores } from 'canvasflow/svelte'

  const flow = createFlowCanvas()
  const editor = flow.editor
  const { tool, canUndo } = flowStores(flow)
  const tools = ['select', 'draw', 'rectangle', 'arrow', 'text']
</script>

<div role="toolbar">
  {#each tools as id}
    <button aria-pressed={$tool === id} on:click={() => $editor?.setTool(id)}>{id}</button>
  {/each}
  <button disabled={!$canUndo} on:click={() => $editor?.undo()}>Undo</button>
</div>
<div use:flow.action style="height: 100vh"></div>

See Building your own UI for the full tour.

SvelteKit and server rendering#

Actions run in the browser, so nothing renders on the server. The element is an empty box until the page runs, and importing canvasflow/svelte on a server is safe.