···11+import type { Action } from "./actions";
22+import type { EditorState, ToolId } from "./reactivity";
33+44+/**
55+ * Tool interface - defines behavior for each editor tool
66+ *
77+ * Tools are explicit state machines that handle user input actions.
88+ * Each tool decides how to respond to actions and can update editor state.
99+ */
1010+export interface Tool {
1111+ /** Unique identifier for this tool */
1212+ readonly id: ToolId;
1313+1414+ /**
1515+ * Called when the tool becomes active
1616+ *
1717+ * @param state - Current editor state
1818+ * @returns Updated editor state
1919+ */
2020+ onEnter(state: EditorState): EditorState;
2121+2222+ /**
2323+ * Called when an action occurs while this tool is active
2424+ *
2525+ * @param state - Current editor state
2626+ * @param action - The action to handle
2727+ * @returns Updated editor state
2828+ */
2929+ onAction(state: EditorState, action: Action): EditorState;
3030+3131+ /**
3232+ * Called when the tool becomes inactive
3333+ *
3434+ * @param state - Current editor state
3535+ * @returns Updated editor state
3636+ */
3737+ onExit(state: EditorState): EditorState;
3838+}
3939+4040+/**
4141+ * Route an action to the currently active tool
4242+ *
4343+ * @param state - Current editor state
4444+ * @param action - Action to route
4545+ * @param tools - Map of tool ID to tool instance
4646+ * @returns Updated editor state after tool handles the action
4747+ */
4848+export function routeAction(state: EditorState, action: Action, tools: Map<ToolId, Tool>): EditorState {
4949+ const currentTool = tools.get(state.ui.toolId);
5050+ if (!currentTool) return state;
5151+ return currentTool.onAction(state, action);
5252+}
5353+5454+/**
5555+ * Switch from current tool to a new tool
5656+ *
5757+ * Calls onExit on the current tool (if it exists), then onEnter on the new tool.
5858+ *
5959+ * @param state - Current editor state
6060+ * @param newToolId - ID of tool to switch to
6161+ * @param tools - Map of tool ID to tool instance
6262+ * @returns Updated editor state with new tool active
6363+ */
6464+export function switchTool(state: EditorState, newToolId: ToolId, tools: Map<ToolId, Tool>): EditorState {
6565+ if (state.ui.toolId === newToolId) {
6666+ return state;
6767+ }
6868+6969+ const currentTool = tools.get(state.ui.toolId);
7070+ let nextState = state;
7171+ if (currentTool) {
7272+ nextState = currentTool.onExit(nextState);
7373+ }
7474+7575+ nextState = { ...nextState, ui: { ...nextState.ui, toolId: newToolId } };
7676+7777+ const newTool = tools.get(newToolId);
7878+ if (newTool) {
7979+ nextState = newTool.onEnter(nextState);
8080+ }
8181+8282+ return nextState;
8383+}
8484+8585+/**
8686+ * Create a map of tools from an array
8787+ *
8888+ * @param toolList - Array of tool instances
8989+ * @returns Map of tool ID to tool instance
9090+ */
9191+export function createToolMap(toolList: Tool[]): Map<ToolId, Tool> {
9292+ const map = new Map<ToolId, Tool>();
9393+ for (const tool of toolList) {
9494+ map.set(tool.id, tool);
9595+ }
9696+ return map;
9797+}