(ref: RefObject<Element | null>)
| 25 | } |
| 26 | |
| 27 | export function useAutoScroll(ref: RefObject<Element | null>): AutoScrollAria { |
| 28 | let scrollableRef = useRef<Element>(null); |
| 29 | let scrollableX = useRef(true); |
| 30 | let scrollableY = useRef(true); |
| 31 | useEffect(() => { |
| 32 | if (ref.current) { |
| 33 | scrollableRef.current = isScrollable(ref.current) |
| 34 | ? ref.current |
| 35 | : getScrollParent(ref.current); |
| 36 | let style = window.getComputedStyle(scrollableRef.current); |
| 37 | scrollableX.current = /(auto|scroll)/.test(style.overflowX); |
| 38 | scrollableY.current = /(auto|scroll)/.test(style.overflowY); |
| 39 | } |
| 40 | }, [ref]); |
| 41 | |
| 42 | let state = useRef<{ |
| 43 | timer: ReturnType<typeof requestAnimationFrame> | undefined; |
| 44 | dx: number; |
| 45 | dy: number; |
| 46 | }>({ |
| 47 | timer: undefined, |
| 48 | dx: 0, |
| 49 | dy: 0 |
| 50 | }).current; |
| 51 | |
| 52 | useEffect(() => { |
| 53 | return () => { |
| 54 | if (state.timer) { |
| 55 | cancelAnimationFrame(state.timer); |
| 56 | state.timer = undefined; |
| 57 | } |
| 58 | }; |
| 59 | // state will become a new object, so it's ok to use in the dependency array for unmount |
| 60 | }, [state]); |
| 61 | |
| 62 | let scroll = useCallback(() => { |
| 63 | if (scrollableX.current && scrollableRef.current) { |
| 64 | scrollableRef.current.scrollLeft += state.dx; |
| 65 | } |
| 66 | if (scrollableY.current && scrollableRef.current) { |
| 67 | scrollableRef.current.scrollTop += state.dy; |
| 68 | } |
| 69 | |
| 70 | if (state.timer) { |
| 71 | state.timer = requestAnimationFrame(scroll); |
| 72 | } |
| 73 | }, [scrollableRef, state]); |
| 74 | |
| 75 | return { |
| 76 | move(x, y) { |
| 77 | // Most browsers auto scroll natively, but WebKit on macOS does not (iOS does 🤷♂️). |
| 78 | // https://bugs.webkit.org/show_bug.cgi?id=222636 |
| 79 | if (!isWebKit() || isIOS() || !scrollableRef.current) { |
| 80 | return; |
| 81 | } |
| 82 | |
| 83 | let box = scrollableRef.current.getBoundingClientRect(); |
| 84 | let left = AUTOSCROLL_AREA_SIZE; |
no test coverage detected