UNPKG

@blossom-carousel/web

Version:

A native-scroll-first carousel component for the web.

283 lines (282 loc) 9.42 kB
var vt = Object.defineProperty; var mt = (n, r, h) => r in n ? vt(n, r, { enumerable: !0, configurable: !0, writable: !0, value: h }) : n[r] = h; var ot = (n, r, h) => (mt(n, typeof r != "symbol" ? r + "" : r, h), h); const gt = (n, r) => { let h = !0; const v = { x: 0, y: 0 }, c = { x: 0, y: 0 }, f = { x: 0, y: 0 }, k = new Proxy( { x: 0, y: 0 }, { set(t, e, l) { return t[e] === l || (t[e] = l, (t.x >= 10 || t.y >= 10) && L(!0)), !0; } } ), i = new Proxy( { x: !1, y: !1 }, { set(t, e, l) { return t[e] === l || (t[e] = l, t.x || t.y ? (n.setAttribute("has-overflow", "true"), n.addEventListener("pointerdown", K), n.addEventListener("wheel", Z, { passive: !1 })) : (n.removeAttribute("has-overflow"), n.removeEventListener("pointerdown", K), n.removeEventListener("wheel", Z))), !0; } } ); let b = 300, m = null, y = !1, x = 300, d = 300, $ = 300, z = 300; const S = { left: 0, right: 0 }, R = { left: 0, right: 0 }; let W = [], P = null, V = null, B = null, U = !1, X; function rt() { n == null || n.setAttribute("blossom-carousel", "true"), P = (n == null ? void 0 : n.querySelectorAll("a[href]")) || null, P == null || P.forEach((l) => { l.addEventListener("click", j); }), window.addEventListener("keydown", _), n.addEventListener("scroll", J), V = new ResizeObserver(G), V.observe(n), B = new MutationObserver(it), B.observe(n, { attributes: !1, childList: !0, subtree: !1 }); const t = window.matchMedia( "(hover: hover) and (pointer: fine)" ).matches, { scrollSnapType: e } = window.getComputedStyle(n); U = e !== "none", n.style.setProperty("--snap-type", e), t && (n.style["scroll-snap-type"] = "none"), n.setAttribute("has-repeat", r != null && r.repeat ? "true" : "false"), X = ht((l) => { (l === n || n.contains(l)) && L(!1); }); } function st() { n.removeAttribute("blossom-carousel"), V == null || V.disconnect(), B == null || B.disconnect(), m && cancelAnimationFrame(m), window.removeEventListener("keydown", _), n.removeEventListener("scroll", J), P == null || P.forEach((t) => { t.removeEventListener("click", j); }), X == null || X(); } function j(t) { k.x > 10 && t.preventDefault(); } function G() { if (!n) return; const t = "ontouchmove" in window; x = n.scrollWidth, d = n.clientWidth, $ = n.scrollHeight, z = n.clientHeight; const e = window.getComputedStyle(n); i.x = !t && x > d && ["auto", "scroll"].includes(e.getPropertyValue("overflow-x")), i.y = !t && $ > z && ["auto", "scroll"].includes(e.getPropertyValue("overflow-y")), S.right = parseInt(e.paddingRight) || 0, S.left = parseInt(e.paddingLeft) || 0, R.left = parseInt(e.scrollPaddingLeft) || 0, R.right = parseInt(e.scrollPaddingRight) || 0, b = x - d - 4, W = U ? ct(n) : [], r != null && r.repeat && Y(null, null); } function it() { G(); } function ct(t) { let e = [], l = 0; const u = (s) => { if (l++, l > 100) return; const w = window.getComputedStyle(s).scrollSnapAlign; if (w !== "none") { e.push({ align: w, el: s }); return; } const I = s.children; if (I.length !== 0) for (let a of I) u(a); }; u(t); const H = t.getBoundingClientRect(); let p = e.map(({ el: s, align: w }, I) => { const a = s.getBoundingClientRect(), C = s.clientWidth, O = a.left - H.left + t.scrollLeft; switch (w) { case "start": return O - R.left; case "end": return O + C - d + R.right; case "center": return O + C * 0.5 - d / 2; default: return null; } }); return p = p.filter((s) => s !== null).reduce((s, w) => (s[s.length - 1] !== w && s.push(w), s), []), p; } function J() { if (r != null && r.repeat) { Y(null, null); return; } if (!(y || !n)) { if (n.scrollLeft < 0) { const t = n.scrollLeft * -1; q(t); } else if (n.scrollLeft > x - d) { const t = n.scrollLeft * -1 + x - d; q(t); } } } const o = { x: 0, y: 0 }; function K(t) { n && (i.x && (o.x = n.scrollLeft, v.x = t.clientX, f.x = 0), i.y && (o.y = n.scrollTop, v.y = t.clientY, f.y = 0), k.x = 0, y = !0, window.addEventListener("pointermove", N), window.addEventListener("pointerup", Q)); } function N(t) { if (t.preventDefault(), i.x) { const e = v.x - t.clientX; c.x += e, f.x += e, v.x = t.clientX, k.x += Math.abs(e); } if (i.y) { const e = v.y - t.clientY; c.y += e, f.y += e, v.y = t.clientY, k.y += Math.abs(e); } } function Q() { window.removeEventListener("pointermove", N), window.removeEventListener("pointerup", Q), y = !1, !(k.x <= 10) && (i.x && (f.x *= 2), i.y && (f.y *= 2), ut(), xt()); } function Z(t) { if (Math.abs(t.deltaX) > Math.abs(t.deltaY)) { if (L(!1), y || !n) return; i.x && (o.x = n.scrollLeft), i.y && (o.y = n.scrollTop); } } function _(t) { ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(t.key) && L(!1); } function ut() { const t = (et( yt({ axis: "x" }), 0, x - d ) - c.x) * (1 - g) * (1 / g); f.x = t; } function Y(t, e) { if (!n) return; const l = e ?? n.scrollLeft, u = S.left - l, H = l - (x - d - S.right), p = Array.from(n.children); let s = 0; for (let a = p.length - 1; a >= p.length / 2; a--) { const C = s > u ? 0 : -(x - d); s += p[a].clientWidth, p[a].style.translate = `${C}px 0`; } let w = 0; for (let a = 0; a < p.length / 2; a++) { const C = w > H ? 0 : x - d; w += p[a].clientWidth, p[a].style.translate = `${C}px 0`; } if (y) return; const I = l > b ? 4 : l < 4 ? b : null; I && (M = !0, n.scrollTo({ left: I, behavior: "instant" })); } const g = 0.72, D = 0.12; let tt = !1; function L(t) { n && (t && !tt ? (F = performance.now(), i.x && (c.x = n.scrollLeft), i.y && (c.y = n.scrollTop), m || (m = requestAnimationFrame(nt))) : t || (m && cancelAnimationFrame(m), m = null), tt = t, h = !t, n.setAttribute("has-snap", h ? "true" : "false")); } let E = 0, F = 0; function nt(t) { m = requestAnimationFrame(nt), E = t - F, n && (i.x && (f.x *= g, y ? o.x = T(o.x, c.x, g, E) : (c.x += f.x, o.x = T(o.x, c.x, D, E))), i.y && (f.y *= g, y ? o.y = T(o.y, c.y, g, E) : (c.y += f.y, o.y = T(o.y, c.y, D, E))), r != null && r.repeat && (o.x > b && (o.x = c.x = 4), o.x < 4 && (o.x = c.x = b)), M = !0, n.scrollTo({ left: o.x, top: o.y, behavior: "instant" }), r != null && r.repeat ? Y(null, o.x) : at(lt(o.x, 2)), F = t); } let A = 0; function at(t) { if (!n) return; const e = x - d; let l = 0; if (t < 0 ? l = y ? t * -0.2 : 0 : t > e && (l = y ? (t - e) * -0.2 : 0), A = T( A, l, y ? 0.8 : D, E ), Math.abs(A) > 0.01) { if (q(A).defaultPrevented) return; n.style.transform = `translateX(${lt(A, 3)}px)`; return; } n.style.transform = "", A = 0; } function q(t) { const e = new CustomEvent("overscroll", { bubbles: !0, cancelable: !0, detail: { left: t } }); return n == null || n.dispatchEvent(e), e; } let M = !1; const ft = n.scrollTo.bind(n); n.scrollTo = function(t) { M === !0 || L(!1), M = !1, ft(t); }; const dt = n.scrollBy.bind(n); n.scrollBy = function(t) { M === !0 || L(!1), M = !1, dt(t); }; function ht(t) { const e = [], l = Element.prototype.scrollIntoView; return l && (Element.prototype.scrollIntoView = function(u) { return t(this, "scrollIntoView", [u]), l.call(this, u); }, e.push(() => { Element.prototype.scrollIntoView = l; })), () => e.forEach((u) => u()); } function pt({ axis: t = "x" }) { return c[t] + f[t] / (1 - g); } function yt({ axis: t = "x" }) { const e = pt({ axis: t }); return W.length ? W.reduce( (l, u) => Math.abs(u - e) < Math.abs(l - e) ? u : l ) : et(e, 0, b); } function xt() { const t = (e) => { e.preventDefault(), e.stopPropagation(), window.removeEventListener("click", t, !0); }; window.addEventListener("click", t, !0); } function wt(t, e, l) { return (1 - l) * t + l * e; } function T(t, e, l, u) { return wt(t, e, 1 - Math.exp(Math.log(1 - l) * (u / 16.666666666666668))); } function et(t, e, l) { return t < e ? e : t > l ? l : t; } function lt(t, e = 0) { const l = Math.pow(10, e); return Math.round(t * l) / l; } return { snap: h, hasOverflow: i, init: rt, destroy: st }; }; class bt extends HTMLElement { constructor() { super(); ot(this, "carouselInstance"); const h = this.attachShadow({ mode: "open" }); this.setAttribute("blossom-carousel", "true"); const v = document.createElement("slot"); h.appendChild(v); } connectedCallback() { this.carouselInstance = gt(this, { repeat: !1 // this.hasAttribute("repeat"), }), this.carouselInstance.init(); } disconnectedCallback() { this.carouselInstance.destroy(); } } customElements.define("blossom-carousel", bt); export { bt as BlossomCarousel };