Edit slides

Connect text, table-cell, formatting, and object-transform edits to a session.

Connect editing

Use an editing session instead of a read-only artifact. Set editable on the view and connect its callbacks to the session. Reassign the returned artifact after each edit so the view updates.

Svelte
<script lang="ts">
  import { untrack } from 'svelte';
  import { openPresentationEditingSession, type PresentationArtifact } from '@tumblerjs/slides';
  import { PresentationSlideView } from '@tumblerjs/svelte/slides';

  let { bytes }: { bytes: Uint8Array } = $props();
  const session = untrack(() => openPresentationEditingSession(bytes));
  let artifact = $state(session.artifact);
  let index = $state(0);
  let canUndo = $state(false);
  let canRedo = $state(false);
  let error = $state('');

  function apply(operation: () => PresentationArtifact) {
    try {
      artifact = operation();
      canUndo = session.canUndo;
      canRedo = session.canRedo;
      error = '';
    } catch (cause) {
      error = cause instanceof Error ? cause.message : 'Could not apply this edit.';
    }
  }
</script>

<button disabled={!canUndo} onclick={() => apply(() => session.undo())}>Undo</button>
<button disabled={!canRedo} onclick={() => apply(() => session.redo())}>Redo</button>
{#if error}<p role="alert">{error}</p>{/if}

<div style="height: 540px; min-width: 0">
  {#if artifact.document.slides[index]}
    <PresentationSlideView
      presentation={artifact.document}
      slide={artifact.document.slides[index]!}
      editable
      onobjectschange={(changes) => apply(() => session.execute({
        name: 'batch',
        commands: changes.map(({slideId, objectKey, x, y, width, height, rotation}) => ({
          name: 'update-object', slideId, objectKey, x, y, width, height,
          ...(rotation === undefined ? {} : {rotation}),
        })),
      }))}
      ontextedit={(change) => apply(() => session.editText(change))}
      onformat={(change) => apply(() => session.formatText(change))}
      onshapechange={(change) => apply(() => session.styleShape(change))}
      onundo={(redo) => apply(() => redo ? session.redo() : session.undo())}
    />
  {/if}
</div>

The text and shape formatting controls appear when their callbacks are connected. To add the thumbnail rail, pass artifact.document as its presentation and bind the same index used by the view.

Use the editor

ActionControl
Select several objectsDrag from empty canvas space to enclose objects. Shift-click adds or removes an object; Shift-drag adds enclosed objects. Escape clears the selection.
Move selected objectsDrag it, or select it and use the arrow keys.
Resize or rotateDrag an edge or corner handle to resize. Use the handle above the object to rotate; hold Shift to snap to 15° increments.
Edit textDouble-click a text box, or select it and press Enter. Select words to apply formatting with the toolbar.
Edit a tableDouble-click a cell. Tab and Shift+Tab move between cells.
Finish editingPress Escape or Ctrl+Enter. Click blank slide space to clear the selection.
Change shape coloursSelect the shape, then use the fill and outline controls.
Next Export a presentation