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 } }