Skip to content

Commit

Permalink
swipe down to dismiss alert
Browse files Browse the repository at this point in the history
  • Loading branch information
yangchristina committed Jan 19, 2025
1 parent 33d0760 commit 6edd5ab
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/components/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const Alert: FC = () => {
showXOnHover
onClose={alert.showCloseLink ? onClose : undefined}
calculatedHeight={popupRef.current?.getBoundingClientRect().height || 50}
swipeDownToDismiss
>
<div
data-testid='alert-content'
Expand Down
3 changes: 3 additions & 0 deletions src/components/PopupBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type PopupBaseProps = PropsWithChildren<
cssRaw?: SystemStyleObject
circledCloseButton?: boolean
showXOnHover?: boolean
swipeDownToDismiss?: boolean
} & Omit<React.HTMLAttributes<HTMLDivElement>, 'className'>
>

Expand All @@ -44,6 +45,7 @@ const PopupBase = React.forwardRef<HTMLDivElement, PopupBaseProps>(
calculatedHeight,
circledCloseButton,
showXOnHover,
swipeDownToDismiss,
...props
},
ref,
Expand All @@ -61,6 +63,7 @@ const PopupBase = React.forwardRef<HTMLDivElement, PopupBaseProps>(
onDismissEnd: () => {
dispatch(alert(null))
},
swipeDown: swipeDownToDismiss,
})

const combinedRefs = useCombinedRefs(isTouch ? [useSwipeToDismissProps.ref, ref] : [ref])
Expand Down
32 changes: 23 additions & 9 deletions src/hooks/useSwipeToDismiss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const defaultOptions = {
dx: 0,
snapbackDuration: 0.1,
snapbackEasing: 'ease-out',
swipeDown: false,
}

/** Custom hook to manage swipe to dismiss alerts. */
Expand All @@ -28,10 +29,13 @@ const useSwipeToDismiss = (

// easing function to animate the element back into place after releasing
snapbackEasing?: string

// whether to swipe down to dismiss (true) or swipe up (false)
swipeDown?: boolean
} = {},
) => {
// initialize default options
const { dismissThreshold, dx, onDismiss, onDismissEnd, snapbackDuration, snapbackEasing } = {
const { dismissThreshold, dx, onDismiss, onDismissEnd, snapbackDuration, snapbackEasing, swipeDown } = {
...defaultOptions,
...options,
}
Expand Down Expand Up @@ -74,12 +78,16 @@ const useSwipeToDismiss = (
// check for dismiss threshold
// if specified as a percentage of height, use percentage of element height
const isPercentageOfHeight = typeof dismissThreshold === 'string' && dismissThreshold.endsWith('%')
const dismissThresholdPx = isPercentageOfHeight
? (-parseFloat(dismissThreshold as string) * height) / 100
: -parseFloat(dismissThreshold as string)
const thresholdValue = isPercentageOfHeight
? (parseFloat(dismissThreshold as string) * height) / 100
: parseFloat(dismissThreshold as string)

// Check threshold based on swipe direction
const dismissThresholdPx = swipeDown ? thresholdValue : -thresholdValue
const shouldDismiss = swipeDown ? dy > dismissThresholdPx : dy < -dismissThresholdPx

if (dy < dismissThresholdPx) {
setDY(-height * 2)
if (shouldDismiss) {
setDY(swipeDown ? height * 2 : -height * 2)
onDismiss?.()
setTimeout(() => {
onDismissEnd?.()
Expand All @@ -98,11 +106,17 @@ const useSwipeToDismiss = (
const y = e.touches?.[0].pageY
const dy = y - y0

// resist dragging down by taking the square root of positive dy
const dyResistant = dy < 0 ? dy : Math.sqrt(dy)
// Apply resistance in the non-dismissal direction
const dyResistant = swipeDown
? dy < 0
? Math.sqrt(-dy) * -1
: dy // resist upward motion when swipeDown
: dy > 0
? Math.sqrt(dy)
: dy // resist dragging down by taking square root of positive dy
setDY(dyResistant)
},
[y0],
[y0, swipeDown],
)

return {
Expand Down

0 comments on commit 6edd5ab

Please sign in to comment.