feat(commands): add app state dispatcher foundation

This commit is contained in:
syntaxbullet
2026-07-03 09:28:06 +02:00
parent 697d12725d
commit a8dbd26474
11 changed files with 331 additions and 3 deletions

View File

@@ -1 +1,4 @@
export type { AppState, EditorState, SelectionState, ViewportState } from "./state";
export { createInitialAppState, initialEditorState } from "./initial-state";
export type { AppStore, StateListener } from "./store";
export { createAppStore } from "./store";

26
editor/initial-state.ts Normal file
View File

@@ -0,0 +1,26 @@
import type { AppState, EditorState } from "./state";
export const initialEditorState: EditorState = {
viewport: {
center: { x: 0, y: 0 },
zoom: 1,
rotation: 0,
size: { w: 0, h: 0 },
},
selection: {
layerIds: [],
},
};
export function createInitialAppState(name = "Untitled"): AppState {
return {
document: {
id: crypto.randomUUID(),
name,
version: 1,
artboards: [],
assets: [],
},
editor: initialEditorState,
};
}

39
editor/store.ts Normal file
View File

@@ -0,0 +1,39 @@
import type { CommandDispatcher } from "@commands/dispatcher";
import { createCommandDispatcher } from "@commands/dispatcher";
import type { CommandRegistry } from "@commands/registry";
import type { AppState } from "./state";
export type StateListener = (state: AppState) => void;
export type AppStore = {
getState(): AppState;
subscribe(listener: StateListener): () => void;
dispatch: CommandDispatcher["dispatch"];
};
export function createAppStore(initialState: AppState, registry: CommandRegistry): AppStore {
let state = initialState;
const listeners = new Set<StateListener>();
const emit = () => {
for (const listener of listeners) listener(state);
};
const dispatcher = createCommandDispatcher({
registry,
getState: () => state,
setState: (nextState) => {
state = nextState;
emit();
},
});
return {
getState: () => state,
subscribe(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
},
dispatch: dispatcher.dispatch,
};
}