class IntersectionSentinel extends HTMLElement { observer: IntersectionObserver | null constructor() { super() this.observer = null } static get observedAttributes() { return ["root", "root-margin", "threshold", "disabled"] } connectedCallback() { this.subscribe() } disconnectedCallback() { this.unsubscribe() } attributeChangedCallback(name: string, _: string, newValue: string) { console.log(name, newValue) if (name === "disabled") { if (newValue === "true") { this.unsubscribe() } else { this.subscribe() } } } subscribe() { if (this.observer == null) { const rootAttribute = this.getAttribute("root") const root = rootAttribute != null ? document.getElementById(rootAttribute) : null const rootMargin = this.getAttribute("root-margin") ?? "0px" const threshold = parseFloat(this.getAttribute("threshold") ?? "0.5") this.observer = new IntersectionObserver( (entries) => { console.log("IntersectionSentinel intersection", entries) entries.forEach((entry) => { if (entry.isIntersecting) { this.dispatchEvent( new CustomEvent("intersection", { detail: entry, }) ) } }) }, { root, rootMargin, threshold, } ) this.observer.observe(this) } } unsubscribe() { if (this.observer != null) { this.observer.disconnect() this.observer = null } } } customElements.define("intersection-sentinel", IntersectionSentinel)