From bccac386a746ea934f0328c6a9ff0be06dd72aeb Mon Sep 17 00:00:00 2001 From: Philip Peterson <1326208+philip-peterson@users.noreply.github.com> Date: Wed, 3 Jun 2026 01:54:29 -0700 Subject: [PATCH] Fix carousel: swipe snap, disabled state, pointer events, resize - Snap clamps after rounding so it can't overshoot max on narrow viewports - atEnd computed inline each render from live measureMax() - forceUpdate on resize guarantees re-render even when left doesn't change - Track gets explicit width (TOTAL_W) so gap areas are hit-testable - Resize handler always calls setLeft (clamp or no-op) to keep state consistent Co-Authored-By: Claude Sonnet 4.6 --- .../js/components/rpt-testimonials.js | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/web/modules/custom/riverside_pt/js/components/rpt-testimonials.js b/web/modules/custom/riverside_pt/js/components/rpt-testimonials.js index e69dfc5..76e3856 100644 --- a/web/modules/custom/riverside_pt/js/components/rpt-testimonials.js +++ b/web/modules/custom/riverside_pt/js/components/rpt-testimonials.js @@ -1,5 +1,5 @@ import { h, render } from "https://esm.sh/preact@10"; -import { useState, useEffect, useRef } from "https://esm.sh/preact@10/hooks"; +import { useState, useEffect, useReducer, useRef } from "https://esm.sh/preact@10/hooks"; import { html } from "https://esm.sh/htm@3/preact"; const TESTIMONIALS = [ @@ -39,6 +39,7 @@ function Testimonials() { const containerRef = useRef(null); const trackRef = useRef(null); const [left, setLeft] = useState(0); + const [, forceUpdate] = useReducer(function (n) { return n + 1; }, 0); function measureMax() { if (!containerRef.current) return 0; @@ -63,9 +64,8 @@ function Testimonials() { clearTimeout(timer); timer = setTimeout(function () { var max = measureMax(); - if (-leftRef.current > max) { - setLeft(-max); - } + setLeft(function (l) { return Math.min(0, Math.max(-max, l)); }); + forceUpdate(); }, 150); } window.addEventListener("resize", onResize); @@ -75,19 +75,35 @@ function Testimonials() { }; }, []); - var touchStartX = useRef(0); + var drag = useRef(null); // null when idle, {x, left} when dragging - var onTouchStart = function (e) { - touchStartX.current = e.touches[0].clientX; + var onPointerDown = function (e) { + drag.current = { x: e.clientX, left: leftRef.current }; + trackRef.current.style.transition = "none"; + e.currentTarget.setPointerCapture(e.pointerId); }; - var onTouchEnd = function (e) { - var delta = e.changedTouches[0].clientX - touchStartX.current; - if (delta < -50) next(); - else if (delta > 50) prev(); + var onPointerMove = function (e) { + if (!drag.current) return; + var delta = e.clientX - drag.current.x; + var max = measureMax(); + setLeft(Math.min(0, Math.max(-max, drag.current.left + delta))); + }; + + var onPointerUp = function (e) { + if (!drag.current) return; + drag.current = null; + trackRef.current.style.transition = "left 0.5s ease"; + var max = measureMax(); + setLeft(function (l) { + var clamped = Math.min(0, Math.max(-max, l)); + var snapped = -Math.round(-clamped / STEP) * STEP; + return Math.max(-max, snapped); + }); }; var atStart = left >= 0; + var atEnd = !!containerRef.current && left <= -measureMax(); return html`
@@ -108,7 +124,7 @@ function Testimonials() { >${String.fromCharCode(8592)} @@ -117,9 +133,10 @@ function Testimonials() {
${TESTIMONIALS.map(function (t, i) { return html`