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 thisAccessing 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
| Name | Type | Default | Description |
|---|---|---|---|
zoom | number | 1 | Current zoom level (1 = 100%). |
canvasSize | { width: number; height: number } | { width: 1080, height: 1080 } | Current canvas dimensions in pixels. |
backgroundColor | string | '#ffffff' | Current canvas background color. |
Selection and Tools
| Name | Type | Default | Description |
|---|---|---|---|
selectedObjectIds | string[] | [] | IDs of all currently selected objects. |
activeTool | string | '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
| Name | Type | Default | Description |
|---|---|---|---|
layers | LayerInfo[] | [] | Array of layer info objects for the current page, ordered bottom to top. |
pages | PageInfo[] | [] | Array of page info objects. |
activePageIndex | number | 0 | Index of the currently active page. |
History
| Name | Type | Default | Description |
|---|---|---|---|
canUndo | boolean | false | Whether undo is available. |
canRedo | boolean | false | Whether redo is available. |
Versions
| Name | Type | Default | Description |
|---|---|---|---|
versions | VersionInfo[] | [] | Array of saved version snapshots. |
activeVersionId | string | null | null | ID of the currently active version, or null. |
Localization
| Name | Type | Default | Description |
|---|---|---|---|
locale | string | 'en' | Current locale code (e.g., 'en', 'id', 'ja'). |
UI Panels
| Name | Type | Default | Description |
|---|---|---|---|
leftPanelOpen | boolean | true | Whether the left side panel is open. |
rightPanelOpen | boolean | true | Whether the right property panel is open. |
activeLeftPanel | string | 'templates' | Active left panel tab: 'templates', 'elements', 'icons', 'uploads', 'pages', 'layers'. |
activeRightTab | string | 'properties' | Active right panel tab: 'properties', 'text', 'fill', 'stroke'. |
Status
| Name | Type | Default | Description |
|---|---|---|---|
isDirty | boolean | false | Whether the canvas has unsaved changes. |
isSaving | boolean | false | Whether a save operation is currently in progress. |
isExporting | boolean | false | Whether an export operation is currently in progress. |
Next Steps
- Events API — event-based alternative to store subscriptions
- EditorEngine API — methods that modify state
- React Guide — using hooks in React components