-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdetectWrappedElements.ts
56 lines (48 loc) · 2.15 KB
/
detectWrappedElements.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
// [jQuery.position() equivalent is wrong](https://github.com/HubSpot/youmightnotneedjquery/issues/172)
function getTopPosition(el: Element) {
const { top } = el.getBoundingClientRect();
const { marginTop } = getComputedStyle(el);
return top - parseInt(marginTop, 10);
}
// [How to detect CSS flex wrap event](https://stackoverflow.com/q/40012428)
export function detectWrappedElements(
rootElement: HTMLElement,
wrapChildrenClassName: string,
nextIsWrappedClassName: string,
hasChildWrappedClassName: string
) {
// For each child of .wrap-children
// - find its previous sibling
// - check if its previous sibling is at the same top position
// - if not, add .next-is-wrapped
// - if same position, remove .next-is-wrapped
// [...HTMLCollection] vs Array.from(HTMLCollection): the latter doesn't need downlevelIteration with IE
const parents = Array.from(rootElement.getElementsByClassName(wrapChildrenClassName));
if (rootElement.classList.contains(wrapChildrenClassName)) parents.unshift(rootElement);
parents.forEach(parent => {
const { children } = parent;
for (let i = 0; i < children.length; i++) {
const child = children[i];
const prev = child.previousElementSibling;
if (prev !== null) {
const top = getTopPosition(child);
const prevTop = getTopPosition(prev);
if (top > prevTop) {
// There is no way to CSS style an element given a match on its next sibling
// [Is there a "previous sibling" CSS selector?](https://stackoverflow.com/q/1817792)
prev.classList.add(nextIsWrappedClassName);
} else if (top === prevTop) {
prev.classList.remove(nextIsWrappedClassName);
}
}
// If the next sibling has been removed since the last run,
// .next-is-wrapped may be present and we need to remove it
if (child.nextElementSibling === null) {
child.classList.remove(nextIsWrappedClassName);
}
}
});
const containsChildNextIsWrapped =
rootElement.getElementsByClassName(nextIsWrappedClassName).length > 0;
rootElement.classList.toggle(hasChildWrappedClassName, containsChildNextIsWrapped);
}