Events API

The EventBus provides a publish/subscribe system for reacting to editor events. Use it for auto-save, analytics, custom integrations, or coordinating external UI with the editor state.

Usage

Basic Usagetypescript
const eventBus = engine.getEventBus();

// Subscribe to an event
const unsubscribe = eventBus.on('object:selected', (data) => {
  console.log('Selected object IDs:', data.objectIds);
});

// Emit a custom event
eventBus.emit('custom:event', { data: 'value' });

// Unsubscribe when done
unsubscribe();
💡
Return value
Every eventBus.on() call returns an unsubscribe function. Always call it when your listener is no longer needed to prevent memory leaks.

Multiple Listeners

Multiple Eventstypescript
const eventBus = engine.getEventBus();

// Track multiple events
const unsub1 = eventBus.on('object:added', (data) => {
  console.log('Object added:', data.id, data.type);
});

const unsub2 = eventBus.on('object:removed', (data) => {
  console.log('Object removed:', data.id);
});

const unsub3 = eventBus.on('object:modified', (data) => {
  console.log('Object modified:', data.id, data.properties);
});

// Clean up all listeners
function cleanup() {
  unsub1();
  unsub2();
  unsub3();
}

React Integration

In React, subscribe inside a useEffect and return the unsubscribe function as the cleanup:

React Patterntsx
import { useEffect } from 'react';
import { useEditorContext } from '@design-on-web/ui';

function SelectionTracker() {
  const engine = useEditorContext();

  useEffect(() => {
    const eventBus = engine.getEventBus();

    const unsubSelected = eventBus.on('object:selected', (data) => {
      console.log('Selected:', data.objectIds);
    });

    const unsubDeselected = eventBus.on('object:deselected', () => {
      console.log('Nothing selected');
    });

    return () => {
      unsubSelected();
      unsubDeselected();
    };
  }, [engine]);

  return null; // Headless tracker component
}

Auto-Save Pattern

Auto-Savetypescript
const eventBus = engine.getEventBus();

// Auto-save pattern
let saveTimeout;

eventBus.on('object:modified', () => {
  // Debounce saves to avoid saving on every small change
  clearTimeout(saveTimeout);
  saveTimeout = setTimeout(() => {
    const json = engine.toJSON();
    fetch('/api/designs/save', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ data: json }),
    });
  }, 2000);
});

// Track export completion
eventBus.on('export:complete', (data) => {
  console.log(`Exported as ${data.format}, size: ${data.blob.size} bytes`);
});

Event Reference

Editor Lifecycle

NameTypeDefaultDescription
editor:ready{}—Fired when the editor engine is fully initialized and ready for interaction.

Object Events

NameTypeDefaultDescription
object:selected{ objectIds: string[] }—Fired when one or more objects are selected on the canvas.
object:deselected{}—Fired when all objects are deselected.
object:added{ id: string; type: string }—Fired when a new object is added to the canvas.
object:removed{ id: string }—Fired when an object is removed from the canvas.
object:modified{ id: string; properties: Record<string, unknown> }—Fired when an object's properties change (move, resize, rotate, color, etc.).

Export Events

NameTypeDefaultDescription
export:start{ format: string }—Fired when an export operation begins.
export:complete{ format: string; blob: Blob }—Fired when an export operation completes successfully.
export:error{ format: string; error: Error }—Fired when an export operation fails.

Save Events

NameTypeDefaultDescription
save:start{}—Fired when a save operation begins.
save:complete{}—Fired when a save operation completes.

Plugin Events

NameTypeDefaultDescription
plugin:loaded{ name: string }—Fired when a plugin is successfully registered.
plugin:error{ name: string; error: Error }—Fired when a plugin fails to load.

Page Events

NameTypeDefaultDescription
page:switched{ index: number }—Fired when the active page changes.
page:added{ index: number }—Fired when a new page is added.
page:removed{ index: number }—Fired when a page is removed.

Version Events

NameTypeDefaultDescription
version:created{ id: string; label: string }—Fired when a new version snapshot is saved.
version:restored{ id: string }—Fired when a previous version is restored.

Custom Events

You can emit and listen for your own custom events using the same EventBus. Use a namespace prefix (e.g., myapp:) to avoid collisions with built-in events.

â„šī¸
Type safety
The EventBus accepts any string as an event name. For TypeScript projects, consider creating a typed wrapper around the EventBus to get autocomplete and type checking for your custom events.

Next Steps