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. The first segment must be one of the top-level app state keys:
| 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 | Current canvas mode ("erase", "crop", "inpaint", etc.) |
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);
}
}
);