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:
| Key | Description |
|---|---|
selectedObjectsIds | IDs of top-level selected objects |
selectedLayersIds | IDs of selected layers |
selectedArtboardIds | IDs of selected artboards |
selectedArtboardsObjectIds | Object IDs within selected artboards |
allSelectedObjectsIds | All selected IDs including nested groups |
canvasMode | Mode object or null: { mode, targetId } for built-in modes, or { mode: 'custom', id, state } for custom modes. See Canvas Mode. |
activeTool | Currently active tool ("move", "pen", "hand", etc.) |
viewport | Viewport position and zoom state |
highlightedObjectId | ID 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.
| Getter | Setter | Value |
|---|---|---|
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.