-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathResizeManager.ts
96 lines (82 loc) · 2.59 KB
/
ResizeManager.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
import { DOMElement } from '../core/DOM/DOMElement'
/**
* Defines a {@link ResizeManager} entry
*/
export interface ResizeManagerEntry {
/** {@link HTMLElement} to track */
element: DOMElement['element'] | Element
/** Priority in which to call the callback function */
priority?: number
/** Function to execute when the {@link element} is resized */
callback: () => void | null
}
/**
* Tiny wrapper around {@link ResizeObserver} used to execute callbacks when given {@link HTMLElement} size changes.
*/
export class ResizeManager {
/** Whether we should add elements to our {@link resizeObserver} or not */
shouldWatch: boolean
/** Array of {@link ResizeManagerEntry | entries} */
entries: ResizeManagerEntry[]
/** {@link ResizeObserver} used */
resizeObserver: ResizeObserver
/**
* ResizeManager constructor
*/
constructor() {
// default to true
this.shouldWatch = true
this.entries = []
this.resizeObserver = new ResizeObserver((observedEntries) => {
// get all entries corresponding to that element, and sort them by priority
const allEntries = observedEntries
.map((observedEntry) => {
return this.entries.filter((e) => e.element.isSameNode(observedEntry.target))
})
.flat()
.sort((a, b) => b.priority - a.priority)
allEntries?.forEach((entry) => {
if (entry && entry.callback) {
entry.callback()
}
})
})
}
/**
* Set {@link shouldWatch}
* @param shouldWatch - whether to watch or not
*/
useObserver(shouldWatch = true) {
this.shouldWatch = shouldWatch
}
/**
* Track an {@link HTMLElement} size change and execute a callback function when it happens
* @param entry - {@link ResizeManagerEntry | entry} to watch
*/
observe({ element, priority, callback }: ResizeManagerEntry) {
if (!element || !this.shouldWatch) return
this.resizeObserver.observe(element)
const entry = {
element,
priority,
callback,
}
this.entries.push(entry)
}
/**
* Unobserve an {@link HTMLElement} and remove it from our {@link entries} array
* @param element - {@link HTMLElement} to unobserve
*/
unobserve(element: DOMElement['element'] | Element) {
this.resizeObserver.unobserve(element)
this.entries = this.entries.filter((e) => !e.element.isSameNode(element))
}
/**
* Destroy our {@link ResizeManager}
*/
destroy() {
this.resizeObserver.disconnect()
}
}
/** @exports @const resizeManager - {@link ResizeManager} class object */
export const resizeManager = new ResizeManager() as ResizeManager