Workspace API
The Workspace class is the core engine orchestrating events, DOM mounting, and overlay drawing. It is the primary public entry point for consumer integrations.
Constructor
import { Workspace } from '@canvus/core'
const ws = new Workspace(container: HTMLElement, callbacks?: WorkspaceCallbacks, config?: WorkspaceConfig)| Parameter | Type | Description |
|---|---|---|
container | HTMLElement | The host DOM element to mount the workspace into |
callbacks | WorkspaceCallbacks | Optional event callbacks (see Configuration) |
config | WorkspaceConfig | Optional configuration overrides (see Configuration) |
Node Management
addNode(node, parentId?, index?)
Mounts a node into the Shadow DOM, updates the tree hierarchy model, measures bounds, and triggers a layout repaint.
addNode(node: Readonly<WebHTMLNode>, parentId?: string | null, index?: number): RectReturns: Measured canvas-space bounds of the mounted node.
const rect = ws.addNode({
id: 'card-1',
rawMarkup: '<div class="card">Content</div>',
currentRect: { x: 100, y: 100, width: 300, height: 200 },
}, null, 0) // root level, first positionremoveNode(id)
Removes a node and all of its descendants from the DOM mount and the internal tree tracker.
removeNode(id: string): booleanupdateMarkup(id, markup)
Updates a node’s inner HTML, recalculates layout, and triggers a repaint.
updateMarkup(id: string, markup: string): Rect | nullClipboard & Deletion
deleteSelectedNode()
Deletes the currently selected node (if selection size is 1) from the workspace. Automatically generates a delete-node operation and commits the parent’s new HTML.
deleteSelectedNode(): voidduplicateSelectedNode()
Duplicates the selected node right next to it as a sibling. Generates a create-node operation and commits the parent’s HTML.
duplicateSelectedNode(): voidcopySelectedNode()
Copies the selected node’s markup and bounds to the internal clipboard.
copySelectedNode(): voidcutSelectedNode()
Cuts the selected node to the clipboard, removing it from the canvas.
cutSelectedNode(): voidpasteNode()
Pastes the node currently in the clipboard into the canvas. Resolves the location based on current selection: pastes inside a selected container, or as a sibling right after a selected leaf node.
pasteNode(): voidStyle Manipulation
setNodeStyle(id, property, value)
Mutates a CSS property on the node content element inside the Shadow DOM, triggers layout measurements, and commits changes.
setNodeStyle(id: string, property: string, value: string | null): voidsetNodeStyles(id, styles)
Batches style changes to limit reflow costs.
setNodeStyles(id: string, styles: Record<string, string | null>): voidws.setNodeStyles('card-1', {
'padding': '24px',
'background-color': '#f0f0f0',
'border-radius': '12px',
})Class Manipulation
addClass(id, className)
Appends a CSS class name, triggers reflow checks, and generates an update-classes operation.
addClass(id: string, className: string): voidremoveClass(id, className)
Removes a class name, triggers reflow, and emits an update-classes operation.
removeClass(id: string, className: string): voidtoggleClass(id, className)
Toggles a CSS class name.
toggleClass(id: string, className: string): voidTree Operations
reparentNode(nodeId, newParentId, index?)
Moves a node wrapper to a new parent in both the Shadow DOM tree and the tree model.
reparentNode(nodeId: string, newParentId: string | null, index?: number): voidreorderChild(nodeId, newIndex)
Reorders a node inside its parent, updating sibling arrangements.
reorderChild(nodeId: string, newIndex: number): voidgetNodeTree()
Returns the active structural tree database container.
getNodeTree(): NodeTreeOperations
applyOperation(op)
Replays a serialized action payload back onto the workspace. Used to trigger Undo/Redo state actions.
applyOperation(op: Operation): voidSee the Operations Guide for details on the operation schema and undo/redo patterns.
Selection
selectNode(id)
Sets selection to a single node.
selectNode(id: string): voiddeselectAll()
Clears active selection sets.
deselectAll(): voidgetSelectedIds()
Returns active node selections.
getSelectedIds(): ReadonlySet<string>Viewport
getViewport()
Gets the current zoom scale and translation panning offsets.
getViewport(): Readonly<ViewportMatrix>setViewport(vp)
Forces a viewport update.
setViewport(vp: ViewportMatrix): voidresetViewport()
Resets the workspace scale to 1:1 and offsets to 0,0.
resetViewport(): voidQuery Methods
getNodes()
Returns a flat array of all registered nodes in topological order.
getNodes(): ReadonlyArray<Readonly<ResolvedNode>>getWrapper(id)
Returns the wrapper element of the specified node.
getWrapper(id: string): HTMLElement | nullextractHTML(id)
Flat String Bridge. Exports clean, unpolluted HTML strings of target subtrees (stripping wrapper elements).
extractHTML(id: string): string | nullmeasureAll()
Forces a synchronous layout read of all elements.
measureAll(): Map<string, Rect>getContentRoot(id)
Returns the user’s content root element (the first child inside the SDK wrapper) for a given node ID. Useful for advanced DOM inspection or custom editor mounting.
getContentRoot(id: string): HTMLElement | nullcomputeAggregateBounds(nodes)
Utility function (exported from tree.ts) that computes a single bounding rectangle encompassing all provided nodes. Returns null if no nodes have measured rects.
import { computeAggregateBounds } from '@canvus/core'
const bounds = computeAggregateBounds(ws.getNodes())
// { x, y, width, height } or nullPreview Mode
setPreviewMode(enabled)
Toggles the workspace between Edit Mode and Preview Mode. In Preview Mode, all editing overlays (selection, handles, spacing adjusters) are hidden, pointer events pass through to the Shadow DOM content, and interactive elements behave normally (links, buttons, forms).
setPreviewMode(enabled: boolean): void// Enter preview mode — user can interact with content natively
ws.setPreviewMode(true)
// Return to edit mode — selection and resize handles re-appear
ws.setPreviewMode(false)Entering Preview Mode automatically clears the current selection, hover state, and any active interaction gesture.
isPreviewMode()
Returns whether the workspace is currently in Preview Mode.
isPreviewMode(): booleanDrawing Tools
setActiveTool(tool)
Sets the active drawing tool ("box", "text", or null to return to selection/idle mode). Selecting a drawing tool automatically deselects all nodes and changes the workspace cursor to crosshair.
setActiveTool(tool: CanvusTool): voidgetActiveTool()
Returns the currently active drawing tool.
getActiveTool(): CanvusToolsetDrawingTag(tag)
Customizes the HTML tag type for box or text drawing.
setDrawingTag(tag: string): voidgetDrawingTag()
Returns the active drawing tag based on the selected tool.
getDrawingTag(): stringState Forcing
forceNodeState(nodeId, state, enabled)
Forces a CSS pseudo-class state (hover, active, or focus) on the specified node element. This injects/removes a .canvus-state-hover, .canvus-state-active, or .canvus-state-focus class on the content root.
Useful in Electron environments where the SDK overlay blocks native :hover from reaching content elements.
forceNodeState(nodeId: string, state: "hover" | "active" | "focus", enabled: boolean): void// Force hover state on a button for visual preview
ws.forceNodeState('btn-1', 'hover', true)
// Remove forced hover
ws.forceNodeState('btn-1', 'hover', false)To delegate pseudo-class forcing to the host (e.g., via Chrome DevTools Protocol in Electron), use the onForcePseudoState callback. See Configuration.
JS Badge Marking
markNodeHasJS(nodeId)
Explicitly marks a node as containing JavaScript behavior. When the node is selected, the canvas overlay renders a specialized amber ⚡️ JS badge next to the layout badge.
The host application calls this based on its own analysis (static analysis, CDP, source maps) rather than the SDK auto-detecting scripts.
markNodeHasJS(nodeId: string): voidunmarkNodeHasJS(nodeId)
Removes the JavaScript badge from a node.
unmarkNodeHasJS(nodeId: string): voidhasJSMark(nodeId)
Returns whether a node is flagged as containing JavaScript behavior.
hasJSMark(nodeId: string): boolean// Flag node as having JS after executing its scripts
ws.markNodeHasJS('interactive-widget')
// Check status
if (ws.hasJSMark('interactive-widget')) {
console.log('Node has JS badge')
}
// Remove the flag
ws.unmarkNodeHasJS('interactive-widget')Synthetic Interaction
dispatchInteractionEvent(nodeId, eventName)
Dispatches a synthetic pointer/mouse event (e.g., mouseenter, mouseleave, click, dblclick) to a node’s content root element inside the Shadow DOM.
Useful for programmatically triggering element behaviors without requiring actual user pointer gestures.
dispatchInteractionEvent(nodeId: string, eventName: string): void// Simulate a click on an interactive element
ws.dispatchInteractionEvent('btn-1', 'click')
// Simulate hover entry/exit
ws.dispatchInteractionEvent('card-1', 'mouseenter')
ws.dispatchInteractionEvent('card-1', 'mouseleave')Stylesheet Injection
injectCSS(css)
Injects a CSS string into the Shadow DOM as a scoped <style> block. Automatically rewrites :root, html, and body selectors to :host for proper Shadow DOM scoping.
injectCSS(css: string): HTMLStyleElementws.injectCSS(`
.card { padding: 24px; border-radius: 12px; }
.btn { background: #6366f1; color: white; }
`)injectCSSLink(href)
Loads an external stylesheet into the Shadow DOM as a <link> element. Returns a promise that resolves when the stylesheet has loaded.
injectCSSLink(href: string): Promise<HTMLLinkElement>await ws.injectCSSLink('https://cdn.example.com/styles.css')Subsystem Access
getShadowMount()
Exposes the inner open Shadow Root mounting subsystem.
getShadowMount(): ShadowMountgetOverlayRenderer()
Exposes the inner 2D canvas overlay painter.
getOverlayRenderer(): OverlayRendererLifecycle
dispose()
Cleans up window resize, wheel, and mouse gesture event listeners.
dispose(): voidAlways call dispose() when unmounting the workspace to prevent memory leaks from orphaned event listeners.