PluginProbe
Code Snippets / 3.10.2
Code Snippets v3.10.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / js / hooks / useHorizontalScrollOverflow.ts

useHorizontalScrollOverflow.ts in Code Snippets 3.10.2, at js/hooks/useHorizontalScrollOverflow.ts

53 lines 1.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useCallback, useEffect, useRef, useState } from 'react'
2
3 interface HorizontalScrollOverflow {
4 atStart: boolean
5 atEnd: boolean
6 scrollRef: React.RefObject<HTMLElement>
7 }
8
9 const EDGE_TOLERANCE = 1
10
11 export const useHorizontalScrollOverflow = (): HorizontalScrollOverflow => {
12 const scrollRef = useRef<HTMLElement>(null)
13 const [position, setPosition] = useState({ atStart: true, atEnd: true })
14
15 const updatePosition = useCallback(() => {
16 const element = scrollRef.current
17
18 if (!element) {
19 return
20 }
21
22 const hasOverflow = element.scrollWidth - element.clientWidth > EDGE_TOLERANCE
23 const atStart = !hasOverflow || element.scrollLeft <= EDGE_TOLERANCE
24 const atEnd = !hasOverflow || element.scrollLeft + element.clientWidth >= element.scrollWidth - EDGE_TOLERANCE
25
26 setPosition(previous => previous.atStart === atStart && previous.atEnd === atEnd
27 ? previous
28 : { atStart, atEnd })
29 }, [])
30
31 useEffect(() => {
32 const element = scrollRef.current
33
34 if (!element) {
35 return
36 }
37
38 updatePosition()
39 element.addEventListener('scroll', updatePosition, { passive: true })
40
41 const observer = new ResizeObserver(updatePosition)
42 observer.observe(element)
43 observer.observe(element.firstElementChild ?? element)
44
45 return () => {
46 element.removeEventListener('scroll', updatePosition)
47 observer.disconnect()
48 }
49 }, [updatePosition])
50
51 return { ...position, scrollRef }
52 }
53