Skip to main content
Version: 0.0.9

App State Subscriptions

Use kittl.appStore.subscribe() to react to real-time changes in the app state — selection changes, active tool switches, viewport updates, and more.

Subscribing to a Single Property​

Pass an array with one path and a callback that receives the current value.

const unsub = await kittl.appStore.subscribe(
['selectedObjectsIds'],
(ids) => {
console.log('selected:', ids);
}
);

Subscribing to Multiple Properties​

Pass multiple paths in the array. The callback receives one argument per path, in the same order.

const unsub = await kittl.appStore.subscribe(
[
'selectedObjectsIds',
'activeTool',
'viewport',
],
(ids, tool, viewport) => {
console.log('selection:', ids);
console.log('tool:', tool);
console.log('viewport:', viewport);
}
);

The callback fires whenever any of the subscribed values changes.

Unsubscribing​

subscribe() returns an unsubscribe function. Call it when you no longer need updates.

const unsub = await kittl.appStore.subscribe(
['selectedObjectsIds'],
(ids) => console.log(ids)
);

// Later, when done:
unsub();

Valid Paths​

Each path is a dot-separated string. Common top-level app state keys include the following. See AppState for the full state shape:

KeyDescription
selectedObjectsIdsIDs of top-level selected objects
selectedLayersIdsIDs of selected layers
selectedArtboardIdsIDs of selected artboards
selectedArtboardsObjectIdsObject IDs within selected artboards
allSelectedObjectsIdsAll selected IDs including nested groups
canvasModeMode object or null: { mode, targetId } for built-in modes, or { mode: 'custom', id, state } for custom modes. See Canvas Mode.
activeToolCurrently active tool ("move", "pen", "hand", etc.)
viewportViewport position and zoom state
highlightedObjectIdID of the currently hovered object

You can drill into nested properties using dot notation:

viewport.coords.tl.x
activeTool.type

Invalid paths — empty segments, unknown top-level keys — throw an error.

Handling undefined​

A callback argument is undefined when the path doesn't resolve to a value. Always account for undefined.

const unsub = await kittl.appStore.subscribe(
['activeTool'],
(tool) => {
if (tool === undefined) {
console.log('No active tool');
return;
}
console.log('tool:', tool);
}
);

Example: React to Selection Changes​

const unsub = await kittl.appStore.subscribe(
['selectedObjectsIds'],
async (ids) => {
if (!ids || ids.length === 0) {
hidePropertiesPanel();
return;
}

// Fetch details for the first selected object
const result = await kittl.design.object.getObject({ id: ids[0] });
if (result.isOk) {
showPropertiesPanel(result.result);
}
}
);

Example: Track Viewport and Tool Together​

const unsub = await kittl.appStore.subscribe(
['viewport', 'activeTool'],
(viewport, tool) => {
if (viewport) {
updateMinimap(viewport);
}
if (tool) {
updateToolbarHighlight(tool);
}
}
);

Additional State APIs in 0.0.9​

These methods belong to kittl.state and were added in SDK 0.0.9. Getters return their values inside SDK results; setters return SDK results with no payload.

GetterSetterValue
getIsViewOnlyMode()setIsViewOnlyMode(isViewOnlyMode)boolean
getCanvasSettings()setCanvasSettings(settings)SettingsType; the setter accepts a partial settings object
getPenToolSetting()setPenToolSetting(setting)AppState['penToolSetting']: stroke, stroke width, and fill; the setter accepts a partial object
getOutlineLoading()setOutlineLoading(id, loading)Record<string, boolean>; the setter takes an object ID and a boolean

kittl.state.isObjectLoading(id) returns a boolean in an SDK result for a specific object.

Pending Operations​

kittl.state.getPendingOperations() returns Record<string, PendingOperation> in an SDK result. kittl.state.isOperationPending(id, operation?) checks an object, optionally for a specific operation.

Use kittl.state.setPendingOperation(id, operation, origin?) and kittl.state.clearPendingOperation(id, operation, origin?) to update the pending operation. See PendingOperation for the published operation values and AppStateAPI for all signatures.