-
Notifications
You must be signed in to change notification settings - Fork 0
/
ReOrderComponents.js
93 lines (79 loc) · 2.56 KB
/
ReOrderComponents.js
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
import { h, Component, Fragment } from "preact";
import "./ReOrderComponents.scss";
import createDragHandler from "../createDragHandler.js";
const DROP_ZONE_ID = "re-order-elements";
const CHECK_CHILDREN_ELEMENT = "re-order-elements-check-children";
const CURRENTLY_RE_ORDERING_ID = "re-order-elements-reordering";
/**
* @type {HTMLElement[]}
*/
const observees = [];
const clickHandler = e => {
e.preventDefault();
const { target } = e;
const { id: originalID } = target;
target.id = CHECK_CHILDREN_ELEMENT;
const subElements = target.querySelectorAll(
`#${CHECK_CHILDREN_ELEMENT}>[data-type]`
);
if (subElements.length) {
Array.from(
document.getElementsByClassName(CURRENTLY_RE_ORDERING_ID)
).forEach(el => el.classList.remove(CURRENTLY_RE_ORDERING_ID));
target.classList.add(CURRENTLY_RE_ORDERING_ID);
target.prepend(document.getElementById(DROP_ZONE_ID));
flushEventListeners();
Array.from(subElements).forEach(addEventListener);
if (subElements.length === 1) {
// If there's just 1 Element, try to travers as there's nothing to reorder
subElements[0].click();
} else {
target.scrollIntoView({ behavior: "smooth", block: "center" });
}
} else if (originalID) {
target.id = originalID;
} else {
target.removeAttribute("id");
}
};
const dragStartHandler = createDragHandler(({ target }, destination) => {
if (destination) {
target.parentElement.insertBefore(target, destination);
} else {
target.remove();
}
});
/**
* @param {HTMLElement} el
*/
const addEventListener = el => {
observees.push(el);
el.addEventListener("click", clickHandler);
el.addEventListener("dragstart", dragStartHandler);
el.draggable = true;
};
const flushEventListeners = () => {
observees.forEach(el => {
el.removeEventListener("click", clickHandler);
el.removeEventListener("dragstart", dragStartHandler);
el.draggable = false;
});
observees.splice(0);
};
export default class ReOrderComponents extends Component {
componentDidMount() {
Array.from(
document.querySelectorAll(`#${DROP_ZONE_ID}~[data-type]`)
).forEach(addEventListener);
}
componentWillUnmount() {
flushEventListeners();
Array.from(
document.getElementsByClassName(CURRENTLY_RE_ORDERING_ID)
).forEach(el => el.classList.remove(CURRENTLY_RE_ORDERING_ID));
document.getElementById(DROP_ZONE_ID).remove();
}
render() {
return <div data-ignore data-do-not-export id={DROP_ZONE_ID} />;
}
}