puck icon indicating copy to clipboard operation
puck copied to clipboard

feat: Drag-and-drop reordering in outline tree

Open napter opened this issue 1 month ago • 6 comments

Summary

This PR implements a complete drag-and-drop system for reordering components in the Puck outline/layer tree using @dnd-kit/react.

Key Features

  • Full drag-and-drop support: Drag components to reorder within zones or move between zones
  • ZoneNode normalization: Explicit zone labels (e.g., 'items', 'content') shown in tree
  • Empty zone visibility: Zone labels remain visible even when empty, enabling first-item insertion
  • Smart drop targeting: Clear, intuitive drop positions with automatic redirects for confusing cases
  • Expansion state preservation: Components stay expanded when children are removed
  • Comprehensive test coverage: 39 unit tests covering flatten, projection, and preview logic

Demo

https://github.com/user-attachments/assets/b50b3b12-b055-447a-aef7-0bc906c1fbbd

Implementation Details

New Files

  • flatten.ts: Normalizes Puck's nested zone structure into flat array with ZoneNodes
  • projection.ts: Pure functions for computing drop targets from flattened tree
  • Test files (flatten.spec.ts, projection.spec.ts, projection-extended.spec.ts, preview.spec.ts)

Modified Files

  • LayerTree/index.tsx: Complete rewrite using DragDropProvider with sortable items
  • Outline/index.tsx: Simplified to use single unified LayerTree

Technical Approach

  • Uses experimental @dnd-kit/react adapter (aligned with Puck's existing DnD implementation)
  • ZoneNodes act as explicit drop targets with synthetic IDs (e.g., g1::zone::items)
  • Projection engine computes valid drops, prevents illegal subtree reparenting
  • Preview updates show exact drop position during drag

Testing

✅ All 39 unit tests passing, covering:

  • ZoneNode emission and hierarchy
  • Cross-zone moves and same-zone reorders
  • Empty zone handling
  • Illegal move detection
  • Preview positioning

User-Facing Changes

  • Zone labels (like 'items') now visible in outline tree
  • Drag handle appears on hover for draggable components
  • Visual feedback during drag shows where item will be dropped
  • Components can be reordered within zones or moved between zones
  • Empty zones remain visible as drop targets

Breaking Changes

None - this is a pure enhancement to existing outline functionality.

Checklist

  • [x] Implementation complete
  • [x] Unit tests passing (39/39)
  • [x] User testing completed
  • [x] No breaking changes
  • [ ] Documentation updated (if needed)
  • [ ] Demo video/GIF added (if requested)

napter avatar Nov 09 '25 19:11 napter

@napter is attempting to deploy a commit to the Puck Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Nov 09 '25 19:11 vercel[bot]

@chrisvxd @FedericoBonel what do you think? I'd love some feedback! It is really nice to be able to organize using the treeview - particularly if your page gets complex with lots of nested fields (flex layouts, grid, etc) and the drag and drop on page gets challenging.

napter avatar Nov 09 '25 20:11 napter

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
puck-demo Ready Ready Preview Comment Nov 18, 2025 6:04am

vercel[bot] avatar Nov 10 '25 02:11 vercel[bot]

@napter this looks awesome, thank you for doing that. Unfortunately I wasn't able to test or see the proper diff because you made a new directory -- would you be able to flatten the changes?

chrisvxd avatar Nov 11 '25 10:11 chrisvxd

@chrisvxd - sorry I missed a couple of commits previously. You should be good to review this now.

napter avatar Nov 16 '25 02:11 napter

Hey @napter! Thanks for the updates, I can't seem to be able to test this in the demo app, it should be available there right?

FedericoBonel avatar Nov 20 '25 09:11 FedericoBonel