Store API

Design on Web uses a Zustand store for managing editor state. The store is the single source of truth for UI state, selection, tool mode, panel visibility, and more.

Accessing State in React

Use the useEditorStore hook with a selector function to subscribe to specific state slices. The component only re-renders when the selected value changes.

React Usagetsx
import { useEditorStore } from '@design-on-web/ui';

function StatusBar() {
  const zoom = useEditorStore((s) => s.zoom);
  const canvasSize = useEditorStore((s) => s.canvasSize);
  const selectedIds = useEditorStore((s) => s.selectedObjectIds);
  const isDirty = useEditorStore((s) => s.isDirty);

  return (
    <div>
      <span>Zoom: {Math.round(zoom * 100)}%</span>
      <span>Canvas: {canvasSize.width} x {canvasSize.height}</span>
      <span>Selected: {selectedIds.length}</span>
      {isDirty && <span>Unsaved changes</span>}
    </div>
  );
}
💡
Selector performance
Always select the minimum state you need. Selecting the entire state object causes the component to re-render on every state change.
Selector Best Practicestsx
// Good: subscribe to minimal state slices for performance
const zoom = useEditorStore((s) => s.zoom);
const tool = useEditorStore((s) => s.activeTool);

// Avoid: selecting the entire state causes re-renders on every change
// const state = useEditorStore((s) => s); // Don't do this

Accessing State Outside React

For vanilla JS or non-React contexts, use engine.getStore() to access the raw Zustand store:

Direct Accesstypescript
// Access state outside React components
const state = engine.getStore().getState();
console.log('Current zoom:', state.zoom);
console.log('Active tool:', state.activeTool);
console.log('Layers:', state.layers);

Subscribing to Changes

Subscribe to state changes outside of React using the store's subscribe method:

Subscribetypescript
// Subscribe to all state changes
const unsubscribe = engine.getStore().subscribe((state) => {
  console.log('State changed:', state);
});

// Subscribe to specific state slice (with selector)
const unsubscribeZoom = engine.getStore().subscribe(
  (state) => state.zoom,
  (zoom, prevZoom) => {
    console.log('Zoom changed from', prevZoom, 'to', zoom);
  }
);

// Unsubscribe when done
unsubscribe();
unsubscribeZoom();

State Fields

The following fields are available in the store. All fields are read-only from the consumer's perspective — they are updated internally by the engine.

Canvas

NameTypeDefaultDescription
zoomnumber1Current zoom level (1 = 100%).
canvasSize{ width: number; height: number }{ width: 1080, height: 1080 }Current canvas dimensions in pixels.
backgroundColorstring'#ffffff'Current canvas background color.

Selection and Tools

NameTypeDefaultDescription
selectedObjectIdsstring[][]IDs of all currently selected objects.
activeToolstring'select'Currently active tool: 'select', 'rect', 'circle', 'triangle', 'line', 'text', 'image', 'draw', 'pan'.
brushConfig{ color: string; width: number; opacity: number }{ color: '#000', width: 3, opacity: 1 }Current freehand drawing brush configuration.

Layers and Pages

NameTypeDefaultDescription
layersLayerInfo[][]Array of layer info objects for the current page, ordered bottom to top.
pagesPageInfo[][]Array of page info objects.
activePageIndexnumber0Index of the currently active page.

History

NameTypeDefaultDescription
canUndobooleanfalseWhether undo is available.
canRedobooleanfalseWhether redo is available.

Versions

NameTypeDefaultDescription
versionsVersionInfo[][]Array of saved version snapshots.
activeVersionIdstring | nullnullID of the currently active version, or null.

Localization

NameTypeDefaultDescription
localestring'en'Current locale code (e.g., 'en', 'id', 'ja').

UI Panels

NameTypeDefaultDescription
leftPanelOpenbooleantrueWhether the left side panel is open.
rightPanelOpenbooleantrueWhether the right property panel is open.
activeLeftPanelstring'templates'Active left panel tab: 'templates', 'elements', 'icons', 'uploads', 'pages', 'layers'.
activeRightTabstring'properties'Active right panel tab: 'properties', 'text', 'fill', 'stroke'.

Status

NameTypeDefaultDescription
isDirtybooleanfalseWhether the canvas has unsaved changes.
isSavingbooleanfalseWhether a save operation is currently in progress.
isExportingbooleanfalseWhether an export operation is currently in progress.

Next Steps