You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
59 lines
1.4 KiB
59 lines
1.4 KiB
export type ResizeObservedNode = HTMLElement | null | undefined
|
|
export type ResizeObservedNodeGetter = () => ResizeObservedNode
|
|
|
|
function canObserveResize(): boolean {
|
|
return typeof window !== 'undefined' && typeof ResizeObserver !== 'undefined'
|
|
}
|
|
|
|
export class SvelteResizeObserver {
|
|
readonly node: ResizeObservedNodeGetter
|
|
readonly onResize: () => void
|
|
|
|
private observer: ResizeObserver | null = null
|
|
private observedNode: HTMLElement | null = null
|
|
private rAF = 0
|
|
|
|
constructor(node: ResizeObservedNodeGetter, onResize: () => void) {
|
|
this.node = node
|
|
this.onResize = onResize
|
|
this.refresh()
|
|
}
|
|
|
|
refresh = () => {
|
|
if (!canObserveResize()) return
|
|
|
|
const nextNode = this.node() ?? null
|
|
if (nextNode === this.observedNode) return
|
|
|
|
this.disconnect()
|
|
if (!nextNode) return
|
|
|
|
this.observedNode = nextNode
|
|
this.observer = new ResizeObserver(() => {
|
|
if (typeof window.requestAnimationFrame === 'function') {
|
|
window.cancelAnimationFrame(this.rAF)
|
|
this.rAF = window.requestAnimationFrame(this.onResize)
|
|
return
|
|
}
|
|
|
|
this.onResize()
|
|
})
|
|
|
|
this.observer.observe(nextNode)
|
|
}
|
|
|
|
destroy = () => {
|
|
this.disconnect()
|
|
}
|
|
|
|
private disconnect() {
|
|
if (typeof window !== 'undefined' && typeof window.cancelAnimationFrame === 'function') {
|
|
window.cancelAnimationFrame(this.rAF)
|
|
}
|
|
this.rAF = 0
|
|
this.observer?.disconnect()
|
|
this.observer = null
|
|
this.observedNode = null
|
|
}
|
|
}
|