g2 icon indicating copy to clipboard operation
g2 copied to clipboard

Drag'n'Drop/Sortable: Need a robust system

Open ItsJonQ opened this issue 5 years ago • 13 comments

Drag gestures are becoming increasingly more popular in Web UIs, and for good reason! They're super easy to use! They extend the fluid "life-like" experience we've become accustomed to from the mobile/tablet world. Therefore, it's important that this library includes a solid and flexible drag and drop / drag sort system.

Drag/Sort systems are almost always excluded from Component libraries. The main reason is... well... because they're heavy and complicated (aka. really hard!). I believe taking on this complexity is worth it as we'll be able to provide users with an easy to use + powerful way to create highly interactive experiences - be that in Gutenberg's UI, custom Block controls, WP Admin, and beyond.

Evaluating Libraries

Below are a handful of libraries I've been evaluating.

(Note: It's been an on-going goal of mine to have a powerful + easy-to-use drag/sort system for years now. I've been following these libraries for a while)

Each of their strengths and weaknesses. Their feature-set (animation handling, element/window scroll coordination, native browser drag attribute support, nesting, multi-list, etc...) vary from library to library. Weaknesses are usually missing features or the library being super complicated (i.e. verbose to code/manage).

Accessibility

Also, having a11y considerations built-in (as much as possible) would be incredibly helpful. Some of the libraries above do this well, others not so much.

Supporting Other Components

Certain components can have drag/sort built right in. FlatList comes to mind! This saves the user time from having rig up and manage multiple components together.

ItsJonQ avatar Aug 13 '20 15:08 ItsJonQ

Just made a push that prototypes s react-dnd solution:

https://github.com/ItsJonQ/g2/commit/f0360f53e3c6e3d1a3661c6e70324d92866aa367

It feels okay so far :). How... let's see if we can get some sort of animated sort/reorder solution going!

drag-drop-example

Demo: https://g2-components.xyz/iframe.html?id=components-draggable--default

ItsJonQ avatar Aug 15 '20 15:08 ItsJonQ

The above solution uses React DND. I'd like to explore React Beautiful DND next, as it has sortable features built in (as well as default support for mobile events)

ItsJonQ avatar Aug 15 '20 20:08 ItsJonQ

Here's React Beautiful DND:

react-bd

Neato sorting animations aside... Speaking purely from an API + dev perspective, I'm a fan. The composition, data flow, and callbacks feel easier to work with. Also, RBD has a bunch of a11y support built-in 👍

https://g2-components.xyz/iframe.html?id=components-draggable--react-beautiful-dnd

I believe we can replace <Sortable /> with RBD. We can also use it for <Draggable /> implementation.

Now to figure out nested lists 🤔

ItsJonQ avatar Aug 15 '20 22:08 ItsJonQ

Woo! Coming up with some neat interactions.

This was inspired by some of the block drag interaction designs from Gutenberg.

post-block-reorder

Demo: https://g2-components.xyz/iframe.html?id=components-draggable--drag-list-context

cc'ing @shaunandrews + @MichaelArestad

ItsJonQ avatar Aug 16 '20 00:08 ItsJonQ

I was confused at first as the what the logic was behind the text fading in-and-out on the right. I think what's happening is that the block being dragged remains unfaded, while every other block fades out. I'd actually expect the opposite behavior; The dragged block fades out (or is removed entirely) but every other block remains unchanged.

shaunandrews avatar Aug 17 '20 16:08 shaunandrews

I'd actually expect the opposite behavior

@shaunandrews Ah gotcha. We can do that :). What I shared in the gif was an experiment to see if:

  1. it even worked (lol)
  2. see how interaction x animations can be combined from different contexts (left list + right list)

ItsJonQ avatar Aug 17 '20 16:08 ItsJonQ

P.S. Update!

Check this example out 🔥

https://g2-components.xyz/iframe.html?id=components-draggable--drag-builder

ItsJonQ avatar Aug 17 '20 16:08 ItsJonQ

When dragging the rendered block (on the right) there's two things that strike me:

  1. Removing the block causes everything to shift, and I lose my desired dropzone in the shifting. Maybe the hole where the block was could still be represented? Maybe just a subtle background color in the empty space.
  2. Dragging a huge block is really hard; I can't see where I'm moving it, as it obscures everything behind it. Perhaps the block I'm dragging could shrink down in size so I can easier see where I'm about to drop it?

shaunandrews avatar Aug 17 '20 16:08 shaunandrews

  1. Gotcha! I worked on @jasmussen a bit on the Editor block drag interaction. We collapsed the block into a tiny "Chip" design that is dragged instead.

