Skip to content

Editor API Reference

The main all-in-one editor component.

interface ElucimEditorProps {
initialDocument?: RenderableDocument | ElucimDocument;
initialFrame?: number | 'last';
theme?: ElucimTheme;
editorTheme?: Record<string, string>;
onDocumentChange?: (document: ElucimDocument, details: ElucimEditorChangeDetails) => void;
onCompatibilityWarnings?: (warnings: string[]) => void;
onBrowseImage?: BrowseImageFn;
imageResolver?: ImageResolverFn;
className?: string;
style?: React.CSSProperties;
}
PropDescription
initialDocumentStarting document. ElucimDocument is the public authoring path; renderable documents are accepted for compatibility.
initialFrameStarting frame, or 'last' to open at the final linear frame.
themeShared content ElucimTheme; editor chrome is derived from it.
editorThemeEditor chrome token overrides. Accepts bare names or full CSS variable names.
onDocumentChangeCalled after edits with Elucim Document output and compatibility details. Skips initial mount.
onCompatibilityWarningsCalled when document output has warnings such as renamed IDs, pruned timelines, or invalid restored output.
onBrowseImageOpens a host-provided image picker from image fields.
imageResolverResolves opaque image refs in editor preview.
className / styleRoot editor container styling.
<ElucimEditor
initialDocument={doc}
initialFrame="last"
theme={contentTheme}
editorTheme={{ 'color-scheme': 'light', accent: '#2563eb' }}
onDocumentChange={(nextDoc, details) => {
save(nextDoc);
if (details.warnings.length > 0) showWarnings(details.warnings);
}}
/>
interface ElucimEditorChangeDetails {
changedFormat: boolean;
warnings: string[];
}

warnings describe compatibility work performed while restoring editor edits to normalized output, such as deleted timeline targets or state-machine states that lost a timeline link.

Internal shell layout for advanced composition inside an EditorProvider.

interface ElucimEditorLayoutProps {
theme?: ElucimTheme;
editorTheme?: Record<string, string>;
className?: string;
style?: React.CSSProperties;
document?: ElucimDocument;
onDocumentChange?: (document: ElucimDocument) => void;
}
import { EditorProvider, ElucimEditorLayout, useEditorDocument } from '@elucim/editor';
function CustomSaveButton() {
const doc = useEditorDocument();
return <button onClick={() => save(doc)}>Save working document</button>;
}
<EditorProvider initialDocument={doc}>
<ElucimEditorLayout document={doc} onDocumentChange={setDoc} />
<CustomSaveButton />
</EditorProvider>;

Use the top-level ElucimEditor unless you specifically need custom panels inside the editor context.

ExportDescription
ElucimEditorMain editor component.
ElucimEditorLayoutDocked workspace shell for custom composition.
ElucimCanvasCanvas with zoom/pan, selection, preview frames, minimap hooks, and overlays.
ToolbarCreate palette and file/history/theme controls.
InspectorContextual property panel.
TimelineTimeline and state-machine motion panel.
FloatingPanelGeneric draggable/resizable panel primitive used by overlays.
SelectionOverlaySelection boxes, resize handles, and rotation handles.
DotGridZoom-adaptive canvas grid.
MinimapCanvas overview.
ZoomControlsZoom buttons and fit controls.
EditorMenuBarOptional menu bar for host integrations.

Returns the editor context object:

function useEditorState(): {
state: EditorState;
dispatch: React.Dispatch<EditorAction>;
};
const { state, dispatch } = useEditorState();
dispatch({ type: 'SELECT', ids: ['title'] });
dispatch({ type: 'UNDO' });

Returns the current editor working document.

function useEditorDocument(): RenderableDocument;

Returns selected element IDs.

function useEditorSelection(): string[];
HookDescription
useViewport()Zoom/pan state and helpers.
useDrag()Move, resize, and rotate interactions.
useMarquee()Marquee selection.
useMeasuredBounds()DOM-based element bounds measurement.
interface EditorState {
document: RenderableDocument;
selectedIds: string[];
viewport: { x: number; y: number; zoom: number };
past: RenderableDocument[];
future: RenderableDocument[];
currentFrame: number;
isPlaying: boolean;
activeTool: EditorTool;
isPanning: boolean;
toolbarPosition: { x: number; y: number };
inspectorPosition: { x: number; y: number } | null;
inspectorPinned: boolean;
toolbarCollapsed: boolean;
themeOverrides: Record<string, string>;
}
type EditorTool = 'select' | 'rect' | 'circle' | 'line' | 'arrow' | 'text' | 'latex';

CANVAS_ID is the sentinel used when the canvas root is selected:

import { CANVAS_ID } from '@elucim/editor';
const canvasSelected = selectedIds.includes(CANVAS_ID);

The reducer supports selection, document replacement, element editing, grouping, ordering, arrangement, viewport, frame playback, panel state, theme overrides, and history:

ActionPayload
SELECT, SELECT_ADD, SELECT_TOGGLE, DESELECT_ALLSelection updates
SET_DOCUMENTReplace the working document
UPDATE_ELEMENT, UPDATE_CANVASProperty updates
ADD_ELEMENT, DELETE_ELEMENTS, DUPLICATE_ELEMENTSElement CRUD
MOVE_ELEMENT, RESIZE_ELEMENT, ROTATE_ELEMENTCanvas transforms
GROUP_ELEMENTS, UNGROUPGrouping
RENAME_ELEMENT, REORDER_ELEMENTIdentity and Object ordering
BRING_FORWARD, SEND_BACKWARD, BRING_TO_FRONT, SEND_TO_BACKSibling order
ALIGN_ELEMENTS, DISTRIBUTE_ELEMENTSMulti-selection layout
SET_VIEWPORT, ZOOM_TO_FITViewport controls
SET_FRAME, SET_PLAYINGPlayback
SET_TOOL, SET_PANNINGInteraction mode
SET_EDITOR_THEMERuntime chrome token overrides
UNDO, REDOHistory

The reducer still contains legacy wrapper compatibility actions for old editor working documents, but normalized public authoring should use timelines and state machines.

InteractionBehavior
Delete / BackspaceDelete selected elements
Ctrl+ZUndo
Ctrl+Y / Ctrl+Shift+ZRedo
Ctrl+ASelect all
Ctrl+DDuplicate
Ctrl+C / Ctrl+VCopy / paste
Ctrl+G / Ctrl+Shift+GGroup / ungroup
Ctrl+] / Ctrl+[Bring forward / send backward
Ctrl+Shift+] / Ctrl+Shift+[Bring to front / send to back
Arrow keysNudge by 1px
Shift+Arrow keysNudge by 10px
Ctrl+= / Ctrl+-Zoom in / out
Ctrl+0 / Ctrl+1Fit / 100% zoom
Space + dragPan
Middle-click dragPan
Right-clickContext menu
Alt+drag elementDuplicate, then drag copy
Shift+drag resize handleConstrained resize
interface BrowseImageResult {
src?: string;
ref?: string;
displayName?: string;
width?: number;
height?: number;
alt?: string;
}
type BrowseImageFn = () => Promise<BrowseImageResult | null>;
type ImageResolverFn = (ref: string) => string | Promise<string>;

Exports:

ImagePickerProvider
useImagePicker
ImageResolverProvider
useImageResolver

See Image Assets.

function v(token: string, scheme?: 'light' | 'dark'): string;
function buildThemeVars(overrides?: Record<string, string>): React.CSSProperties;
function deriveEditorTheme(contentTheme: ElucimTheme, colorScheme: 'light' | 'dark'): Record<string, string>;
function makeRotateCursor(color?: string): string;
const EDITOR_TOKENS: Record<string, string>;
const EDITOR_TOKENS_LIGHT: Record<string, string>;
const ROTATE_CURSOR: string;

See Editor Theming.

function exportToJson(document: RenderableDocument, options?: { pretty?: boolean }): string;
function importFromJson(json: string): { document: RenderableDocument | null; errors: string[] };
function downloadAsJson(document: RenderableDocument, filename?: string): void;

importFromJson() accepts Elucim Document JSON, validates it, and migrates it into the editor working document shape. Host apps should persist onDocumentChange output when they need normalized document JSON.

function getElementBounds(element: object):
{ x: number; y: number; width: number; height: number } | null;
function mergeBounds(boxes: Array<{ x: number; y: number; width: number; height: number }>):
{ x: number; y: number; width: number; height: number };
function isPointInBounds(
point: { x: number; y: number },
bounds: { x: number; y: number; width: number; height: number }
): boolean;
function computeSnap(value: number, gridSize: number): number;
const ELEMENT_TEMPLATES: ElementTemplate[];
function getTemplatesByCategory(): Record<string, ElementTemplate[]>;
const CATEGORY_LABELS: Record<string, string>;

Template categories are presentation, shape, line, text, math, and data.