@@ -66,6 +66,7 @@ interface SileoProps {
6666 refreshKey ?: string ;
6767 onMouseEnter ?: MouseEventHandler < HTMLButtonElement > ;
6868 onMouseLeave ?: MouseEventHandler < HTMLButtonElement > ;
69+ onDismiss ?: ( ) => void ;
6970}
7071
7172/* ---------------------------------- Icons --------------------------------- */
@@ -133,6 +134,7 @@ export const Sileo = memo(function Sileo({
133134 refreshKey,
134135 onMouseEnter,
135136 onMouseLeave,
137+ onDismiss,
136138} : SileoProps ) {
137139 const next : View = useMemo (
138140 ( ) => ( { title, description, state, icon, styles, button, fill } ) ,
@@ -428,10 +430,59 @@ export const Sileo = memo(function Sileo({
428430 [ open ] ,
429431 ) ;
430432
433+ /* -------------------------------- Swipe ----------------------------------- */
434+
435+ const SWIPE_DISMISS = 30 ;
436+ const SWIPE_MAX = 20 ;
437+ const buttonRef = useRef < HTMLButtonElement > ( null ) ;
438+ const pointerStartRef = useRef < number | null > ( null ) ;
439+ const onDismissRef = useRef ( onDismiss ) ;
440+ onDismissRef . current = onDismiss ;
441+
442+ useEffect ( ( ) => {
443+ const el = buttonRef . current ;
444+ if ( ! el ) return ;
445+
446+ const onMove = ( e : PointerEvent ) => {
447+ if ( pointerStartRef . current === null ) return ;
448+ const dy = e . clientY - pointerStartRef . current ;
449+ const sign = dy > 0 ? 1 : - 1 ;
450+ const clamped = Math . min ( Math . abs ( dy ) , SWIPE_MAX ) * sign ;
451+ el . style . transform = `translateY(${ clamped } px)` ;
452+ } ;
453+
454+ const onUp = ( e : PointerEvent ) => {
455+ if ( pointerStartRef . current === null ) return ;
456+ const dy = e . clientY - pointerStartRef . current ;
457+ pointerStartRef . current = null ;
458+ el . style . transform = "" ;
459+ if ( Math . abs ( dy ) > SWIPE_DISMISS ) {
460+ onDismissRef . current ?.( ) ;
461+ }
462+ } ;
463+
464+ el . addEventListener ( "pointermove" , onMove ) ;
465+ el . addEventListener ( "pointerup" , onUp ) ;
466+ return ( ) => {
467+ el . removeEventListener ( "pointermove" , onMove ) ;
468+ el . removeEventListener ( "pointerup" , onUp ) ;
469+ } ;
470+ } , [ ] ) ;
471+
472+ const handlePointerDown = useCallback (
473+ ( e : React . PointerEvent < HTMLButtonElement > ) => {
474+ if ( exiting || ! onDismiss ) return ;
475+ pointerStartRef . current = e . clientY ;
476+ e . currentTarget . setPointerCapture ( e . pointerId ) ;
477+ } ,
478+ [ exiting , onDismiss ] ,
479+ ) ;
480+
431481 /* --------------------------------- Render --------------------------------- */
432482
433483 return (
434484 < button
485+ ref = { buttonRef }
435486 type = "button"
436487 data-sileo-toast
437488 data-ready = { ready }
@@ -445,6 +496,7 @@ export const Sileo = memo(function Sileo({
445496 onMouseEnter = { handleEnter }
446497 onMouseLeave = { handleLeave }
447498 onTransitionEnd = { handleTransitionEnd }
499+ onPointerDown = { handlePointerDown }
448500 >
449501 < div data-sileo-canvas data-edge = { expand } >
450502 < svg
0 commit comments