# DragSession

> Headless drag-and-drop session: owns the item being dragged, the drop candidate under the pointer, and the position of the pending drop computed against it.

```ts
import { DragSession } from "@sdxc/ui/behaviors";
```

Owns one drag-and-drop interaction and dispatches a plain `"change"` event
from every mutating method, so a pointer- or keyboard-driven mixin
subscribes once and keeps every view it drives in sync from this state.

## Signature

```ts
new DragSession<TData = unknown>()
```

## Properties

| Property | Type | Description |
| --- | --- | --- |
| `source` | `DragSession.Source<TData> \| null` | Item currently being dragged, or `null` when no session is active. |
| `target` | `DragSession.Target \| null` | Drop candidate currently under the pointer; `null` while the session is idle or the pointer sits away from every valid target. |
| `active` | `boolean` | Whether a drag session is currently in progress. |

## Methods

| Method | Description |
| --- | --- |
| `start(source: DragSession.Source<TData>): void` | Begins a drag session for the given item, implicitly ending any session already in progress first. Always dispatches `"change"`. |
| `moveOver(target: DragSession.Target): void` | Records the drop candidate currently under the pointer. A no-op outside an active session and when key and position match the last call, so a drop indicator repositions only on actual movement. |
| `clearTarget(): void` | Clears the current drop candidate and keeps the session running, e.g. when the pointer moves past every valid target mid-drag. A no-op while the target is already clear. |
| `drop(): DragSession.DropDetail<TData> \| null` | Commits a drop at the current target and ends the session. Returns `null` and leaves the state untouched while the session is idle or the target is unset. |
| `cancel(): void` | Ends the current session and discards the pending drop, e.g. on Escape or a pointer release away from every valid target. A no-op while the session is idle. |

## Examples

```tsx
let session = new DragSession<{ index: number }>();
session.addEventListener("change", () => update());
session.start({ key: "row-1", data: { index: 0 } });
session.moveOver({ key: "row-3", position: "after" });
session.drop();
```

## Used with it

The events, constants and types its module publishes, each imported from `@sdxc/ui/behaviors` too.

### DragSession.Source

Item that starts a drag session: a stable key identifying it, plus an
optional consumer-defined payload carried for the life of the session
and read back when the drop commits.

#### Members

| Member | Type | Description |
| --- | --- | --- |
| `key` | `string` | Stable identifier for the dragged item. |
| `data?` | `TData` | Consumer-defined payload carried for the life of the session. |

### DragSession.Target

Drop candidate currently under the pointer.

#### Members

| Member | Type | Description |
| --- | --- | --- |
| `key` | `string` | Stable identifier for the candidate drop target. |
| `position` | `Position` | Position of the pending drop relative to this target. |

### DragSession.DropDetail

Snapshot returned when a drag session ends in a committed drop.

#### Members

| Member | Type | Description |
| --- | --- | --- |
| `source` | `Source<TData>` | Item that was dragged. |
| `target` | `Target` | Target the item was dropped on. |

### DragSession.EventMap

Events dispatched by DragSession as its state changes.

#### Members

| Member | Type | Description |
| --- | --- | --- |
| `change` | `Event` | Dispatched after the drag source, the current target, or its position changes. |

### DragSession.Position

Position of a pending drop relative to its current target. `"before"` and
`"after"` insert the dragged item next to the target for reordering;
`"on"` drops onto the target itself, nesting into it or filling a drop zone.

#### Signature

```ts
type DragSession.Position = "before" | "after" | "on"
```

One of `"before"`, `"after"`, `"on"`.
