UNPKG

@blossom-carousel/web

Version:

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

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