}
diff --git a/src/features/payments/flows/contribute-pot/components/ContributorsDrawer.tsx b/src/features/payments/flows/contribute-pot/components/ContributorsDrawer.tsx
index 8aaf5a3736..5525a22e2d 100644
--- a/src/features/payments/flows/contribute-pot/components/ContributorsDrawer.tsx
+++ b/src/features/payments/flows/contribute-pot/components/ContributorsDrawer.tsx
@@ -59,7 +59,7 @@ export function ContributorsDrawer({ contributors }: ContributorsDrawerProps) {
{t('contributors.title', { count: contributors.length })}
-
+
{contributorCards.map((contributor, index) => (
{
expect(invalidateQueries).not.toHaveBeenCalled()
expect(impactHaptic).not.toHaveBeenCalled()
})
+
+ it('ignores touches that start on an open vaul drawer', () => {
+ const invalidateQueries = jest.spyOn(queryClient, 'invalidateQueries')
+ renderHook(() => usePullToRefresh(), { wrapper })
+
+ const sheet = document.createElement('div')
+ sheet.setAttribute('data-vaul-drawer', '')
+ const inner = document.createElement('button')
+ sheet.appendChild(inner)
+ document.body.appendChild(sheet)
+
+ const start = new Event('touchstart', { bubbles: true })
+ Object.defineProperty(start, 'touches', { value: [{ clientX: 0, clientY: 0 }] })
+ act(() => {
+ inner.dispatchEvent(start)
+ })
+
+ // a full downward drag on the sheet must not move the indicator
+ touch('touchmove', 200)
+ touch('touchend', 200)
+
+ expect(indicator()?.style.opacity).toBe('0')
+ expect(invalidateQueries).not.toHaveBeenCalled()
+ expect(impactHaptic).not.toHaveBeenCalled()
+ sheet.remove()
+ })
})
diff --git a/src/hooks/usePullToRefresh.ts b/src/hooks/usePullToRefresh.ts
index 0bf0d2d7df..45d70c94bc 100644
--- a/src/hooks/usePullToRefresh.ts
+++ b/src/hooks/usePullToRefresh.ts
@@ -168,6 +168,11 @@ export const usePullToRefresh = (options: UsePullToRefreshOptions = {}) => {
const onTouchStart = (e: TouchEvent) => {
if (refreshing || e.touches.length !== 1) return
+ // a touch on an open vaul sheet (or its overlay) is a drawer
+ // gesture, never a pull — without this, dragging the sheet moved
+ // the page behind it (the listeners here are on document)
+ const target = e.target as Element | null
+ if (target?.closest?.('[data-vaul-drawer],[data-vaul-overlay]')) return
const allowed = shouldPullToRefreshRef.current ? shouldPullToRefreshRef.current() : window.scrollY === 0
if (!allowed) return
// a new pull can start inside the retract window — put the arrow back