(For prototype purposes, I'm going to avoid coding up a toolbar)

For the interaction, there's a design decision we have to make:

a. Keep the placeholder (original empty space) the same size. Perhaps grey it out to indicate the drop zone. b. Shrink the placeholder (using an animation to communicate the change).

  1. Yes, we can (and should) shrink it down - into a draggable "Chip" design that @jasmussen made 👍

I can attempt these 2 updates next.

For context, the library that powers this (react-beautiful-dnd) cannot do what is described above out-of-the-box (I checked and attempted). That means, we'll have to apply some clever tinkering to achieve the desired effects.

ItsJonQ avatar Aug 17 '20 16:08 ItsJonQ

I just tried this and it's great! @shaunandrews did a good job identifying ways to improve it. I also struggled dragging a large block where I wanted, particularly, when there isn't much content on the page. Glad to see you iterating so quickly on this.

MichaelArestad avatar Aug 17 '20 17:08 MichaelArestad

Love it. Seems a lot less finicky than Gutenberg.

davewhitley avatar Aug 17 '20 18:08 davewhitley

Removing the block causes everything to shift, and I lose my desired dropzone in the shifting. Maybe the hole where the block was could still be represented? Maybe just a subtle background color in the empty space. Dragging a huge block is really hard; I can't see where I'm moving it, as it obscures everything behind it. Perhaps the block I'm dragging could shrink down in size so I can easier see where I'm about to drop it?

Important points as always, Shaun.

Dragging a huge block around was one important reason why we collapsed the block lifted into a tiny "chip". However a more important point is that we cannot show a fully opaque clone with a drop shadow as shown in this prototype. It's unfeasible (trying to avoid breaking Clarke's first law here) for a few reasons:

  • A theme can provide any arbitrary background color. When you "lift a block" it's essentially taken out of the flow, and in order for it to have an opaque background color, we explicitly have to add that color to the component.
  • This prototype (which I agree is beautiful) specifically applies a white background color. Presumably we could detect the theme background color and apply that. But what if you're dragging inside a group with a different background?
  • What if you're dragging it from inside a block with one background color and into one with another, should the background color on the fly?

By collapsing it into an abstract representation, we not only solve that, but we also don't cover too much of the page you're dragging things around on. It's a tradeoff, but one that to me feels worth it.

The other aspect, the layout shifting, is something I discussed a lot with @mtias back in the first version. I was in favor of the leaving a gray hole camp, and he was in the move blocks instantly camp. Since then I've come full circle to his point, because there is something immediately understandable when the block moves with your cursor rather than happening on drop. One of the bigger challenges with drag and drop, moving stretches so long the browser scrolls, is also slightly mitigated. And when you make an erroneous move, you just undo.

jasmussen avatar Aug 18 '20 07:08 jasmussen

Hey @ItsJonQ I thought I'd check in on this - keen to see how this is progressing as I want to upgrade the drag and drop library in a project I'm working on (and I try to keep in sync with the wp/gutenberg way).

My experiences as I've been testing a few drag and drop libraries also:

Some stuff you probably already know: I couldn't use the Gutenberg drag and and drop libraries as it was not responsive enough (ie, when dragging a block above / below another block, at the half way point, the block should move out of the way above / below, but sometimes its not responsive enough, you have to do slightly exaggerated gestures to make sure the movement is captured and the blocks move out of the way and the inserter is shown at the correct position).

Anyway, this led me to creating my own kind of block editor, with another library for drag and drop (a lot of work, just to get smooth drag and drop).

I only tested 2 (if I recall correctly, it was about 8 months ago):

React Beautiful DND - this was the best out of the box (and the one I went with) in terms of responsiveness and appearance, but doing things programmatically with the sensor API looks a bit awkward, and it doesn't look like its maintained anymore - also it doesn't support nested scroll containers, which may or may not be an issue, but I think somewhere along the line, it probably will be.

React DND - I think this could be good, but there was a lot of work to get animations setup (I actually gave up as I didn't have the time/skills) - however I think in React beautiful dnd a lot of the smoothness and responsiveness comes from performance optimizations - I think to get this working well would require some really clever programming - the bonus would be that we would have full control over how all this works going forwards - and it won't be abandoned.

Anyway, my testing hasn't been that comprehensive, but I've tested these two - if you want a hand trying any of others out and I can give them a spin and provide demos / feedback.

Cheers!

rmorse avatar Apr 11 '21 09:04 rmorse