DragSession
On this page
DragSession is the stable public handle for one drag gesture. It is a
TypeScript interface, not a constructor; SnapSort supplies it through drag
events and the root Container’s dragSession property.
import type { DragSession, DragStartEvent } from "@snap-engine/snapsort";
function onDragStart(event: DragStartEvent) {
const session: DragSession = event.session;
session.dragVisual = "preview";
} Interface
interface DragSession {
readonly root: Container;
readonly pointerId: number;
readonly items: readonly Item[];
readonly sources: readonly DragLocation[];
readonly pressedItem: Item;
readonly primaryItem: Item;
readonly start: Readonly<{ x: number; y: number }>;
readonly pointer: Readonly<{ x: number; y: number }>;
readonly status: DragSessionStatus;
dragVisual: DragVisual;
dropEffect: DropEffect;
/** @deprecated */
handoff(replacements: readonly Item[]): void;
} Properties
root
Type: Container · Read-only
The independent root Container that owns the gesture. It receives root
lifecycle callbacks and exposes this handle as root.dragSession while the
session is active.
const activeSession = event.session.root.dragSession; pointerId
Type: number · Read-only
The browser pointer identifier captured from the gesture that started the drag. Use it when correlating the session with application-level pointer state.
if (event.pointerId === session.pointerId) {
// Both refer to the pointer driving this drag.
} items
Type: readonly Item[] · Read-only
The complete ordered run participating in the drag. A single-item drag has one entry. Multi-drag participants are ordered by their original document position, not by which Item was pressed.
const draggedIds = session.items.map((item) => item.itemId); The array is frozen. Do not add, remove, or reorder its entries.
sources
Type: readonly DragLocation[] · Read-only
The gesture-origin locations parallel to items: sources[i] describes items[i]. They remain the original locations when the prospective target
changes and after a deprecated handoff.
const origins = session.items.map((item, index) => ({
item,
source: session.sources[index],
})); The array and each location are frozen.
pressedItem
Type: Item · Read-only
The Item on which pointer input began. It anchors pointer-following geometry
and can differ from primaryItem when the user presses a later member of a
multi-selection.
const pressedId = session.pressedItem.itemId; primaryItem
Type: Item · Read-only
The first participant in the ordered run; equivalent to items[0]. SnapSort
uses this Item for singular event fields and swap placement.
const isSingleDrag =
session.items.length === 1 && session.primaryItem === session.pressedItem; start
Type: Readonly<{ x: number; y: number }> · Read-only
Frozen world-space pointer coordinates captured when the drag began.
const distanceX = session.pointer.x - session.start.x; pointer
Type: Readonly<{ x: number; y: number }> · Read-only
The latest world-space pointer coordinates processed by SnapSort. Each value is an immutable snapshot. Read it inside callbacks; do not use it as a continuous framework render signal.
function onDropTargetChange(event: DropTargetChangeEvent) {
console.log(event.session.pointer);
} status
Type: DragSessionStatus · Read-only
The current public lifecycle phase:
type DragSessionStatus = "pending" | "active" | "dropping" | "ended"; "pending": SnapSort is runningonDragStart; activation can still be vetoed anddragVisualcan still be changed."active": pointer movement can resolve targets, hover, and ghost state."dropping": cancellation or pointer release is finalizing temporary and persistent state."ended": cleanup is complete androot.dragSessionis alreadynull.
if (session.status === "active") {
session.dropEffect = "none";
} dragVisual
Type: "item" | "preview" | "none" · Writable only while pending
Selects what follows the pointer independently of placement feedback:
"item"hoists and positions the real dragged Items."preview"leaves the Items in layout and creates a root-ownedpointer-previewGhost."none"leaves Items in layout without a pointer-following visual.
The default is "item" for euclidean and progressive mode, "none" for
insertion mode, and "preview" for swap mode. Set it synchronously inside onDragStart; changing it after activation or assigning another value throws.
const callbacks = {
onDragStart(event: DragStartEvent) {
event.session.dragVisual = "preview";
},
} satisfies ContainerCallbacks; Placement feedback remains independent, so a preview can coexist with a target spacer or insertion marker.
dropEffect
Type: "move" | "none" · Default: "move" · Writable while pending or active
Controls whether SnapSort performs its ordinary persistent drop mutation:
"move"commits the resolved move or swap through the root callback."none"suppresses that mutation whileonDragEndstill reports the resolved destination.
Changing it after dropping begins or assigning another value throws. A cancelled session never performs the persistent mutation.
const callbacks = {
onDragStart(event: DragStartEvent) {
event.session.dropEffect = "none";
},
onDragEnd(event: DragEndEvent) {
if (event.destination) handleApplicationOwnedDrop(event);
},
} satisfies ContainerCallbacks; Supporting Types
DragLocation
interface DragLocation {
readonly container: Container;
readonly containerMetadata: Record<string, unknown>;
readonly index: number;
} container is the direct owner, containerMetadata is its read-only
application metadata, and index is the zero-based position in that
Container. DragSession uses this type for every entry in sources.
const source: DragLocation = session.sources[0];
console.log(source.container.name, source.index); Methods
Deprecated handoff
/** @deprecated */
session.handoff(replacements: readonly Item[]): void; Transfers a pending gesture to an already-mounted parallel run of replacement
Items. It may only run synchronously during onDragStart. Replacements must
be a unique, equally sized run of non-ghost Items attached to the same root
and engine, and must not include the current participants. Invalid input or a
call after the pending phase throws without changing the current participants.
This escape hatch predates the supported move-and-backfill copying recipe and has no recommended first-party use case. Do not add new integrations that use it; it may be removed in a future release.
Appendix
Obtaining and Retaining the Session
All events from one active gesture expose the same event.session object.
Policy events created for programmatic work may instead have session: null.
The root’s dragSession property returns the active handle during the gesture
and null before startup and after cleanup; a nested Container’s property
always returns null.
An ended handle remains readable, but it no longer describes an active operation. Prefer callback-local access unless the application specifically needs to correlate lifecycle events.
Lifecycle and Multi-Item Model
Returning false from onDragStart ends the pending session without
activation or onDragEnd. An activated drag fires onDragEnd after temporary
state is cleared, including cancellation and a return to the source.
For multi-item drags, items and sources stay parallel in document order. pressedItem anchors the gesture; primaryItem is the run head used by
singular APIs. One pointer-preview can represent the whole run, while
slot-preserving lifecycles may create one spacer anchor per represented Item.
For the full chronology, see Drag Start, Drags and Ghosts, and Commit and Cleanup.