UNPKG

joicomponents

Version:

Design patterns to build native web components

97 lines (83 loc) 2.61 kB
<script> function postConstructionCallback(cb) { if (document.readyState === "loading") { window.addEventListener("DOMContentLoaded", cb); } else { Promise.resolve().then(function () { Promise.resolve().then(cb) }); } } const defaultSizes = { S: 0, M: 400, L: 800 }; class SmallMediumLarge extends HTMLElement { constructor() { super(); this.__size = undefined; this._sizeSettings = defaultSizes; this._viewportObserver = this.viewportChanged.bind(this); postConstructionCallback(this._viewportObserver); /*event listener*/ this._onScrollListener = this.onScroll.bind(this); } connectedCallback() { window.addEventListener("resize", this._viewportObserver); } disconnectedCallback() { window.removeEventListener("resize", this._viewportObserver); } static get observedAttributes() { return ["_size", "size-settings"]; } attributeChangedCallback(name, oldValue, newValue) { if (name === "_size" && newValue !== this.__size) this.setAttribute("_size", this.__size); if (name === "size-settings") this._sizeSettings = newValue ? JSON.parse(newValue) : defaultSizes; } viewportChanged() { const sorted = Object .entries(this._sizeSettings) .sort(([aKey, aValue], [bKey, bValue]) => aValue <= bValue) .filter(([key, value]) => value <= window.innerWidth); const newSize = sorted.length ? sorted[sorted.length - 1][0] : null; if (this.__size === newSize) return; this.__size = newSize; this.__size === null ? this.removeAttribute("_size") : this.setAttribute("_size", this.__size); /* setup listeners */ if (this.__size === "S") window.addEventListener("scroll", this._onScrollListener); else window.removeEventListener("scroll", this._onScrollListener); } onScroll() { console.log(this.id, "only observes scroll when its _size is small"); } } customElements.define("small-medium-large", SmallMediumLarge); </script> <style> small-medium-large { display: block; height: 60%; } small-medium-large[_size="S"] { border-bottom: 5px solid red; } small-medium-large[_size="M"] { border-right: 5px solid orange; } small-medium-large[_size="L"] { border-top: 5px solid green; } </style> <small-medium-large id="one"> default sizes </small-medium-large> <small-medium-large id="two" size-settings='{"S": 0, "M": 200, "L": 400}'> custom sizes </small-medium-large>