UNPKG

shareshade

Version:

A zero-dependency JavaScript library that overlays a shared gradient background across multiple elements.

103 lines (86 loc) 3.16 kB
export default class ShareShade { constructor(options) { if (!options || !options.selector || !options.background) { throw new Error('ShareShade requires "selector" and "background" options.'); } this.selector = options.selector; this.background = options.background; this.opacity = options.opacity ?? 1; this.className = 'shareshade-overlay'; this._resizeHandler = () => this.update(); window.addEventListener('resize', this._resizeHandler); this.injectStyle(); this.update(); } injectStyle() { if (document.getElementById('__shareshade-style')) return; const style = document.createElement('style'); style.id = '__shareshade-style'; style.textContent = ` .${this.className} { position: absolute; z-index: -1; pointer-events: none; background-repeat: no-repeat; background-size: cover; background-position: center; border-radius: inherit; } `; document.head.appendChild(style); } update() { const elements = document.querySelectorAll(this.selector); if (!elements.length) return; let minTop = Infinity; let minLeft = Infinity; let maxRight = -Infinity; let maxBottom = -Infinity; elements.forEach(el => { const rect = el.getBoundingClientRect(); const top = rect.top + window.scrollY; const left = rect.left + window.scrollX; const right = left + rect.width; const bottom = top + rect.height; minTop = Math.min(minTop, top); minLeft = Math.min(minLeft, left); maxRight = Math.max(maxRight, right); maxBottom = Math.max(maxBottom, bottom); }); const width = maxRight - minLeft; const height = maxBottom - minTop; elements.forEach(el => { const rect = el.getBoundingClientRect(); const top = rect.top + window.scrollY; const left = rect.left + window.scrollX; const overlay = document.createElement('div'); overlay.className = this.className; overlay.style.backgroundImage = this.background.startsWith('url') ? `url("${this.background}")` : this.background; overlay.style.backgroundSize = `${width}px ${height}px`; overlay.style.backgroundPosition = `-${left - minLeft}px -${top - minTop}px`; overlay.style.opacity = this.opacity; overlay.style.position = 'absolute'; overlay.style.top = '0'; overlay.style.left = '0'; overlay.style.right = '0'; overlay.style.bottom = '0'; overlay.style.pointerEvents = 'none'; overlay.style.zIndex = '-1'; const computed = getComputedStyle(el); if (computed.position === 'static') el.style.position = 'relative'; const existing = el.querySelector(`.${this.className}`); if (existing) existing.remove(); el.appendChild(overlay); }); } destroy() { window.removeEventListener('resize', this._resizeHandler); const elements = document.querySelectorAll(this.selector); elements.forEach(el => { const overlay = el.querySelector(`.${this.className}`); if (overlay) overlay.remove(); }); } }