use-scroller 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -58
- package/dist/cjs/hooks/use-scroll.d.ts +10 -5
- package/dist/cjs/hooks/use-scroll.js +38 -42
- package/dist/cjs/hooks/use-window-scroll.d.ts +1 -0
- package/dist/cjs/hooks/use-window-scroll.js +29 -23
- package/dist/cjs/scroller.d.ts +5 -4
- package/dist/cjs/scroller.js +49 -50
- package/dist/cjs/utils.d.ts +17 -4
- package/dist/cjs/utils.js +35 -22
- package/dist/esm/hooks/use-scroll.d.ts +10 -5
- package/dist/esm/hooks/use-scroll.js +40 -44
- package/dist/esm/hooks/use-window-scroll.d.ts +1 -0
- package/dist/esm/hooks/use-window-scroll.js +30 -24
- package/dist/esm/scroller.d.ts +5 -4
- package/dist/esm/scroller.js +47 -48
- package/dist/esm/utils.d.ts +17 -4
- package/dist/esm/utils.js +35 -22
- package/package.json +11 -2
- package/src/hooks/use-scroll.ts +47 -51
- package/src/hooks/use-window-scroll.ts +52 -35
- package/src/scroller.ts +50 -52
- package/src/utils.ts +37 -24
package/src/hooks/use-scroll.ts
CHANGED
|
@@ -1,56 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useRef, useState } from 'react'
|
|
2
|
+
import { createScroller } from '../scroller'
|
|
3
3
|
import { ScrollOptions } from '../types'
|
|
4
4
|
import { defaultScrollOptions, getElement } from '../utils'
|
|
5
5
|
import { useIsoMorphicEffect } from './use-iso-morphic-effect'
|
|
6
6
|
|
|
7
|
+
const initialState = {
|
|
8
|
+
left: 0, // Current scroll position on the X-axis
|
|
9
|
+
top: 0, // Current scroll position on the Y-axis
|
|
10
|
+
isScrollable: false, // Determines if the container has content that can be scrolled
|
|
11
|
+
isScrolledLeft: true, // Determines if the container is at its leftmost position
|
|
12
|
+
isScrolledRight: false, // Determines if the container is at its rightmost position
|
|
13
|
+
isScrolledTop: true, // Determines if the container is at its topmost position
|
|
14
|
+
isScrolledBottom: false, // Determines if the container is at its bottommost position
|
|
15
|
+
maxScrollLeft: 0, // Maximum possible scroll on the X-axis
|
|
16
|
+
maxScrollTop: 0, // Maximum possible scroll on the Y-axis
|
|
17
|
+
scrollPercentageX: 0, // Percentage of horizontal scroll covered
|
|
18
|
+
scrollPercentageY: 0, // Percentage of vertical scroll covered
|
|
19
|
+
}
|
|
20
|
+
|
|
7
21
|
export function useScroll<T extends HTMLElement>(props?: Partial<ScrollOptions>) {
|
|
8
22
|
const ref = useRef<T>(null)
|
|
9
|
-
const [state, setState] = useState(() => ({
|
|
10
|
-
left: 0,
|
|
11
|
-
top: 0,
|
|
12
|
-
isScrollable: false,
|
|
13
|
-
isScrolledLeft: false,
|
|
14
|
-
isScrolledRight: false,
|
|
15
|
-
isScrolledTop: false,
|
|
16
|
-
isScrolledBottom: false,
|
|
17
|
-
}))
|
|
18
23
|
const scrollOpt = { ...defaultScrollOptions, ...props }
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
const container = getElement(ref)
|
|
22
|
-
const scrollContainer = scroller({ container, options: scrollOpt })
|
|
23
|
-
scrollContainer.scrollToCenter()
|
|
24
|
-
}, [])
|
|
25
|
-
|
|
26
|
-
const scrollTop = useCallback((offset?: number) => {
|
|
27
|
-
const container = getElement(ref)
|
|
28
|
-
const scrollContainer = scroller({ container, options: scrollOpt })
|
|
29
|
-
scrollContainer.scrollToTop(offset)
|
|
30
|
-
}, [])
|
|
31
|
-
|
|
32
|
-
const scrollBottom = useCallback((offset?: number) => {
|
|
33
|
-
const container = getElement(ref)
|
|
34
|
-
const scrollContainer = scroller({ container, options: scrollOpt })
|
|
35
|
-
scrollContainer.scrollToBottom(offset)
|
|
36
|
-
}, [])
|
|
37
|
-
|
|
38
|
-
const scrollRight = useCallback((offset?: number) => {
|
|
39
|
-
const container = getElement(ref)
|
|
40
|
-
const scrollContainer = scroller({ container, options: scrollOpt })
|
|
41
|
-
scrollContainer.scrollToRight(offset)
|
|
42
|
-
}, [])
|
|
43
|
-
|
|
44
|
-
const scrollLeft = useCallback((offset?: number) => {
|
|
45
|
-
const container = getElement(ref)
|
|
46
|
-
const scrollContainer = scroller({ container, options: scrollOpt })
|
|
47
|
-
scrollContainer.scrollToLeft(offset)
|
|
48
|
-
}, [])
|
|
24
|
+
const scrollerRef = useRef<ReturnType<typeof createScroller> | null>(null)
|
|
25
|
+
const [state, setState] = useState(() => initialState)
|
|
49
26
|
|
|
50
27
|
useIsoMorphicEffect(() => {
|
|
51
28
|
const scrollContainer = ref.current
|
|
52
29
|
if (!scrollContainer) return
|
|
53
30
|
|
|
31
|
+
// Create the scroller instance only once inside the effect
|
|
32
|
+
if (!scrollerRef.current) {
|
|
33
|
+
const container = getElement(ref)
|
|
34
|
+
scrollerRef.current = createScroller(container, scrollOpt)
|
|
35
|
+
}
|
|
36
|
+
|
|
54
37
|
const { scrollWidth, clientWidth, clientHeight, scrollHeight } = scrollContainer
|
|
55
38
|
const isScrollable = clientWidth !== scrollWidth || clientHeight !== scrollHeight
|
|
56
39
|
setState((prev) => ({ ...prev, isScrollable }))
|
|
@@ -58,14 +41,26 @@ export function useScroll<T extends HTMLElement>(props?: Partial<ScrollOptions>)
|
|
|
58
41
|
const handleScroll = () => {
|
|
59
42
|
if (scrollContainer) {
|
|
60
43
|
const { scrollLeft, scrollTop } = scrollContainer
|
|
44
|
+
const isAtLeftBoundary = scrollLeft === 0
|
|
45
|
+
const isAtRightBoundary = scrollLeft >= scrollWidth - clientWidth
|
|
46
|
+
const isAtTopBoundary = scrollTop === 0
|
|
47
|
+
const isAtBottomBoundary = scrollTop >= scrollHeight - clientHeight
|
|
61
48
|
const scrollState = {
|
|
62
49
|
...state,
|
|
63
|
-
isScrolledLeft:
|
|
64
|
-
isScrolledRight:
|
|
65
|
-
isScrolledTop:
|
|
66
|
-
isScrolledBottom:
|
|
50
|
+
isScrolledLeft: isAtLeftBoundary,
|
|
51
|
+
isScrolledRight: isAtRightBoundary,
|
|
52
|
+
isScrolledTop: isAtTopBoundary,
|
|
53
|
+
isScrolledBottom: isAtBottomBoundary,
|
|
67
54
|
left: scrollLeft,
|
|
68
55
|
top: scrollTop,
|
|
56
|
+
maxScrollLeft: scrollWidth - clientWidth,
|
|
57
|
+
maxScrollTop: scrollHeight - clientHeight,
|
|
58
|
+
scrollPercentageX: isAtLeftBoundary
|
|
59
|
+
? 0
|
|
60
|
+
: (scrollLeft / (scrollWidth - clientWidth)) * 100,
|
|
61
|
+
scrollPercentageY: isAtTopBoundary
|
|
62
|
+
? 0
|
|
63
|
+
: (scrollTop / (scrollHeight - clientHeight)) * 100,
|
|
69
64
|
}
|
|
70
65
|
setState(scrollState)
|
|
71
66
|
}
|
|
@@ -74,15 +69,16 @@ export function useScroll<T extends HTMLElement>(props?: Partial<ScrollOptions>)
|
|
|
74
69
|
handleScroll()
|
|
75
70
|
scrollContainer?.addEventListener('scroll', handleScroll)
|
|
76
71
|
return () => scrollContainer?.removeEventListener('scroll', handleScroll)
|
|
77
|
-
}, [])
|
|
72
|
+
}, [state])
|
|
78
73
|
|
|
79
74
|
return {
|
|
80
75
|
ref,
|
|
81
76
|
state,
|
|
82
|
-
scrollLeft,
|
|
83
|
-
scrollRight,
|
|
84
|
-
scrollBottom,
|
|
85
|
-
scrollTop,
|
|
86
|
-
scrollCenter,
|
|
77
|
+
scrollLeft: scrollerRef.current?.scrollToLeft,
|
|
78
|
+
scrollRight: scrollerRef.current?.scrollToRight,
|
|
79
|
+
scrollBottom: scrollerRef.current?.scrollToBottom,
|
|
80
|
+
scrollTop: scrollerRef.current?.scrollToTop,
|
|
81
|
+
scrollCenter: scrollerRef.current?.scrollToCenter,
|
|
82
|
+
scrollTo: scrollerRef.current?.scrollTo,
|
|
87
83
|
}
|
|
88
84
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useState } from 'react'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createScroller } from '../scroller'
|
|
3
|
+
import { ScrollOptions } from '../types'
|
|
4
4
|
import { useIsoMorphicEffect } from './use-iso-morphic-effect'
|
|
5
5
|
import { defaultScrollOptions, resolveScrollValues } from '../utils'
|
|
6
6
|
|
|
@@ -12,45 +12,62 @@ export function useWindowScroll(props?: Partial<Omit<ScrollOptions, 'direction'>
|
|
|
12
12
|
isScrolledBottom: false,
|
|
13
13
|
}))
|
|
14
14
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
options: { ...defaultScrollOptions, ...props },
|
|
18
|
-
}
|
|
15
|
+
const container = window
|
|
16
|
+
const scrollOptions = { ...defaultScrollOptions, ...props }
|
|
19
17
|
|
|
20
|
-
const
|
|
21
|
-
const scrollContainer = scroller(scrollArgs)
|
|
22
|
-
scrollContainer.scrollToTarget(currentTarget)
|
|
23
|
-
}, [])
|
|
18
|
+
const scrollContainer = createScroller(container, scrollOptions)
|
|
24
19
|
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
scrollContainer.scrollToTop(offset)
|
|
28
|
-
}, [])
|
|
20
|
+
const handleScroll = useCallback(() => {
|
|
21
|
+
const { scrollLeft, scrollTop, clientHeight, scrollHeight } = resolveScrollValues(container)
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
scrollContainer.scrollToBottom(offset)
|
|
33
|
-
}, [])
|
|
23
|
+
const isAtTopBoundary = scrollTop === 0
|
|
24
|
+
const isAtBottomBoundary = scrollTop >= scrollHeight - clientHeight
|
|
34
25
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
...state,
|
|
41
|
-
isScrolledTop: scrollTop === 0,
|
|
42
|
-
isScrolledBottom: scrollTop >= scrollHeight - clientHeight,
|
|
43
|
-
left: scrollLeft,
|
|
44
|
-
top: scrollTop,
|
|
45
|
-
}
|
|
46
|
-
setState(scrollState)
|
|
47
|
-
}
|
|
26
|
+
const scrollState = {
|
|
27
|
+
left: scrollLeft,
|
|
28
|
+
top: scrollTop,
|
|
29
|
+
isScrolledTop: isAtTopBoundary,
|
|
30
|
+
isScrolledBottom: isAtBottomBoundary,
|
|
48
31
|
}
|
|
49
32
|
|
|
33
|
+
setState(scrollState)
|
|
34
|
+
}, [container])
|
|
35
|
+
|
|
36
|
+
useIsoMorphicEffect(() => {
|
|
50
37
|
handleScroll()
|
|
51
|
-
|
|
52
|
-
return () =>
|
|
53
|
-
|
|
38
|
+
container.addEventListener('scroll', handleScroll)
|
|
39
|
+
return () => {
|
|
40
|
+
container.removeEventListener('scroll', handleScroll)
|
|
41
|
+
}
|
|
42
|
+
}, [handleScroll])
|
|
43
|
+
|
|
44
|
+
const scrollTo = useCallback(
|
|
45
|
+
(position: number) => {
|
|
46
|
+
scrollContainer.scrollTo(position)
|
|
47
|
+
},
|
|
48
|
+
[scrollContainer]
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const scrollToTarget = useCallback(
|
|
52
|
+
(currentTarget: HTMLElement) => {
|
|
53
|
+
scrollContainer.scrollToTarget(currentTarget)
|
|
54
|
+
},
|
|
55
|
+
[scrollContainer]
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
const scrollTop = useCallback(
|
|
59
|
+
(offset?: number | undefined) => {
|
|
60
|
+
scrollContainer.scrollToTop(offset)
|
|
61
|
+
},
|
|
62
|
+
[scrollContainer]
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
const scrollBottom = useCallback(
|
|
66
|
+
(offset?: number | undefined) => {
|
|
67
|
+
scrollContainer.scrollToBottom(offset)
|
|
68
|
+
},
|
|
69
|
+
[scrollContainer]
|
|
70
|
+
)
|
|
54
71
|
|
|
55
|
-
return { state, scrollTop, scrollBottom, scrollToTarget }
|
|
72
|
+
return { state, scrollTop, scrollBottom, scrollToTarget, scrollTo }
|
|
56
73
|
}
|
package/src/scroller.ts
CHANGED
|
@@ -1,44 +1,53 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ScrollOptions } from './types'
|
|
2
2
|
import { defaultScrollOptions, getEasing, resolveScrollValues, validateElement } from './utils'
|
|
3
3
|
|
|
4
|
-
export function
|
|
4
|
+
export function createScroller(
|
|
5
|
+
container: HTMLElement | Window,
|
|
6
|
+
options: ScrollOptions = defaultScrollOptions
|
|
7
|
+
) {
|
|
5
8
|
validateElement(container)
|
|
6
|
-
|
|
7
9
|
const { duration, easingOption, direction } = options
|
|
8
10
|
const { scrollLeft, scrollTop, clientWidth, clientHeight, scrollWidth, scrollHeight } =
|
|
9
11
|
resolveScrollValues(container)
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
* Scroll the Element or Window to the given
|
|
13
|
-
* position.
|
|
14
|
-
*
|
|
15
|
-
* @param {number} from the current scroll position.
|
|
16
|
-
* @param {number} to the new position to scroll.
|
|
17
|
-
* @param {string} layout the scroll direction.
|
|
18
|
-
*/
|
|
19
|
-
function scrollTo(from: number, to: number, layout: 'horizontal' | 'vertical') {
|
|
13
|
+
function scroll(from: number, to: number, layout: ScrollOptions['direction'] = direction) {
|
|
20
14
|
let startTime: number | null = null
|
|
21
15
|
let requestId = 0
|
|
16
|
+
const distance = Math.abs(to - from)
|
|
22
17
|
|
|
23
|
-
function
|
|
24
|
-
if (!startTime) startTime = currentTime
|
|
25
|
-
|
|
26
|
-
const time = Math.min((currentTime - startTime) / duration, 1)
|
|
18
|
+
function calculateCurrentPosition(timeFraction: number): number {
|
|
27
19
|
const easingFunc = getEasing(easingOption)
|
|
28
|
-
|
|
20
|
+
return easingFunc(timeFraction) * distance + from
|
|
21
|
+
}
|
|
29
22
|
|
|
23
|
+
function updateScrollPosition(currentPosition: number) {
|
|
30
24
|
container.scrollTo({
|
|
31
|
-
left: layout === 'horizontal' ?
|
|
32
|
-
top: layout === 'vertical' ?
|
|
25
|
+
left: layout === 'horizontal' ? currentPosition : undefined,
|
|
26
|
+
top: layout === 'vertical' ? currentPosition : undefined,
|
|
33
27
|
})
|
|
28
|
+
}
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
function animateScroll(currentTime: number) {
|
|
31
|
+
if (!startTime) startTime = currentTime
|
|
32
|
+
const elapsedTime = currentTime - startTime
|
|
33
|
+
const timeFraction = elapsedTime / duration
|
|
34
|
+
const currentPosition = calculateCurrentPosition(timeFraction)
|
|
35
|
+
|
|
36
|
+
updateScrollPosition(currentPosition)
|
|
37
|
+
|
|
38
|
+
if (timeFraction < 1) {
|
|
39
|
+
requestId = requestAnimationFrame(animateScroll)
|
|
37
40
|
} else {
|
|
38
41
|
cancelAnimationFrame(requestId)
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
|
-
|
|
44
|
+
|
|
45
|
+
requestId = requestAnimationFrame(animateScroll)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function scrollTo(to: number) {
|
|
49
|
+
const from = direction === 'vertical' ? scrollTop : scrollLeft
|
|
50
|
+
scroll(from, to)
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
function scrollToCenter() {
|
|
@@ -56,10 +65,10 @@ export function scroller({ container, options = defaultScrollOptions }: Scroller
|
|
|
56
65
|
from = scrollLeft
|
|
57
66
|
to = scrollXCenterPosition
|
|
58
67
|
}
|
|
59
|
-
|
|
68
|
+
scroll(from, to, direction)
|
|
60
69
|
}
|
|
61
70
|
|
|
62
|
-
function scrollToTarget(target: HTMLElement) {
|
|
71
|
+
function scrollToTarget(target: HTMLElement, offset = 0) {
|
|
63
72
|
validateElement(target)
|
|
64
73
|
const { offsetTop, offsetLeft } = target
|
|
65
74
|
let from = 0
|
|
@@ -67,43 +76,32 @@ export function scroller({ container, options = defaultScrollOptions }: Scroller
|
|
|
67
76
|
|
|
68
77
|
if (direction === 'vertical') {
|
|
69
78
|
from = scrollTop
|
|
70
|
-
to = offsetTop
|
|
79
|
+
to = offsetTop - offset
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
if (direction === 'horizontal') {
|
|
74
83
|
from = scrollLeft
|
|
75
|
-
to = offsetLeft
|
|
84
|
+
to = offsetLeft - offset
|
|
76
85
|
}
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const scrollToLeft = (offset?: number) => {
|
|
82
|
-
const scrollPosition = offset || scrollLeft - clientWidth
|
|
83
|
-
scrollTo(scrollLeft, scrollPosition, 'horizontal')
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const scrollToRight = (offset?: number) => {
|
|
87
|
-
const scrollPosition = offset || scrollLeft + clientWidth
|
|
88
|
-
scrollTo(scrollLeft, scrollPosition, 'horizontal')
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const scrollToTop = (offset?: number) => {
|
|
92
|
-
const scrollPosition = offset || scrollTop - clientHeight
|
|
93
|
-
scrollTo(scrollTop, scrollPosition, 'vertical')
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const scrollToBottom = (offset?: number) => {
|
|
97
|
-
const scrollPosition = offset || scrollTop + clientHeight
|
|
98
|
-
scrollTo(scrollTop, scrollPosition, 'vertical')
|
|
87
|
+
scroll(from, to, direction)
|
|
99
88
|
}
|
|
100
89
|
|
|
101
90
|
return {
|
|
102
|
-
|
|
103
|
-
scrollToRight,
|
|
104
|
-
scrollToTop,
|
|
105
|
-
scrollToBottom,
|
|
106
|
-
scrollToTarget,
|
|
91
|
+
scrollTo,
|
|
107
92
|
scrollToCenter,
|
|
93
|
+
scrollToTarget,
|
|
94
|
+
scrollToLeft: (offset?: number) => {
|
|
95
|
+
scroll(scrollLeft, offset || scrollLeft - clientWidth, 'horizontal')
|
|
96
|
+
},
|
|
97
|
+
scrollToRight: (offset?: number) => {
|
|
98
|
+
scroll(scrollLeft, offset || scrollLeft + clientWidth, 'horizontal')
|
|
99
|
+
},
|
|
100
|
+
scrollToTop: (offset?: number) => {
|
|
101
|
+
scroll(scrollTop, offset || scrollTop - clientHeight, 'vertical')
|
|
102
|
+
},
|
|
103
|
+
scrollToBottom: (offset?: number) => {
|
|
104
|
+
scroll(scrollTop, offset || scrollTop + clientHeight, 'vertical')
|
|
105
|
+
},
|
|
108
106
|
}
|
|
109
107
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { RefObject } from 'react'
|
|
2
2
|
import { EasingFunction, EasingFunctions, EasingOptions, ScrollOptions } from './types'
|
|
3
3
|
|
|
4
|
+
// Check if the code is running on the server-side.
|
|
4
5
|
export const isServer = typeof window === 'undefined' || typeof document === 'undefined'
|
|
5
6
|
|
|
7
|
+
// Default scroll options used if no options are provided.
|
|
6
8
|
export const defaultScrollOptions: ScrollOptions = {
|
|
7
9
|
direction: 'vertical',
|
|
8
10
|
duration: 300,
|
|
@@ -10,37 +12,37 @@ export const defaultScrollOptions: ScrollOptions = {
|
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
|
-
* Resolves scroll values based on the type of
|
|
14
|
-
* @param {HTMLElement | Window} element
|
|
15
|
+
* Resolves scroll values based on the type of element.
|
|
16
|
+
* @param {HTMLElement | Window} element - The element to retrieve scroll values from.
|
|
17
|
+
* @returns {object} - An object containing scroll-related properties.
|
|
15
18
|
*/
|
|
16
19
|
export const resolveScrollValues = (element: HTMLElement | Window) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
scrollHeight: document.body.scrollHeight || document.documentElement.scrollHeight,
|
|
29
|
-
}
|
|
30
|
-
}
|
|
20
|
+
const isWindow = element instanceof Window
|
|
21
|
+
const docElement = document.documentElement
|
|
22
|
+
const docBody = document.body
|
|
23
|
+
|
|
24
|
+
const scrollLeftMax = isWindow
|
|
25
|
+
? Math.max(docBody.scrollLeft, docElement.scrollLeft)
|
|
26
|
+
: element.scrollWidth - element.clientWidth
|
|
27
|
+
const scrollTopMax = isWindow
|
|
28
|
+
? Math.max(docBody.scrollTop, docElement.scrollTop)
|
|
29
|
+
: element.scrollHeight - element.clientHeight
|
|
30
|
+
|
|
31
31
|
return {
|
|
32
|
-
scrollLeft: element.scrollLeft,
|
|
33
|
-
scrollTop: element.scrollTop,
|
|
34
|
-
scrollWidth: element.scrollWidth,
|
|
35
|
-
clientWidth: element.clientWidth,
|
|
36
|
-
clientHeight: element.clientHeight,
|
|
37
|
-
scrollHeight: element.scrollHeight,
|
|
32
|
+
scrollLeft: isWindow ? docBody.scrollLeft || docElement.scrollLeft : element.scrollLeft,
|
|
33
|
+
scrollTop: isWindow ? docBody.scrollTop || docElement.scrollTop : element.scrollTop,
|
|
34
|
+
scrollWidth: isWindow ? docBody.scrollWidth || docElement.scrollWidth : element.scrollWidth,
|
|
35
|
+
clientWidth: isWindow ? docBody.clientWidth || docElement.clientWidth : element.clientWidth,
|
|
36
|
+
clientHeight: isWindow ? docBody.clientHeight || docElement.clientHeight : element.clientHeight,
|
|
37
|
+
scrollHeight: isWindow ? docBody.scrollHeight || docElement.scrollHeight : element.scrollHeight,
|
|
38
|
+
scrollLeftMax,
|
|
39
|
+
scrollTopMax,
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
|
-
* Validate if element passed to the function is valid.
|
|
43
|
-
* @param {HTMLElement | Window} element
|
|
44
|
+
* Validate if the element passed to the function is valid.
|
|
45
|
+
* @param {HTMLElement | Window} element - The element to validate.
|
|
44
46
|
*/
|
|
45
47
|
export function validateElement(element?: HTMLElement | Window) {
|
|
46
48
|
if (element === undefined) {
|
|
@@ -56,6 +58,11 @@ export function validateElement(element?: HTMLElement | Window) {
|
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Get the DOM element from a React ref object.
|
|
63
|
+
* @param {RefObject<HTMLElement>} ref - The React ref object.
|
|
64
|
+
* @returns {HTMLElement} - The DOM element.
|
|
65
|
+
*/
|
|
59
66
|
export const getElement = (ref: RefObject<HTMLElement>) => {
|
|
60
67
|
if (!ref.current) {
|
|
61
68
|
throw new Error(`Could not resolve ref object: ${ref.current}`)
|
|
@@ -63,6 +70,7 @@ export const getElement = (ref: RefObject<HTMLElement>) => {
|
|
|
63
70
|
return ref.current
|
|
64
71
|
}
|
|
65
72
|
|
|
73
|
+
// Map of easing functions for scroll animations.
|
|
66
74
|
export const easingMap: EasingFunctions = {
|
|
67
75
|
linear(t: number) {
|
|
68
76
|
return t
|
|
@@ -78,6 +86,11 @@ export const easingMap: EasingFunctions = {
|
|
|
78
86
|
},
|
|
79
87
|
}
|
|
80
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Get an easing function based on the provided easing option or the default option.
|
|
91
|
+
* @param {EasingOptions} easing - The easing option.
|
|
92
|
+
* @returns {EasingFunction} - The easing function.
|
|
93
|
+
*/
|
|
81
94
|
export const getEasing = (easing?: EasingOptions): EasingFunction => {
|
|
82
95
|
const easeFunc = easingMap[easing || defaultScrollOptions.easingOption]
|
|
83
96
|
if (!easeFunc) {
|