# State

Import these from `@grafloria/engine`.

## Classes

### `ConnectionStateManager`

Manages connection creation state during drag operations

```ts
class ConnectionStateManager
```

**Methods**

- `constructor(eventBus: EventBus, diagram: DiagramModel | null = null)`
- `setDiagram(diagram: DiagramModel | null): void` — Point the manager at the live diagram (DiagramEngine calls this on load).
- `startConnection(sourcePort: PortModel, startPoint: Point): void` — Start connection drag from a port
- `updateConnection(currentPoint: Point, hoveredPort?: PortModel): void` — Update connection drag position
- `completeConnection(targetPort: PortModel): { success: boolean; link?: LinkModel }` — Complete connection to target port
- `cancelConnection(): void` — Cancel connection
- `setValidTargets(nodeIds: Set<string>, portIds: Set<string>): void` — Set valid target ports (called by a host that wants to narrow the set
further than the rules do — e.g. a wizard that only permits one legal move).
- `addValidator(validator: ConnectionValidator): void` — Add a custom connection validator
- `removeValidator(validator: ConnectionValidator): void` — Remove a custom connection validator
- `clearValidators(): void` — Clear all custom validators
- `getState(): Readonly<ConnectionDragState>` — Get current state (read-only)
- `isConnecting(): boolean` — Check if currently connecting
- `getSourcePort(): PortModel | null` — Get source port (if connecting)
- `getTargetPort(): PortModel | null` — Get target port (if hovering over one)
- `getCurrentMousePosition(): Point | null` — Get current mouse position
- `isOverValidTarget(): boolean` — Check if hovering over valid target

### `DiagramStore`

```ts
class DiagramStore
```

**Methods**

- `constructor(initialState?: Partial<DiagramState>)`
- `getState(): Readonly<DiagramState>` — Get current state (immutable)
- `setState(updater: (state: DiagramState) => void): void` — Set state with change tracking
- `select<T>(path: string): T` — Get state value by path
- `get(path: string): any` — Get state value by path
- `set(path: string, value: any): void` — Set state value by path
- `subscribe(listener: StateListener): () => void` — Subscribe to all state changes
- `watch(path: string, listener: PathListener): () => void` — Subscribe to path changes
- `computed<T>(key: string, compute: (state: DiagramState) => T, deps?: string[]): T` — Computed value with memoization
- `batch(fn: () => void): void` — Batch multiple state updates
- `reset(initialState?: Partial<DiagramState>): void` — Reset to initial state
- `timeTravel(index: number): void` — Time travel to history index
- `getHistory(): ReadonlyArray<StateSnapshot>` — Get history
- `createSnapshot(): StateSnapshot` — Create snapshot
- `restoreSnapshot(snapshot: StateSnapshot): void` — Restore snapshot

## Interfaces

### `ConnectionDragState`

Connection drag state
Tracks the state of an in-progress connection being dragged

```ts
interface ConnectionDragState
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `isConnecting` | `boolean` |  | Whether a connection is currently being dragged |
| `sourcePort` | `PortModel \| null` |  | Source port where connection started |
| `targetPort` | `PortModel \| null` |  | Target port currently hovered (if any) |
| `currentMousePosition` | `Point \| null` |  | Current mouse position in world coordinates |
| `previewPath` | `Point[] \| null` |  | Preview path points (for rendering connection line) |
| `validTargetNodes` | `Set<string>` |  | Set of node IDs that can accept this connection |
| `validTargetPorts` | `Set<string>` |  | Set of port IDs that can accept this connection |
| `isOverValidTarget` | `boolean` |  | Whether current hover position is over a valid target |
| `invalidTargetPorts` | `Map<string, ConnectionRejectionReason>` |  | Every port the drag has REJECTED, and why. |
| `rejectionReason?` | `ConnectionRejectionReason` |  | Why the CURRENT hover was rejected (undefined when it is valid). |
| `rejectionMessage?` | `string` |  | Human-readable form of {@link rejectionReason}. |

### `DiagramState`

```ts
interface DiagramState
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `diagram` | `DiagramModel \| null` |  |  |
| `selectedNodes` | `Set<string>` |  |  |
| `selectedLinks` | `Set<string>` |  |  |
| `hoveredElement` | `string \| null` |  |  |
| `focusedElement` | `string \| null` |  |  |
| `viewport` | `Viewport` |  |  |
| `zoom` | `number` |  |  |
| `gridEnabled` | `boolean` |  |  |
| `snapEnabled` | `boolean` |  |  |
| `activeTool` | `string` |  |  |
| `toolOptions` | `Record<string, any>` |  |  |
| `mode` | `'design' \| 'runtime' \| 'readonly'` |  |  |
| `locked` | `boolean` |  |  |
| `theme` | `'light' \| 'dark'` |  |  |
| `showMinimap` | `boolean` |  |  |
| `showToolbar` | `boolean` |  |  |
| `showProperties` | `boolean` |  |  |
| `renderStats` | `RenderStats` |  |  |
| `errors` | `Error[]` |  |  |
| `warnings` | `string[]` |  |  |

### `RenderStats`

```ts
interface RenderStats
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `fps` | `number` |  |  |
| `renderTime` | `number` |  |  |
| `nodeCount` | `number` |  |  |
| `linkCount` | `number` |  |  |
| `visibleNodes` | `number` |  |  |
| `visibleLinks` | `number` |  |  |

### `StateSnapshot`

```ts
interface StateSnapshot
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `timestamp` | `number` |  |  |
| `state` | `DiagramState` |  |  |
| `version` | `string` |  |  |

## Types

### `ConnectionValidator`

Connection validation function
Returns true if connection is allowed

```ts
type ConnectionValidator = (
  sourcePort: PortModel,
  targetPort: PortModel
) => boolean;
```

### `PathListener`

```ts
type PathListener = (value: any, oldValue: any) => void;
```

### `StateListener`

```ts
type StateListener = (state: DiagramState, changes: string[]) => void;
```
