generated from solidjs-community/solid-lib-starter
-
Notifications
You must be signed in to change notification settings - Fork 32
/
create-sortable.ts
109 lines (95 loc) · 3.25 KB
/
create-sortable.ts
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
106
107
108
109
import { createEffect } from "solid-js";
import { createDraggable } from "./create-draggable";
import { createDroppable } from "./create-droppable";
import { RefSetter, combineRefs } from "./combine-refs";
import { useSortableContext } from "./sortable-context";
import { Listeners, useDragDropContext } from "./drag-drop-context";
import { Layout, noopTransform, Transform, transformsAreEqual } from "./layout";
import { transformStyle } from "./style";
interface Sortable {
(element: HTMLElement): void;
ref: RefSetter<HTMLElement | null>;
get transform(): Transform;
get dragActivators(): Listeners;
get isActiveDraggable(): boolean;
get isActiveDroppable(): boolean;
}
const createSortable = (
id: string | number,
data: Record<string, any> = {}
): Sortable => {
const [dndState, { displace }] = useDragDropContext()!;
const [sortableState] = useSortableContext()!;
const draggable = createDraggable(id, data);
const droppable = createDroppable(id, data);
const setNode = combineRefs(draggable.ref, droppable.ref);
const initialIndex = (): number => sortableState.initialIds.indexOf(id);
const currentIndex = (): number => sortableState.sortedIds.indexOf(id);
const layoutById = (id: string | number): Layout | null =>
dndState.droppables[id]?.layout || null;
const sortedTransform = (): Transform => {
const delta = noopTransform();
const resolvedInitialIndex = initialIndex();
const resolvedCurrentIndex = currentIndex();
if (resolvedCurrentIndex !== resolvedInitialIndex) {
const currentLayout = layoutById(id);
const targetLayout = layoutById(
sortableState.initialIds[resolvedCurrentIndex]
);
if (currentLayout && targetLayout) {
delta.x = targetLayout.x - currentLayout.x;
delta.y = targetLayout.y - currentLayout.y;
}
}
return delta;
};
createEffect(() => {
displace("droppables", id, sortedTransform());
});
const transform = (): Transform => {
return (
(id === dndState.active.draggable && !dndState.usingDragOverlay
? dndState.draggables[id]?.transform
: dndState.droppables[id]?.transform) || noopTransform()
);
};
const sortable = Object.defineProperties(
(element: HTMLElement) => {
draggable(element, () => ({ skipTransform: true }));
droppable(element, () => ({ skipTransform: true }));
createEffect(() => {
const resolvedTransform = transform();
if (!transformsAreEqual(resolvedTransform, noopTransform())) {
const style = transformStyle(transform());
element.style.setProperty("transform", style.transform);
} else {
element.style.removeProperty("transform");
}
});
},
{
ref: {
enumerable: true,
value: setNode,
},
transform: {
enumerable: true,
get: transform,
},
isActiveDraggable: {
enumerable: true,
get: () => draggable.isActiveDraggable,
},
dragActivators: {
enumerable: true,
get: () => draggable.dragActivators,
},
isActiveDroppable: {
enumerable: true,
get: () => droppable.isActiveDroppable,
},
}
) as unknown as Sortable;
return sortable;
};
export { createSortable };