# Interaction

Import these from `@grafloria/angular`.

## Functions

### `buildMarqueeRect`

Build the world-space rect spanned by two points.

```ts
function buildMarqueeRect(
  down: ToolPointerEvent,
  current: ToolPointerEvent,
): MarqueeRect
```

### `directionToIntersectionMode`

Map drag direction → membership test. Left→right (or straight down) = `contain` (fully enclosed), right→left =
`intersect` (touched) — the Sketch / Figma convention.

```ts
function directionToIntersectionMode(
  downWorldX: number,
  currentWorldX: number,
): IntersectionMode
```

### `modifiersToSelectionMode`

Map modifier keys → selection combine mode. Shift → add, Cmd/Ctrl → toggle, Alt → subtract, none → replace. Precedence when several are held: shift > meta/ctrl > alt.

```ts
function modifiersToSelectionMode(m: ToolModifiers): SelectionMode
```

## Classes

### `ToolManager`

```ts
class ToolManager
```

**Methods**

- `constructor( private hitTest: SceneHitTester, private actions: ToolActions, private config: ToolManagerConfig, )`
- `setConfig(patch: Partial<ToolManagerConfig>): void` — Patch config (e.g. when the engine's interaction mode / threshold changes).
- `get activeTool(): ToolId | null` — The tool that has actually committed for the current gesture, else null.
- `get armedTool(): ToolId | null` — The tool armed on down (may still be pending the threshold), else null.
- `get hasGesture(): boolean` — True while a gesture is in flight (between down and up/cancel).
- `pointerDown(event: ToolPointerEvent, hit?: HitTestResult): void` — Begin a gesture: hit-test once and choose the single tool that will own it. Drag tools are armed but not committed until the threshold is crossed.
- `pointerMove(event: ToolPointerEvent): void` — Continue a gesture. Promotes an armed drag tool to committed once the
pointer crosses the threshold, then forwards the move to the active tool.
- `pointerUp(event: ToolPointerEvent): void` — End a gesture, firing the active tool's end hook.
- `pointerCancel(event: ToolPointerEvent): void` — Abort a gesture (pointercancel / mouseleave).

## Interfaces

### `HitTestResult`

```ts
interface HitTestResult
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `kind` | `HitKind` |  |  |
| `nodeId?` | `string` |  | Owning node id for `node` / `port` hits. |
| `nodeWasSelected?` | `boolean` |  | Whether the hit node was already selected BEFORE this pointerdown. MUST be captured before any on-down selection mutation — it is the sole input to DELIBERATE-mode drag gating. |
| `payload?` | `unknown` |  | Opaque hook for the actions layer (e.g. the port/link reference). |

### `MarqueeRect`

World-space rectangle, shaped to match the engine's `BoundingBox`.

```ts
interface MarqueeRect
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `left` | `number` |  |  |
| `top` | `number` |  |  |
| `right` | `number` |  |  |
| `bottom` | `number` |  |  |
| `width` | `number` |  |  |
| `height` | `number` |  |  |

### `MarqueeSelection`

Fully-resolved marquee query handed to the actions layer each move.

```ts
interface MarqueeSelection
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `rect` | `MarqueeRect` |  |  |
| `intersectionMode` | `IntersectionMode` |  |  |
| `selectionMode` | `SelectionMode` |  |  |

### `ToolActions`

Side-effect sink. Every method is OPTIONAL so a host can wire only the tools
it owns (the canvas keeps pan / link-draw in their existing branches for now
and implements just the node-drag + marquee actions). The manager still
arbitrates all five so the model — and its tests — stay complete.

```ts
interface ToolActions
```

**Members**

- `beginNodeDrag?(hit: HitTestResult, down: ToolPointerEvent): void`
- `updateNodeDrag?(current: ToolPointerEvent, down: ToolPointerEvent): void`
- `endNodeDrag?(current: ToolPointerEvent): void`
- `beginMarquee?(down: ToolPointerEvent): void`
- `updateMarquee?( selection: MarqueeSelection, current: ToolPointerEvent, down: ToolPointerEvent, ): void`
- `endMarquee?(current: ToolPointerEvent): void`
- `beginLinkDraw?(hit: HitTestResult, down: ToolPointerEvent): void`
- `updateLinkDraw?(current: ToolPointerEvent): void`
- `endLinkDraw?(current: ToolPointerEvent): void`
- `beginPan?(down: ToolPointerEvent): void`
- `updatePan?(current: ToolPointerEvent): void`
- `endPan?(current: ToolPointerEvent): void`

### `ToolManagerConfig`

```ts
interface ToolManagerConfig
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | `ToolInteractionMode` |  |  |
| `dragThreshold` | `number` |  | Screen-px movement before a drag tool commits. |

### `ToolModifiers`

Keyboard modifier snapshot carried by every event.

```ts
interface ToolModifiers
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `shift` | `boolean` |  |  |
| `ctrl` | `boolean` |  |  |
| `alt` | `boolean` |  |  |
| `meta` | `boolean` |  |  |

### `ToolPointerEvent`

Minimal pointer event the tools consume. Built per-event by the canvas'
`toToolEvent()` from the native MouseEvent/PointerEvent.

```ts
interface ToolPointerEvent
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `type` | `'down' \| 'move' \| 'up' \| 'cancel'` |  |  |
| `worldX` | `number` |  | World-space X (viewBox / zoom applied). |
| `worldY` | `number` |  | World-space Y. |
| `screenX` | `number` |  | Element-local screen X in CSS px — used for the drag threshold. |
| `screenY` | `number` |  | Element-local screen Y in CSS px. |
| `button` | `number` |  | Button whose state changed (0 = left, 1 = middle, -1 = pure move). |
| `buttons` | `number` |  | Bitmask of pressed buttons. |
| `modifiers` | `ToolModifiers` |  |  |

## Types

### `HitKind`

Also has every member of `String`, listed on its own entry.

What sits under the pointer at down-time.

```ts
type HitKind = 'node' | 'port' | 'link' | 'empty';
```

### `IntersectionMode`

Also has every member of `String`, listed on its own entry.

How a marquee decides membership (derived from drag direction).

```ts
type IntersectionMode = 'contain' | 'intersect';
```

### `SceneHitTester`

Injected scene query — returns what is under a world-space point.

```ts
type SceneHitTester = (worldX: number, worldY: number) => HitTestResult;
```

### `SelectionMode`

Also has every member of `String`, listed on its own entry.

How a marquee combines with the existing selection (derived from modifiers).

```ts
type SelectionMode = 'replace' | 'add' | 'subtract' | 'toggle';
```

### `ToolId`

Also has every member of `String`, listed on its own entry.

The five canvas tools. Exactly one is ever active per gesture.

```ts
type ToolId = 'select' | 'node-drag' | 'link-draw' | 'marquee' | 'pan';
```

### `ToolInteractionMode`

Also has every member of `String`, listed on its own entry.

Interaction mode string (matches the engine's `InteractionMode` enum values).

```ts
type ToolInteractionMode = 'direct' | 'deliberate' | 'smart';
```
