Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new drag-and-drop engine #598

Open
wants to merge 60 commits into
base: main
Choose a base branch
from
Open

Implement new drag-and-drop engine #598

wants to merge 60 commits into from

Conversation

chrisvxd
Copy link
Member

@chrisvxd chrisvxd commented Sep 4, 2024

Implement a new drag-and-drop engine using the experimental dnd-kit release. This is a backwards compatible upgrade, focused on two new pieces of functionality:

  1. Dragging between nested areas (closes Support dragging between DropZone areas #123)
  2. Dragging across advanced CSS layouts (inline, grid, flexbox) via elimination of edit wrappers (Explore elimination of edit wrappers #455, Feature request: DropZones support horizontal direction #520)

This implementation includes additional periphery features:

  • reduce DropZone to height of items unless empty
  • control empty DropZone height with minEmptyHeight prop
  • add DropZone collisionAxis API for forcing collision direction
  • support inline Drawers, deprecating unnecessary props

Closes #556, closes #481, closes #123, closes #455, closes #520

Testing

Quick start

Testing guide

  • Report issues in the PR comments
  • Check list of known issues before reporting
  • React strict mode currently causes the drag-and-drop to be unresponsive - if you used create-puck-app, you likely have this enabled in your next.config.js and will need to disable it.
  • Safari still has a bunch of issues
  • Mobile/touch still needs implementing
  • When using canary builds, you must explicitly reference the specific version in your package.json, i.e. "@measured/puck": "0.17.0-canary.XXXXXX"

What to test

  1. The new multi-column layout behaviour
  2. Dragging between DropZones
  3. General Puck functionality
  4. Code reviews welcome

Known issues

  • Latest canary triggers Invalid instance type error on DragDropRegistry.register
  • DragDropContext re-renders on pointer move
  • Doesn't work with React strict mode
  • Drawer items missing grab handler
  • Zoom changes don't refresh overlays
  • Overlay not accounting for scroll when iframe disabled
  • Safari behaviour buggy on desktop and mobile
  • Touch dragging (mobile) not yet fully implemented
  • Items sometimes incorrectly repositioned when dragging between nested areas (requires upstream fix)
  • Sporadic error when dragging NotFoundError: Failed to execute 'setPointerCapture' on 'Element': No active pointer with the given id is found. (requires upstream fix)

Implementation details

  • Use of the experimental dnd-kit release, with upstream contributions, particularly around iframes.
  • A custom dnd-kit plugin called NestedDroppablePlugin for detecting the appropriate droppable when using nested layouts.
  • A custom collision algorithm for complex layouts, inspired by react-beautiful-dnd.
  • Complete rebuild of DropZone and DraggableComponent components.
  • Fully backwards compatible.

Implementation tasks

  • Rebuild DropZone / DraggableComponent
  • Custom collision algorithm
  • Replace active DropZone detection logic with plugin
  • Fix NestedDroppablePlugin on Safari
  • Rebase
  • Don't select chrome UI text when dragging with iframe disabled
  • Fix outline items
  • Tidy implementation
  • Make preview more robust
  • Split different bugfixes
  • Optimise NestedDroppablePlugin
    • Consider using elementFromPoint
      • Need to account for frame enlargement
      • Is this actually more performance
    • Don't resize on each pointer move
  • Update pathData when dragging between areas
  • Add iframe support to dndkit
  • Fix autoscroller
  • Fix drop animation on Safari
  • Prevent action bar from getting cut-off on left side of frame
  • Update .drag permission behaviour
  • Fix undo/redo hotkeys when focus inside iframe
  • Fix ghosting when moving quickly between zones
  • Prevent overlay from flashing in bottom left during drop
  • Review draggable / droppable data attributes, and make types strict
  • Split different features and document
  • Fix build
  • Overlay not showing consistently in docs
  • Fix overlay performance issues in prod build
  • Sporadic flashing of overlay on drop

Bonus

  • Cancel drag if escape key used
  • Add drag handle to overlay item
  • Account for scrolling during drop animation
  • Persist droppable size when dragging between zones
  • Animate droppable resize

Follow-ons

  • Isolate styles to host
  • Migrate array fields to dndkit
  • Keyboard dragging

Copy link

vercel bot commented Sep 4, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
puck-demo ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 2, 2024 9:40pm
puck-docs ✅ Ready (Inspect) Visit Preview Dec 2, 2024 9:40pm

chrisvxd added a commit that referenced this pull request Sep 7, 2024
This will result in duplicate history entries if the item has a resolveData method. This is difficult to prevent without a deferredDispatch method, similar to that being explored in #598.
chrisvxd added a commit that referenced this pull request Sep 7, 2024
This will result in duplicate history entries if the item has a resolveData method. This is difficult to prevent without a deferredDispatch method, similar to that being explored in #598.
chrisvxd added a commit that referenced this pull request Sep 7, 2024
This will result in duplicate history entries if the item has a resolveData method. This is difficult to prevent without a deferredDispatch method, similar to that being explored in #598.
chrisvxd added a commit that referenced this pull request Sep 9, 2024
This will result in duplicate history entries if the item has a resolveData method. This is difficult to prevent without a deferredDispatch method, similar to that being explored in #598.
chrisvxd added a commit that referenced this pull request Sep 9, 2024
This will result in duplicate history entries if the item has a resolveData method. This is difficult to prevent without a deferredDispatch method, similar to that being explored in #598.
@princebansal
Copy link

@chrisvxd This sounds very exciting. Dnd kit will really be a good upgrade. May I know, if there are any estimates of when this will be ready to use. Both stable and beta version of it.

@chrisvxd
Copy link
Member Author

Thanks @princebansal - we don't have a timeline yet. It's slow progress as it's a non-trivial implementation.

I would like to get it out by end of October in v0.17, but that's not based on anything!

@chrisvxd chrisvxd marked this pull request as ready for review November 23, 2024 16:52

## Using DropZones
1. The [`<DropZone>` component](/docs/api-reference/components/drop-zone), enabling you to nest components
2. The [`inline` parameter](/docs/api-reference/configuration/component-config#inline), enable multi-directional drag-and-drop
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
2. The [`inline` parameter](/docs/api-reference/configuration/component-config#inline), enable multi-directional drag-and-drop
2. The [`inline` parameter](/docs/api-reference/configuration/component-config#inline), enabling multi-directional drag-and-drop

Comment on lines +204 to +224
<ConfigPreview
label="Example"
componentConfig={{
fields: {
title: {
type: "text",
},
},
defaultProps: {
title: "Hello, world",
},
inline: true,
render: ({ title, puck }) => {
return (
<p style={{ margin: 0 }} ref={puck.dragRef}>
{title}
</p>
);
},
}}
/>
Copy link
Member Author

@chrisvxd chrisvxd Nov 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example needs updating or removing

iframe.contentWindow?.addEventListener("mousemove", function (event) {
const rect = iframe.getBoundingClientRect();

// NB this is a different event
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is weird - check if possible to use same event, or use other solution

@nikhilbansal
Copy link

Thanks so much @chrisvxd - this is an awesome update. Looking forward to mobile touch implementation.

While double clicking on components.
Sometimes, it creates nesting of the demo, while sometimes it fails.

Screenshot 2024-11-24 at 11 01 32 AM Screenshot 2024-11-24 at 11 01 54 AM

@apurbo-omnixima
Copy link

apurbo-omnixima commented Dec 4, 2024

Hi @chrisvxd, thanks for this awesome update.

Is there any guide on how to migrate an existing project? I tried to install the canary version, but the drag and drop functionality was broken.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants