-
Notifications
You must be signed in to change notification settings - Fork 22
/
SortableList.svelte
105 lines (95 loc) · 2.49 KB
/
SortableList.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<script>
import { quintOut } from "svelte/easing";
import { crossfade } from "svelte/transition";
import { flip } from "svelte/animate";
// FLIP ANIMATION
const [send, receive] = crossfade({
duration: d => Math.sqrt(d * 200),
fallback(node, params) {
const style = getComputedStyle(node);
const transform = style.transform === "none" ? "" : style.transform;
return {
duration: 600,
easing: quintOut,
css: t => `
transform: ${transform} scale(${t});
opacity: ${t}
`
};
}
});
// DRAG AND DROP
let isOver = false;
const getDraggedParent = node =>
node.dataset && node.dataset.index
? node.dataset
: getDraggedParent(node.parentNode);
const start = ev => {
ev.dataTransfer.setData("source", ev.target.dataset.index);
};
const over = ev => {
ev.preventDefault();
let dragged = getDraggedParent(ev.target);
if (isOver !== dragged.id) isOver = JSON.parse(dragged.id);
};
const leave = ev => {
let dragged = getDraggedParent(ev.target);
if (isOver === dragged.id) isOver = false;
};
const drop = ev => {
isOver = false;
ev.preventDefault();
let dragged = getDraggedParent(ev.target);
let from = ev.dataTransfer.getData("source");
let to = dragged.index;
reorder({ from, to });
};
// DISPATCH REORDER
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
const reorder = ({ from, to }) => {
let newList = [...list];
newList[from] = [newList[to], (newList[to] = newList[from])][0];
dispatch("sort", newList);
};
// UTILS
const getKey = item => (key ? item[key] : item);
// PROPS
export let list;
export let key;
</script>
<style>
ul {
list-style: none;
padding: 0;
}
li {
border: 2px dotted transparent;
transition: border 0.1s linear;
}
.over {
border-color: rgba(48, 12, 200, 0.2);
}
</style>
{#if list && list.length}
<ul>
{#each list as item, index (getKey(item))}
<li
data-index={index}
data-id={JSON.stringify(getKey(item))}
draggable="true"
on:dragstart={start}
on:dragover={over}
on:dragleave={leave}
on:drop={drop}
in:receive={{ key: getKey(item) }}
out:send={{ key: getKey(item) }}
animate:flip={{ duration: 300 }}
class:over={getKey(item) === isOver}>
<slot {item} {index}>
<p>{getKey(item)}</p>
</slot>
</li>
{/each}
</ul>
{/if}