Open elron opened 1 month ago
Hi, @elron! Thanks a lot for reaching out! And congratulations on your talk during the recent Svelte Summit. As a longtime WP user and a Svelte fan, that one was definitely one of my favorites :)
And regarding your query, I’ve been considering working on that specific feature for a while, and since I’ve finally been able to provide a solid ground for this package, this could be a good moment to give that a try.
It’ll definitely be quite tricky for lists to detect and handle foreign items (if even possible :P), so I can’t make any promises, but I will definitely give it my best shot :)
Thanks for the kind words about my Svelte Summit talk! It means a lot, especially coming from someone making such useful Svelte tools. Speaking of which - I really think this library deserves a spotlight at the next Svelte Summit! The UX is so polished, and multiple droppables would make it even more powerful.
I'm actually looking to migrate from a React app that uses react-beautiful-dnd to Svelte, and your library looks perfect except for this one feature. In my current app, I heavily rely on the multiple droppables functionality to move items between different lists, and also re-ordering the lists themselves. I totally understand the technical challenges involved though - just wanted to give you this context about my use case. Really excited to see how the library evolves!
PS: If it helps, this free Egghead.io course on "Beautiful and Accessible Drag and Drop with react-beautiful-dnd" really helped me understand how droppables work. (On lesson 9 minute 0:20 is where he shows the columns object structure, which might give you inspiration)
Thank you, @elron! Thanks for taking the time to provide all that context for your use case. I love this kind of concrete feedback since it provides an scenario and a feature that I might have not considered. Plus it’s always good to know that I might me helping someone out with the work that I’m doing here :)
While considering our options, I realized that making use of the Drag and Drop API would probably make this task much easier, but in the beginning (and after a lot of testing) I went the custom route because it allowed me for much more control over the visuals. I haven’t discarded this approach yet, and I’ve been considered rewriting the package using that DnD API, and I will definitely give it a go at some point. Plus with all the stuff I’ve learnt while build this, I might be able to sort out the API’s shortcomings this time :)
But at the moment it’s kind of hard for me to tell what approach could work considering the current state of this package. My best bet is creating a new component to wrap multiple lists inside in order to share state from one list to another, which might be what React Beautiful DnD is doing.
I’ve just started to work on it, so hopefully I’ll have an update soon enough :)
Thank you for such a detailed response! Really cool to hear about your different approaches and thinking process. I'm excited that you've started working on it! And yes, you'll be helping not just me, but many others too - I'm sure of it. I'm excited because this feature is essential for it to work and I'm happy to brainstorm ideas if you're open for it! but obviously I think you know better because you actually built everything and knows how it works.
The current behavior is great by the way, and I wonder if there's a way to extend it instead of re-writing everything - might be easier and less time consuming for you. Just throwing an idea here on how it could work:
<SortableContext on:sort={handleSort}>
{#each lists as list, index (list.id)}
<SortableList id={list.id}>
<!-- check if it has SortableContext or not, it it does not, then allow If
on:sort on <SortableList>. That way the API keeps working as it does now, but
only has extensions if its needed to have multiple sortables. -->
{#each items as item, index (item.id)}
<SortableItem id={item.id} {index}>
<div class="ssl-item__content">{item.text}</div>
</SortableItem>
{/each}
</SortableList>
{/each}
</SortableContext>
Here are two possible ways we could structure the data: Option 1 (Array of lists with nested items, already in the correct order [and when re-ordered the whole array gets modified]):
let lists = [
{
id: 'list-1',
items: [
{
id: 'list-1-item-1',
text: 'List 1 item 1',
},
{
id: 'list-1-item-2',
text: 'List 1 item 2',
}
]
},
{
id: 'list-2',
items: [
{
id: 'list-2-item-1',
text: 'List 2 item 1',
}
]
}
];
Option 2 (Normalized object structure, this is inspired by the React-DnD lib):
data = {
tasks: {
'task-1': { id: 'task-1', content: 'Take out the garbage' },
'task-2': { id: 'task-2', content: 'Watch my favorite show' },
'task-3': { id: 'task-3', content: 'Charge my phone' }
},
columns: {
'column-1': {
id: 'column-1',
title: 'To do',
taskIds: ['task-1', 'task-2']
},
'column-2': {
id: 'column-2',
title: 'Done',
taskIds: ['task-3']
}
},
columnOrder: ['column-1', 'column-2']
}
In my opinion, the first option is more Svelte-like in the philosophy of simplicity, but might need to be careful when actually changing the sort, and the second option is smart and conservative, maybe better for bigger objects, and easier to modify.
Another thing, I noticed the library is in svelte-4. I feel like maybe after migrating to Svelte 5 it will be easier to make this feature, as $state() can hold the whole data object/array and re-render in a more cost efficient way.
What are your thoughts on this? I hope you don't mind me brainstorming ideas - I'm just excited about the possibilities, but of course you know what's best for the library!
After some thinking, I think the second option (like react-beautiful-dnd) of structuring the data is more cost-effective, not just for the front end, but also when saving to the back end.
Because what actually changes during a sort is just:
taskIds: ['task-1', 'task-2']
or/and
columnOrder: ['column-1', 'column-2']
The items data itself (tasks) stays the same and doesn't need to be updated at all. This can be beneficial for two reasons:
Don’t you even worry, my friend! Your input is very welcome and appreciated! In fact, just yesterday I was thinking how nice it would be to have someone to discuss this stuff with :)
So thank you again for your feedback! And I was glad to see we’re very much in sync, by coincidence I even called this new context component <SortableContext>
just like you did :P
And yes, out of the box the second data structure that you shared seems to be more cost-effective, but I guess that will depend mostly on the kind of structure the user has created for his/her own app. But in all honesty, I prefer the first approach the most since to me it goes more in line with what has already been built for this package. I’m guessing most people will create lists with a small amount of items, so hopefully the difference in performance won’t be perceived :)
This has been way more challenging than I expected, but I’ve been exploring a few different approaches:
pointerenter
, pointerleave
, pointerover
, pointerout
) in combination with pointer capture methods and events.While walking myself through the drag events once again I remembered the main reason why I discarded them: they do not work on mobile devices x__x
Getting the first option to work would be the easiest, but I’m putting effort on getting the second one to work since (imo) it would keep the DX/UX simple while handling the tricky stuff behind the scenes (which has always been my main goal for this package) and probably make it much easier to implement something like nested lists in the near future.
That’s all I have for the moment! :P
Wow, that makes me so happy that you're open to brainstorming! And that's such a fun coincidence about the SortableContext name 😄
I really appreciate you explaining your thought process about the data structures. I totally trust your approach - if you feel the first option aligns better with the package's philosophy, that makes a lot of sense! Even if you go with that approach, I'll find a way to migrate my data structure to match it. (I'm thinking maybe to hold the actual data in another object, and store the "order" in your approach. That way we enjoy the best of both worlds!)
Super interesting to hear about the mobile device limitations with drag events - I hadn't considered that challenge, sounds annoying. Actually, I think I saw a video about this drag and drop problem by Alex Reardon (the creator of react-beautiful-dnd who deprecated it). If you haven't seen it, it might give you some inspiration: https://www.youtube.com/watch?v=Kz50msV-zq0. By the way, I'm not sure if it was this video or a different one.
Keep me posted on how it goes - I'm excited to see what you come up with!
Hey, I love this package, good job for making it! Looks beautiful and nice UX/UI.
I was wondering, do you have a future plan to support multiple droppables?
(Moving a sortable item from one sortable list to another sortable list).
Example:
https://react-beautiful-dnd.netlify.app/iframe.html?id=board--simple