Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
at main 85 lines 2.2 kB view raw
1import {type ForwardedRef, useEffect, useMemo, useRef} from 'react' 2import {type ScrollView} from 'react-native' 3import {Platform} from 'react-native' 4 5import {mergeRefs} from '#/lib/merge-refs' 6 7type Props<Scrollable extends ScrollView = ScrollView> = { 8 cursor?: string 9 outerRef?: ForwardedRef<Scrollable> 10} 11 12export function useDraggableScroll<Scrollable extends ScrollView = ScrollView>({ 13 outerRef, 14 cursor = 'grab', 15}: Props<Scrollable> = {}) { 16 const ref = useRef<Scrollable>(null) 17 18 useEffect(() => { 19 if (Platform.OS !== 'web' || !ref.current) { 20 return 21 } 22 const slider = ref.current as unknown as HTMLDivElement 23 let isDragging = false 24 let isMouseDown = false 25 let startX = 0 26 let scrollLeft = 0 27 28 const mouseDown = (e: MouseEvent) => { 29 isMouseDown = true 30 startX = e.pageX - slider.offsetLeft 31 scrollLeft = slider.scrollLeft 32 33 slider.style.cursor = cursor 34 } 35 36 const mouseUp = () => { 37 if (isDragging) { 38 slider.addEventListener('click', e => e.stopPropagation(), {once: true}) 39 } 40 41 isMouseDown = false 42 isDragging = false 43 slider.style.cursor = 'default' 44 } 45 46 const mouseMove = (e: MouseEvent) => { 47 if (!isMouseDown) { 48 return 49 } 50 51 // Require n pixels momement before start of drag (3 in this case ) 52 const x = e.pageX - slider.offsetLeft 53 if (Math.abs(x - startX) < 3) { 54 return 55 } 56 57 isDragging = true 58 e.preventDefault() 59 const walk = x - startX 60 slider.scrollLeft = scrollLeft - walk 61 62 if (slider.contains(document.activeElement)) 63 (document.activeElement as HTMLElement)?.blur?.() 64 } 65 66 slider.addEventListener('mousedown', mouseDown) 67 window.addEventListener('mouseup', mouseUp) 68 window.addEventListener('mousemove', mouseMove) 69 70 return () => { 71 slider.removeEventListener('mousedown', mouseDown) 72 window.removeEventListener('mouseup', mouseUp) 73 window.removeEventListener('mousemove', mouseMove) 74 } 75 }, [cursor]) 76 77 const refs = useMemo( 78 () => mergeRefs(outerRef ? [ref, outerRef] : [ref]), 79 [ref, outerRef], 80 ) 81 82 return { 83 refs, 84 } 85}