/** * Drag a bottom sheet down by its handle to dismiss it. `panel` is the * `.gsheet`, `handle` the grab area (its header), `close` the dismiss fn. * Past ~110px (or a quick flick) it closes; otherwise it springs back. */ export function dragToClose(panel, handle, close) { let y0 = 0; let dy = 0; let t0 = 0; let dragging = false; const start = (e) => { if (e.touches.length !== 1) return; y0 = e.touches[0].clientY; dy = 0; t0 = Date.now(); dragging = true; panel.style.transition = 'none'; }; const move = (e) => { if (!dragging) return; dy = e.touches[0].clientY - y0; // Rubber-band an upward pull; follow a downward one. const shown = dy < 0 ? dy * 0.25 : dy; panel.style.transform = `translateY(${shown}px)`; if (dy > 0) e.preventDefault(); }; const end = () => { if (!dragging) return; dragging = false; panel.style.transition = ''; panel.style.transform = ''; const flick = dy > 40 && Date.now() - t0 < 300; if (dy > 110 || flick) close(); }; handle.addEventListener('touchstart', start, { passive: true }); handle.addEventListener('touchmove', move, { passive: false }); handle.addEventListener('touchend', end, { passive: true }); handle.addEventListener('touchcancel', end, { passive: true }); }