ItsJonQ / g2

✨ An experimental reimagining of WordPress components
http://g2-components.com/
MIT License
105 stars 12 forks source link

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

Open ItsJonQ opened 4 years ago

ItsJonQ commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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

shaunandrews commented 4 years ago

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.

ItsJonQ commented 4 years ago

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 commented 4 years ago

P.S. Update!

Check this example out 🔥

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

shaunandrews commented 4 years ago

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?
ItsJonQ commented 4 years ago
  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.

MichaelArestad commented 4 years ago

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.

davewhitley commented 4 years ago

Love it. Seems a lot less finicky than Gutenberg.

jasmussen commented 4 years ago

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:

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.

rmorse commented 3 years ago

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!