Skip to content

Conversation

@zero2sudo
Copy link
Owner

Pull Request: Drag-and-Drop Between Encoding Channels

Summary

Added the ability to drag field pills between encoding channels (e.g., drag "Horsepower" from X axis to Y axis). When both channels have fields, they swap positions.

Changes

File Change
src/types/index.ts Added DragPayload interface to distinguish drag sources
src/components/FieldList/FieldPill.tsx Updated drag payload to include sourceType: 'fieldList'
src/components/EncodingPanel/EncodingShelf.tsx Made pills draggable, added swap logic in drop handler

How It Works

The Problem: We needed to know where a drag originated to handle it correctly:

  • Drag from FieldList → copy/replace behavior (existing)
  • Drag from EncodingShelf → move/swap behavior (new)

The Solution: Added a DragPayload type that includes the source:

interface DragPayload {
  field: DetectedField;
  sourceType: 'fieldList' | 'encodingShelf';
  sourceChannel?: EncodingChannel;  // Only set when dragging from shelf
}

The drop handler checks sourceType and either replaces (from FieldList) or swaps (from EncodingShelf).

Bug We Hit & How We Fixed It

Symptom: Dragging from one encoding shelf to another showed visual feedback, but nothing happened on drop.

Debugging steps:

  1. Added console.log at start of handleDrop → never fired
  2. Added console.log in handleDragOver → fired correctly
  3. Pattern: "dragOver works, drop doesn't" = browser rejecting the drop

Root cause: HTML5 Drag and Drop requires effectAllowed (set on drag source) and dropEffect (set on drop target) to be compatible:

// Source (EncodingShelf pill):
e.dataTransfer.effectAllowed = 'move';

// Target (EncodingShelf drop zone):
e.dataTransfer.dropEffect = 'copy';  // ❌ MISMATCH - browser silently rejects!

Fix: Removed explicit dropEffect, letting the browser infer from effectAllowed:

const handleDragOver = (e: React.DragEvent) => {
  e.preventDefault();
  // Don't set dropEffect - let browser use effectAllowed from source
  setIsOver(true);
};

Key Lesson for Interns

When an event handler "should" fire but doesn't, check browser API rules before debugging your logic. HTML5 Drag and Drop will silently reject drops with no error if effectAllowed and dropEffect don't match.

Debugging strategy:

  1. Log at the start of handlers to confirm events fire
  2. If dragOver works but drop doesn't → browser rejection
  3. Check API compatibility rules (effectAllowed/dropEffect)

Test Plan

  • Drag field from FieldList to empty shelf → assigns
  • Drag field from FieldList to occupied shelf → replaces
  • Drag pill from X to empty Y → moves (X empty, Y has field)
  • Drag pill from X to occupied Y → swaps (fields exchange)
  • Drag pill, drop on same channel → no-op
  • Cancel drag (ESC or drop outside) → reverts
  • Remove button still works
  • Clear All still works

zero2sudo and others added 2 commits January 3, 2026 21:35
Enable dragging field pills from one encoding channel to another.
When dropped on an occupied channel, fields swap positions.
When dropped on an empty channel, field moves (source becomes empty).

Changes:
- Add DragPayload type to distinguish fieldList vs encodingShelf drags
- Update FieldPill to send sourceType in drag payload
- Make encoding shelf pills draggable with move/swap logic
- Fix effectAllowed/dropEffect mismatch that silently blocked drops

Includes debug console.logs (to be removed in follow-up commit).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Repository owner locked as resolved and limited conversation to collaborators Jan 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants