UNPKG

@douxcode/vue-spring-bottom-sheet

Version:
418 lines (417 loc) 14.8 kB
import { ref as P, computed as _, defineComponent as Be, watch as q, onMounted as Ie, toRefs as Ee, nextTick as N, onUnmounted as _e, createBlock as te, openBlock as ae, Teleport as De, createElementVNode as ne, createVNode as $, unref as m, withCtx as E, createCommentVNode as ge, normalizeStyle as He, normalizeClass as oe, renderSlot as le } from "vue"; import { useMotionValue as me, animate as B, AnimatePresence as be, Motion as A } from "motion-v"; import { useVModel as Ve, useWindowSize as Fe, useElementBounding as Q, useScrollLock as ye } from "@vueuse/core"; import { useFocusTrap as Re } from "@vueuse/integrations/useFocusTrap"; function G(n, a) { const o = parseFloat(n); return a * o / 100; } function $e(n, a, o) { const t = P(0), s = _(() => n.value.map((p) => typeof p == "string" ? G(p, o.value) : p)), y = _(() => Math.min(...s.value)), r = _(() => Math.max(...s.value)), h = _(() => { const p = s.value.reduce( (g, M) => Math.abs(M - a.value) < Math.abs(g - a.value) ? M : g ); return s.value.indexOf(p); }); return { currentSnapPointIndex: t, flattenedSnapPoints: s, minSnapPoint: y, maxSnapPoint: r, closestSnapPointIndex: h }; } function Ae(n, a, o) { let t = (s) => n(s, ...a); return o === void 0 ? t : Object.assign(t, { lazy: o, lazyArgs: a }); } function We(n, a, o) { let t = n.length - a.length; if (t === 0) return n(...a); if (t === 1) return Ae(n, a, o); throw new Error("Wrong number of arguments"); } function je(n, { triggerAt: a = "end", minQuietPeriodMs: o, maxBurstDurationMs: t, minGapMs: s, reducer: y = ze }) { let r, h, p, g, M = () => { let i = p; i !== void 0 && (p = void 0, n(i), s !== void 0 && (h = setTimeout(D, s))); }, D = () => { clearTimeout(h), h = void 0, r === void 0 && M(); }, H = () => { clearTimeout(r), r = void 0, g = void 0, h === void 0 && M(); }; return { call: (...i) => { let c = r === void 0 && h === void 0; if ((a !== "start" || c) && (p = y(p, ...i)), !(r === void 0 && !c)) { if (o !== void 0 || t !== void 0 || s === void 0) { clearTimeout(r); let C = Date.now(); g ?? (g = C); let W = t === void 0 ? o ?? 0 : Math.min(o ?? t, t - (C - g)); r = setTimeout(H, W); } a !== "end" && c && M(); } }, cancel: () => { clearTimeout(r), r = void 0, g = void 0, clearTimeout(h), h = void 0, p = void 0; }, flush: () => { H(), D(); }, get isIdle() { return r === void 0 && h === void 0; } }; } var ze = () => ""; function b(...n) { return We(Le, n); } var Le = (n, { min: a, max: o }) => a !== void 0 && n < a ? a : o !== void 0 && n > o ? o : n; function qe(n, a, o) { return Math.max(a, Math.min(n, o)); } function Ne(n, a) { return Math.pow(n, a * 5); } function Se(n, a, o) { return a === 0 || Math.abs(a) === 1 / 0 ? Ne(n, o) : n * a * o / (a + o * n); } function ue(n, a, o, t = 0.15) { return t === 0 ? qe(n, a, o) : n < a ? -Se(a - n, o - a, t) + a : n > o ? +Se(n - o, o - a, t) + o : n; } const Qe = { "data-vsbs-container": "" }, Ge = /* @__PURE__ */ Be({ __name: "BottomSheet", props: { duration: { default: 250 }, snapPoints: {}, initialSnapPoint: {}, blocking: { type: Boolean, default: !0 }, canSwipeClose: { type: Boolean, default: !0 }, canBackdropClose: { type: Boolean, default: !0 }, expandOnContentDrag: { type: Boolean, default: !0 }, modelValue: { type: Boolean }, teleportTo: { default: "body" }, teleportDefer: { type: Boolean, default: !1 }, headerClass: {}, contentClass: {}, footerClass: {} }, emits: ["opened", "opening-started", "closed", "closing-started", "ready", "dragging-up", "dragging-down", "snapped", "instinctHeight", "update:modelValue"], setup(n, { expose: a, emit: o }) { const t = n, s = o, y = Ve(t, "modelValue", s, { passive: !0 }); q(y, (e) => { e && X(); }), Ie(() => { y.value && X(); }); const r = P(), h = P(null), p = P(null), g = P(null), M = P(null), D = P(null), H = P(null), i = P(t.expandOnContentDrag), { height: c } = Fe(), { height: C } = Q(r), { height: W } = Q(h), { height: se } = Q(D), { height: re } = Q(p), K = _({ get() { return b( Math.ceil(se.value + W.value + re.value), { max: c.value } ); }, set(e) { [W.value, se.value, re.value] = e; } }), l = P(0), v = P(0), k = me(0), S = me(0), { snapPoints: Pe } = Ee(t), d = _(() => Pe.value ?? [K.value]), { flattenedSnapPoints: U, currentSnapPointIndex: I, closestSnapPointIndex: V, minSnapPoint: O, maxSnapPoint: F } = $e(d, l, c); let w; const j = ye(document.body), z = ye(document.documentElement), Y = Re([r, H], { immediate: !1, fallbackFocus: () => { var e; return ((e = r.value) == null ? void 0 : e.$el) || document.body; } }); function ie(e) { i.value = !0, ve(e); } function ve(e) { i.value && e.preventDefault(); } const de = (e) => { e.key === "Escape" && L(); }, Ce = () => { t.canBackdropClose && L(); }; let J = !1; const X = async () => { if (J) return; y.value = !0, J = !0, s("opening-started"), t.blocking && (j.value = !0, z.value = !0), await N(); const e = r.value.$el; C.value = e.getBoundingClientRect().height; const u = e.querySelector("[data-vsbs-content]"), f = e.querySelector("[data-vsbs-header]"), T = e.querySelector("[data-vsbs-footer]"); if (K.value = [ f.getBoundingClientRect().height, u.getBoundingClientRect().height, T.getBoundingClientRect().height ], await N(), I.value = U.value.findIndex( (x) => x === O.value ), t.initialSnapPoint) { const x = t.initialSnapPoint; if (x < 0 || x >= d.value.length) { console.warn("Index out of bounds"); return; } let R; typeof d.value[x] == "number" ? R = b(d.value[x], { max: c.value }) : R = G(d.value[x], c.value), l.value = R; } else l.value = b(O.value, { max: c.value }); v.value = l.value, k.jump(l.value), S.jump(l.value), requestAnimationFrame(() => { w = B(k, l.value, { duration: t.duration / 1e3, ease: "easeInOut" }), w = B(S, 0, { duration: t.duration / 1e3, ease: "easeInOut", onComplete: () => { t.blocking && (s("opened"), Y.activate()); } }); }), window.addEventListener("keydown", de), J = !1; }; let Z = !1; const L = () => { Z || (y.value = !1, Z = !0, s("closing-started"), t.blocking && (j.value = !1, z.value = !1), window.removeEventListener("keydown", de), t.blocking && Y.deactivate(), setTimeout(() => { s("closed"), Z = !1; }, t.duration)); }, ce = (e) => { if (!d.value) return; if (e < 0 || e >= d.value.length) { console.warn("Index out of bounds"); return; } I.value = e; let u; typeof d.value[e] == "number" ? u = b(d.value[e], { max: c.value }) : u = G(d.value[e], c.value), l.value = u, w = B(k, l.value, { duration: t.duration / 1e3, ease: "easeInOut", onComplete: () => s("snapped", d.value.indexOf(d.value[e])) }); }; function fe(e) { e > 0 ? s("dragging-down") : e < 0 && s("dragging-up"); } const pe = () => { l.value = C.value, v.value = S.get(), k.jump(l.value), S.jump(v.value); }, he = async (e, u) => { await N(), r.value && (v.value <= 0 && (l.value -= u.delta.y), l.value <= O.value && (l.value = O.value, v.value += u.delta.y, S.set( t.canSwipeClose ? b(v.value, { min: 0 }) : b(ue(v.value, -C.value, 0, 0.5), { min: 0 }) )), k.set( b(ue(l.value, 0, F.value, 0.25), { min: 0, max: c.value }) ), fe(u.delta.y)); }, ee = () => { v.value = t.canSwipeClose ? [0, l.value].reduce( (u, f) => Math.abs(f - v.value) < Math.abs(u - v.value) ? f : u ) : 0, w = B(S, v.value, { duration: t.duration / 1e3, ease: "easeInOut" }), v.value === l.value && (v.value = 0, L()), I.value = V.value; let e; typeof d.value[V.value] == "number" ? e = b(d.value[V.value], { max: c.value }) : e = G( d.value[V.value], c.value ), l.value = e, w = B(k, l.value, { duration: t.duration / 1e3, ease: "easeInOut", onComplete: () => s( "snapped", d.value.indexOf(d.value[V.value]) ) }), w = B(S, 0, { duration: t.duration / 1e3, ease: "easeInOut" }); }, ke = (e, u) => { if (l.value = C.value, v.value = S.get(), w && w.stop(), !g.value) return; const f = g.value.scrollTop === 0, T = u.delta.y > 0, x = U.value.length === 1, R = 0.5 > Math.abs(l.value - F.value); if (x) { if (!t.expandOnContentDrag) { i.value = !1; return; } S.get() === 0 && f && T && (i.value = !0), S.get() === 0 && f && !T && (i.value = !1); } else { if (!t.expandOnContentDrag) { i.value = !1; return; } i.value = !0, R && (T && f && (i.value = !0), !T && f && (i.value = !1), f || (i.value = !1)); } }, we = async (e, u) => { if (await N(), !t.expandOnContentDrag) { i.value = !1; return; } if (!r.value) return; v.value === 0 && i.value && t.expandOnContentDrag && (l.value -= u.delta.y), l.value <= O.value && (l.value = O.value, i.value && t.expandOnContentDrag && (v.value += u.delta.y), v.value = b(v.value, { min: 0, max: O.value }), S.set( t.canSwipeClose ? b(v.value, { min: 0 }) : b(ue(v.value, -C.value, 0, 0.5), { min: 0 }) )), l.value > F.value && (l.value = F.value), l.value = b(l.value, { max: c.value }), U.value.length === 1 || l.value === F.value && (i.value = !1), k.set(l.value), fe(u.delta.y); }, Te = () => { t.blocking || (j.value = !0, z.value = !0); }, xe = () => { t.blocking || (j.value = !1, z.value = !1); }, Me = () => { if (!g.value) return; const e = g.value.scrollTop === 0; i.value = e; }, Oe = je((e) => ce(e), { minQuietPeriodMs: t.duration, reducer: (e, u) => u }); return q(d, (e, u) => { if (y.value === !1 || !e || !u) return; const f = e[I.value], T = u[I.value]; typeof f != "string" && typeof T != "string" && (l.value = b(f, { max: c.value }), f !== T && (w = B(k, l.value, { duration: t.duration / 1e3, ease: "easeInOut" }))); }), q(c, () => { Oe.call(I.value); }), q(K, (e) => { s("instinctHeight", e); }), _e(() => { Y.deactivate(); }), a({ open: X, close: L, snapToPoint: ce }), (e, u) => (ae(), te(De, { to: e.teleportTo, defer: e.teleportDefer }, [ ne("div", Qe, [ $(m(be), null, { default: E(() => [ m(y) && e.blocking ? (ae(), te(m(A), { key: 0, ref_key: "backdrop", ref: H, "data-vsbs-backdrop": "", onClick: u[0] || (u[0] = (f) => Ce()), transition: { ease: "easeInOut", duration: e.duration / 1e3 }, initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 } }, null, 8, ["transition"])) : ge("", !0) ]), _: 1 }), $(m(be), null, { default: E(() => [ m(y) ? (ae(), te(m(A), { key: 0, ref_key: "sheet", ref: r, exit: { y: "100%", height: m(C) }, initial: !1, style: He({ y: m(S), height: m(k) }), "data-vsbs-shadow": !e.blocking, "data-vsbs-sheet-show": m(y), "aria-modal": "true", "data-vsbs-sheet": "", tabindex: "-1", onTouchstart: Te, onTouchend: xe }, { default: E(() => [ $(m(A), { ref_key: "sheetHeader", ref: h, "data-vsbs-header": "", onPanStart: pe, onPan: he, onPanEnd: ee, onTouchmove: ie, class: oe(e.headerClass) }, { default: E(() => [ le(e.$slots, "header", {}, void 0, !0) ]), _: 3 }, 8, ["class"]), ne("div", { ref_key: "sheetScroll", ref: g, "data-vsbs-scroll": "", onScrollend: Me }, [ $(m(A), { ref_key: "sheetContentWrapper", ref: M, "data-vsbs-content-wrapper": "", onPanStart: ke, onPan: we, onPanEnd: ee, onTouchmove: ve }, { default: E(() => [ ne("div", { ref_key: "sheetContent", ref: D, "data-vsbs-content": "", class: oe(e.contentClass) }, [ le(e.$slots, "default", {}, void 0, !0) ], 2) ]), _: 3 }, 512) ], 544), $(m(A), { ref_key: "sheetFooter", ref: p, "data-vsbs-footer": "", onPanStart: pe, onPan: he, onPanEnd: ee, onTouchmove: ie, class: oe(e.footerClass) }, { default: E(() => [ le(e.$slots, "footer", {}, void 0, !0) ]), _: 3 }, 8, ["class"]) ]), _: 3 }, 8, ["exit", "style", "data-vsbs-shadow", "data-vsbs-sheet-show"])) : ge("", !0) ]), _: 3 }) ]) ], 8, ["to", "defer"])); } }), Ke = (n, a) => { const o = n.__vccOpts || n; for (const [t, s] of a) o[t] = s; return o; }, Ze = /* @__PURE__ */ Ke(Ge, [["__scopeId", "data-v-3c41a73f"]]); export { Ze as default };