Drag / drop: beside + spatial alignment

This document describes the current editor drag pipeline for flex parents. Older notes that referenced besideDetector in layoutInference, separate alignment dwell paths, or BesideDropIndicator-only alignment are obsolete.

This document describes the current editor drag pipeline for flex parents. Older notes that referenced besideDetector in layoutInference, separate alignment dwell paths, or BesideDropIndicator-only alignment are obsolete.

Orchestrator

  • findPosition2D (packages/sdk/src/chrome/shell/findPosition2D.ts) runs each pointer move while dragging.
  • Order of evaluation: early main-axis slots (gap, before-all, after-all) → nearest childbeside (column split) → cross-axis alignment + before/after zone on the nearest child.
  • syncResolvedIntent writes the latest placement + optional cross-axis snapshot into spatialSession (setLastResolvedIntent) so indicators and drop execution read one source of truth.

Modules (packages/sdk/src/chrome/shell/spatial/)

AreaFileRole
Main-axis reorderreorderMainAxis.tsSort children, gap / edge slots, before / after vs main position
BesidedetectBeside.ts + besideConstants.tsColumn “split beside sibling” hit testing; shared numeric thresholds
Cross-axis aligndetectAlignCrossFromDrag.tsDirection-dominant drag + optional cursor zones
Zones onlyalignCrossAxisZones.tsInner 32px edges + middle third; outer ratio bands on cross-axis; tiny-container guard (MIN_ALIGN_CONTAINER_PX)
SessionspatialSession.tsDrag origin, alignment preview/commit, last resolved SpatialIntent
TypesspatialIntent.tsReorderMainIntent, BesideIntent, AlignCrossIntent, compounds

Alignment during drag

  • Single path: updateAlignCrossFromDragsetActiveCrossAxisAlign / clearCrossAxisPreviewOnly in spatialSession. There is no second detector or dwell-only alignment hook.
  • Direction first: dominant movement along the cross-axis (vs main-axis) above a deadzone selects start/center/end from cursor position in the parent box.
  • Zone fallback: if direction does not yield an intent, inferCrossAxisIntentFromCursorZones may still set intent from cursor position (inner vs outer parent per drag origin).
  • Gaps: Early-return branches (e.g. dropping in the gap between siblings) still call updateAlignCrossFromDrag so alignment updates while the pointer stays in a gap.
  • Beside wins: If tryBesideInColumn hits, setActiveCrossAxisAlign(null, null) clears alignment so beside placement does not combine with a stale align preview. onBesideDrop in besideDrop.ts also clears alignment at drop start.

Indicators and drop

  • DropZoneIndicator reads intent from spatialSession (e.g. getLastResolvedIntent, alignment getters) — not from a parallel alignment store.
  • CustomEventHandlers / executeSpatialDrop consume the same session state when applying moves and alignment on drop.
  • alignmentInference.ts is for drop-time class resolution (applyAlignmentOnDrop, labels, inner vs wrapper). It does not own drag-time intent detection.

Deprecated / removed concepts

  • besideDetector inside layoutInference (removed); beside logic lives under spatial/.
  • AlignmentDropIndicator, useDwellIntent, detectAlignmentIntent (removed).
  • Stub globals clearAlignmentIntent / setBesideDropInProgress (removed); use spatialSession APIs instead.