-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(UI): Implement a
DraggableList
component (#460)
This PR is the first step to fix #408. ## UI/UX preview https://github.com/user-attachments/assets/d9db0c12-bee1-4795-ab3b-fc7c4e11ae9e ## usage The component needs a reactive list of `Item` (a ref). Item is a regular object that needs an id filed that is a string. It will mutate the given array of items to reflect the user selected order. ```vue <script setup lang="ts"> import { ref } from "vue"; const draggableListData = ref( Array.from({ length: 25 }, (v, i) => ({ id: `${i}`, color: `hsl(${(360 / 25) * i}deg, 90%, 50%)`, content: Array.from( { length: Math.floor(Math.random() * 10) + 1 }, // Random number of items between 1 and 10 () => String.fromCharCode(97 + Math.floor(Math.random() * 26)) // Random lowercase letter ), })) ); </script> <template> <DraggableList v-model:items="draggableListData"> <template #item="{ id, color, content }"> <div :style="{ backgroundColor: color, color: 'white' }"> <span>ID: {{ id }}</span> <ul> <li v-for="(c, i) in content" :key="i">{{ c }}</li> </ul> </div> </template> </DraggableList> </template> ``` ## implementation choices The implementation introduces two new dependencies. - [html-to-image](https://github.com/bubkoo/html-to-image) to create rasterized version of the moved item - [interact.js](https://interactjs.io/) to streamline pointer interaction The main container is a flexbox, items flow normally in it (no absolute positioning). When a drag start the selected items becomes slightly transparent and a raster copy of it is generated. That raster copy follows user's pointer using computed translation (CSS transform). To make room for the item to be dropped each items also has a drop indicator. The size of this drop indicator reflects the size of the dragged item. I use margin top & bottom to give different feedback when dragging down or up. This is nice because no coordinates calculation is needed and items continue to flow normally in the container. To limit clashes with inner item code when dragging all the items are transformed to a rasterized version of themself. ## known limitation ~~For now it is not possible to automatically scroll the container when dragging outside of its visible range.~~ --------- Co-authored-by: Thomas S. <[email protected]>
- Loading branch information
1 parent
3c892b1
commit 2e80e75
Showing
13 changed files
with
603 additions
and
50 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<div id="container"> | ||
<div id="square"></div> | ||
</div> | ||
<script> | ||
const container = document.getElementById("container"); | ||
const square = document.getElementById("square"); | ||
setInterval(() => { | ||
square.style.backgroundColor = "#" + ((Math.random() * 0xffffff) << 0).toString(16); | ||
}, 500); | ||
setInterval(() => { | ||
const newHeight = Math.round(Math.random() * 200); | ||
container.style.height = `${newHeight}px`; | ||
square.style.height = `${newHeight / 2}px`; | ||
}, 1000); | ||
</script> | ||
<style> | ||
#container { | ||
display: flex; | ||
width: 100px; | ||
height: 100px; | ||
align-items: center; | ||
justify-content: center; | ||
padding: 5px; | ||
border: 1px dashed #ccc; | ||
background-color: #fff; | ||
transition: all 0.5s linear; | ||
} | ||
|
||
#square { | ||
width: 50px; | ||
height: 50px; | ||
transition: all 0.5s linear; | ||
} | ||
</style> |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.