@shopify/shop-minis-react
Version:
React component library for Shopify Shop Minis with Tailwind CSS v4 support (source-only, requires TypeScript)
150 lines (149 loc) • 4.05 kB
JavaScript
import { useState as M, useRef as P, useCallback as o, useEffect as O } from "react";
const _ = 200, H = 400;
function U({
onRefresh: g,
threshold: R = _,
indicatorThreshold: p = 0,
enabled: E = !1
}) {
const [Y, u] = M({
isPulling: !1,
pullDistance: 0,
canRefresh: !1
}), i = P(0), F = P(0), f = P(null), e = P(null), a = P(!1), A = o(
(n) => {
!E || !f.current || a.current || (e.current && (cancelAnimationFrame(e.current), e.current = null), u((t) => {
const r = f.current;
if (!r) return t;
if (r.scrollTop <= 0) {
const h = n.touches[0];
i.current = h.clientY;
} else
return i.current = 0, {
...t,
isPulling: !1,
pullDistance: 0,
canRefresh: !1
};
return t;
}));
},
[E]
), S = o(
(n, t) => {
!E || !f.current || i.current === 0 || u((r) => {
if (a.current)
return r;
const c = f.current;
if (!c) return r;
const h = c.scrollTop <= 0;
F.current = n;
const s = F.current - i.current;
if (h && s > 0) {
const l = s, m = l >= p;
if (m && t && t(), m || r.isPulling) {
const D = l > R ? R + (l - R) * 0.5 : l;
return {
...r,
isPulling: m,
pullDistance: D,
canRefresh: l >= R
};
}
return r;
} else if (r.isPulling)
return {
...r,
isPulling: !1,
pullDistance: 0,
canRefresh: !1
};
return r;
});
},
[R, p, E]
), L = o(
(n) => {
if (a.current) return;
const t = n.touches[0];
t && i.current !== 0 && S(t.clientY, () => n.preventDefault());
},
[S]
), v = o(() => {
a.current = !1;
}, []), w = o((n) => {
e.current && (cancelAnimationFrame(e.current), e.current = null);
let t = n;
if (t === void 0 && u((s) => (t = s.pullDistance, s)), !t || t <= 0) {
u((s) => ({
...s,
pullDistance: 0,
canRefresh: !1,
isPulling: !1
}));
return;
}
const r = H, c = Date.now(), h = () => {
const s = Date.now() - c, T = Math.min(s / r, 1), l = 1 - (1 - T) ** 3, m = t * (1 - l);
u((D) => ({
...D,
pullDistance: m,
canRefresh: T < 1 ? D.canRefresh : !1
})), T < 1 ? e.current = requestAnimationFrame(h) : (e.current = null, u((D) => ({
...D,
pullDistance: 0,
canRefresh: !1,
isPulling: !1
})));
};
e.current = requestAnimationFrame(h);
}, []), d = o(async () => {
if (a.current) {
i.current = 0;
return;
}
i.current = 0, e.current && (cancelAnimationFrame(e.current), e.current = null);
let n = !1, t = 0;
const r = a.current;
if (u((c) => (n = c.canRefresh && !r, t = c.pullDistance, {
...c,
isPulling: !1
})), t <= 0) {
u((c) => ({
...c,
pullDistance: 0,
canRefresh: !1
}));
return;
}
if (n && g) {
a.current = !0;
try {
await g();
} catch (c) {
console.error("Pull to refresh failed:", c);
}
v();
}
w(t);
}, [g, w, v]), I = o(
(n) => {
if (n)
return f.current = n, n.addEventListener("touchstart", A, { passive: !1 }), n.addEventListener("touchmove", L, { passive: !1 }), n.addEventListener("touchend", d), n.addEventListener("touchcancel", d), () => {
n.removeEventListener("touchstart", A), n.removeEventListener("touchmove", L), n.removeEventListener("touchend", d), n.removeEventListener("touchcancel", d);
};
},
[A, L, d]
);
return O(() => () => {
e.current && (cancelAnimationFrame(e.current), e.current = null);
}, []), {
state: Y,
bindToElement: I,
containerRef: f
};
}
export {
U as usePullToRefresh
};
//# sourceMappingURL=usePullToRefresh.js.map