use-scroller 1.2.0 → 2.0.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.
Files changed (42) hide show
  1. package/README.md +387 -95
  2. package/dist/chunk-BDIJT5M4.js +1188 -0
  3. package/dist/core.d.ts +121 -0
  4. package/dist/core.js +36 -0
  5. package/dist/index.d.ts +51 -0
  6. package/dist/index.js +346 -0
  7. package/package.json +38 -24
  8. package/dist/cjs/hooks/use-iso-morphic-effect.d.ts +0 -2
  9. package/dist/cjs/hooks/use-iso-morphic-effect.js +0 -6
  10. package/dist/cjs/hooks/use-scroll.d.ts +0 -24
  11. package/dist/cjs/hooks/use-scroll.js +0 -80
  12. package/dist/cjs/hooks/use-window-scroll.d.ts +0 -13
  13. package/dist/cjs/hooks/use-window-scroll.js +0 -62
  14. package/dist/cjs/index.d.ts +0 -3
  15. package/dist/cjs/index.js +0 -19
  16. package/dist/cjs/scroller.d.ts +0 -10
  17. package/dist/cjs/scroller.js +0 -94
  18. package/dist/cjs/types.d.ts +0 -17
  19. package/dist/cjs/types.js +0 -2
  20. package/dist/cjs/utils.d.ts +0 -37
  21. package/dist/cjs/utils.js +0 -92
  22. package/dist/esm/hooks/use-iso-morphic-effect.d.ts +0 -2
  23. package/dist/esm/hooks/use-iso-morphic-effect.js +0 -3
  24. package/dist/esm/hooks/use-scroll.d.ts +0 -24
  25. package/dist/esm/hooks/use-scroll.js +0 -76
  26. package/dist/esm/hooks/use-window-scroll.d.ts +0 -13
  27. package/dist/esm/hooks/use-window-scroll.js +0 -58
  28. package/dist/esm/index.d.ts +0 -3
  29. package/dist/esm/index.js +0 -3
  30. package/dist/esm/scroller.d.ts +0 -10
  31. package/dist/esm/scroller.js +0 -90
  32. package/dist/esm/types.d.ts +0 -17
  33. package/dist/esm/types.js +0 -1
  34. package/dist/esm/utils.d.ts +0 -37
  35. package/dist/esm/utils.js +0 -85
  36. package/src/hooks/use-iso-morphic-effect.ts +0 -4
  37. package/src/hooks/use-scroll.ts +0 -84
  38. package/src/hooks/use-window-scroll.ts +0 -73
  39. package/src/index.ts +0 -3
  40. package/src/scroller.ts +0 -107
  41. package/src/types.ts +0 -21
  42. package/src/utils.ts +0 -103
@@ -1,90 +0,0 @@
1
- import { defaultScrollOptions, getEasing, resolveScrollValues, validateElement } from './utils';
2
- export function createScroller(container, options) {
3
- if (options === void 0) { options = defaultScrollOptions; }
4
- validateElement(container);
5
- var duration = options.duration, easingOption = options.easingOption, direction = options.direction;
6
- var _a = resolveScrollValues(container), scrollLeft = _a.scrollLeft, scrollTop = _a.scrollTop, clientWidth = _a.clientWidth, clientHeight = _a.clientHeight, scrollWidth = _a.scrollWidth, scrollHeight = _a.scrollHeight;
7
- function scroll(from, to, layout) {
8
- if (layout === void 0) { layout = direction; }
9
- var startTime = null;
10
- var requestId = 0;
11
- var distance = Math.abs(to - from);
12
- function calculateCurrentPosition(timeFraction) {
13
- var easingFunc = getEasing(easingOption);
14
- return easingFunc(timeFraction) * distance + from;
15
- }
16
- function updateScrollPosition(currentPosition) {
17
- container.scrollTo({
18
- left: layout === 'horizontal' ? currentPosition : undefined,
19
- top: layout === 'vertical' ? currentPosition : undefined,
20
- });
21
- }
22
- function animateScroll(currentTime) {
23
- if (!startTime)
24
- startTime = currentTime;
25
- var elapsedTime = currentTime - startTime;
26
- var timeFraction = elapsedTime / duration;
27
- var currentPosition = calculateCurrentPosition(timeFraction);
28
- updateScrollPosition(currentPosition);
29
- if (timeFraction < 1) {
30
- requestId = requestAnimationFrame(animateScroll);
31
- }
32
- else {
33
- cancelAnimationFrame(requestId);
34
- }
35
- }
36
- requestId = requestAnimationFrame(animateScroll);
37
- }
38
- function scrollTo(to) {
39
- var from = direction === 'vertical' ? scrollTop : scrollLeft;
40
- scroll(from, to);
41
- }
42
- function scrollToCenter() {
43
- var from = 0;
44
- var to = 0;
45
- if (direction === 'vertical') {
46
- var scrollYCenterPosition = (scrollHeight - clientHeight) / 2;
47
- from = scrollTop;
48
- to = scrollYCenterPosition;
49
- }
50
- if (direction === 'horizontal') {
51
- var scrollXCenterPosition = (scrollWidth - clientWidth) / 2;
52
- from = scrollLeft;
53
- to = scrollXCenterPosition;
54
- }
55
- scroll(from, to, direction);
56
- }
57
- function scrollToTarget(target, offset) {
58
- if (offset === void 0) { offset = 0; }
59
- validateElement(target);
60
- var offsetTop = target.offsetTop, offsetLeft = target.offsetLeft;
61
- var from = 0;
62
- var to = 0;
63
- if (direction === 'vertical') {
64
- from = scrollTop;
65
- to = offsetTop - offset;
66
- }
67
- if (direction === 'horizontal') {
68
- from = scrollLeft;
69
- to = offsetLeft - offset;
70
- }
71
- scroll(from, to, direction);
72
- }
73
- return {
74
- scrollTo: scrollTo,
75
- scrollToCenter: scrollToCenter,
76
- scrollToTarget: scrollToTarget,
77
- scrollToLeft: function (offset) {
78
- scroll(scrollLeft, offset || scrollLeft - clientWidth, 'horizontal');
79
- },
80
- scrollToRight: function (offset) {
81
- scroll(scrollLeft, offset || scrollLeft + clientWidth, 'horizontal');
82
- },
83
- scrollToTop: function (offset) {
84
- scroll(scrollTop, offset || scrollTop - clientHeight, 'vertical');
85
- },
86
- scrollToBottom: function (offset) {
87
- scroll(scrollTop, offset || scrollTop + clientHeight, 'vertical');
88
- },
89
- };
90
- }
@@ -1,17 +0,0 @@
1
- export type ScrollOptions = {
2
- direction: 'horizontal' | 'vertical';
3
- duration: number;
4
- easingOption: EasingOptions;
5
- };
6
- export type ScrollerProps = {
7
- container: HTMLElement | Window;
8
- options: ScrollOptions;
9
- };
10
- export type EasingOptions = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
11
- export type EasingFunction = (t: number) => number;
12
- export interface EasingFunctions {
13
- linear: EasingFunction;
14
- 'ease-in': EasingFunction;
15
- 'ease-out': EasingFunction;
16
- 'ease-in-out': EasingFunction;
17
- }
package/dist/esm/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,37 +0,0 @@
1
- import { RefObject } from 'react';
2
- import { EasingFunction, EasingFunctions, EasingOptions, ScrollOptions } from './types';
3
- export declare const isServer: boolean;
4
- export declare const defaultScrollOptions: ScrollOptions;
5
- /**
6
- * Resolves scroll values based on the type of element.
7
- * @param {HTMLElement | Window} element - The element to retrieve scroll values from.
8
- * @returns {object} - An object containing scroll-related properties.
9
- */
10
- export declare const resolveScrollValues: (element: HTMLElement | Window) => {
11
- scrollLeft: number;
12
- scrollTop: number;
13
- scrollWidth: number;
14
- clientWidth: number;
15
- clientHeight: number;
16
- scrollHeight: number;
17
- scrollLeftMax: number;
18
- scrollTopMax: number;
19
- };
20
- /**
21
- * Validate if the element passed to the function is valid.
22
- * @param {HTMLElement | Window} element - The element to validate.
23
- */
24
- export declare function validateElement(element?: HTMLElement | Window): void;
25
- /**
26
- * Get the DOM element from a React ref object.
27
- * @param {RefObject<HTMLElement>} ref - The React ref object.
28
- * @returns {HTMLElement} - The DOM element.
29
- */
30
- export declare const getElement: (ref: RefObject<HTMLElement>) => HTMLElement;
31
- export declare const easingMap: EasingFunctions;
32
- /**
33
- * Get an easing function based on the provided easing option or the default option.
34
- * @param {EasingOptions} easing - The easing option.
35
- * @returns {EasingFunction} - The easing function.
36
- */
37
- export declare const getEasing: (easing?: EasingOptions) => EasingFunction;
package/dist/esm/utils.js DELETED
@@ -1,85 +0,0 @@
1
- // Check if the code is running on the server-side.
2
- export var isServer = typeof window === 'undefined' || typeof document === 'undefined';
3
- // Default scroll options used if no options are provided.
4
- export var defaultScrollOptions = {
5
- direction: 'vertical',
6
- duration: 300,
7
- easingOption: 'ease-in-out',
8
- };
9
- /**
10
- * Resolves scroll values based on the type of element.
11
- * @param {HTMLElement | Window} element - The element to retrieve scroll values from.
12
- * @returns {object} - An object containing scroll-related properties.
13
- */
14
- export var resolveScrollValues = function (element) {
15
- var isWindow = element instanceof Window;
16
- var docElement = document.documentElement;
17
- var docBody = document.body;
18
- var scrollLeftMax = isWindow
19
- ? Math.max(docBody.scrollLeft, docElement.scrollLeft)
20
- : element.scrollWidth - element.clientWidth;
21
- var scrollTopMax = isWindow
22
- ? Math.max(docBody.scrollTop, docElement.scrollTop)
23
- : element.scrollHeight - element.clientHeight;
24
- return {
25
- scrollLeft: isWindow ? docBody.scrollLeft || docElement.scrollLeft : element.scrollLeft,
26
- scrollTop: isWindow ? docBody.scrollTop || docElement.scrollTop : element.scrollTop,
27
- scrollWidth: isWindow ? docBody.scrollWidth || docElement.scrollWidth : element.scrollWidth,
28
- clientWidth: isWindow ? docBody.clientWidth || docElement.clientWidth : element.clientWidth,
29
- clientHeight: isWindow ? docBody.clientHeight || docElement.clientHeight : element.clientHeight,
30
- scrollHeight: isWindow ? docBody.scrollHeight || docElement.scrollHeight : element.scrollHeight,
31
- scrollLeftMax: scrollLeftMax,
32
- scrollTopMax: scrollTopMax,
33
- };
34
- };
35
- /**
36
- * Validate if the element passed to the function is valid.
37
- * @param {HTMLElement | Window} element - The element to validate.
38
- */
39
- export function validateElement(element) {
40
- if (element === undefined) {
41
- throw new Error("The element passed to scroller() was undefined");
42
- }
43
- if (!(element instanceof HTMLElement || Window)) {
44
- throw new TypeError("\n The element passed to scroller() must be a valid element. \n You passed ".concat(element, ".\n "));
45
- }
46
- }
47
- /**
48
- * Get the DOM element from a React ref object.
49
- * @param {RefObject<HTMLElement>} ref - The React ref object.
50
- * @returns {HTMLElement} - The DOM element.
51
- */
52
- export var getElement = function (ref) {
53
- if (!ref.current) {
54
- throw new Error("Could not resolve ref object: ".concat(ref.current));
55
- }
56
- return ref.current;
57
- };
58
- // Map of easing functions for scroll animations.
59
- export var easingMap = {
60
- linear: function (t) {
61
- return t;
62
- },
63
- 'ease-in': function (t) {
64
- return t * t;
65
- },
66
- 'ease-out': function (t) {
67
- return t * (2 - t);
68
- },
69
- 'ease-in-out': function (t) {
70
- return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
71
- },
72
- };
73
- /**
74
- * Get an easing function based on the provided easing option or the default option.
75
- * @param {EasingOptions} easing - The easing option.
76
- * @returns {EasingFunction} - The easing function.
77
- */
78
- export var getEasing = function (easing) {
79
- var easeFunc = easingMap[easing || defaultScrollOptions.easingOption];
80
- if (!easeFunc) {
81
- var options = Object.keys(easingMap).join(',');
82
- throw new Error("Scroll error: scroller does not support an easing option of \"".concat(easing, "\". Supported options are ").concat(options));
83
- }
84
- return easeFunc;
85
- };
@@ -1,4 +0,0 @@
1
- import { useLayoutEffect, useEffect } from 'react'
2
- import { isServer } from '../utils'
3
-
4
- export const useIsoMorphicEffect = isServer ? useEffect : useLayoutEffect
@@ -1,84 +0,0 @@
1
- import { useRef, useState } from 'react'
2
- import { createScroller } from '../scroller'
3
- import { ScrollOptions } from '../types'
4
- import { defaultScrollOptions, getElement } from '../utils'
5
- import { useIsoMorphicEffect } from './use-iso-morphic-effect'
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
-
21
- export function useScroll<T extends HTMLElement>(props?: Partial<ScrollOptions>) {
22
- const ref = useRef<T>(null)
23
- const scrollOpt = { ...defaultScrollOptions, ...props }
24
- const scrollerRef = useRef<ReturnType<typeof createScroller> | null>(null)
25
- const [state, setState] = useState(() => initialState)
26
-
27
- useIsoMorphicEffect(() => {
28
- const scrollContainer = ref.current
29
- if (!scrollContainer) return
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
-
37
- const { scrollWidth, clientWidth, clientHeight, scrollHeight } = scrollContainer
38
- const isScrollable = clientWidth !== scrollWidth || clientHeight !== scrollHeight
39
- setState((prev) => ({ ...prev, isScrollable }))
40
-
41
- const handleScroll = () => {
42
- if (scrollContainer) {
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
48
- const scrollState = {
49
- ...state,
50
- isScrolledLeft: isAtLeftBoundary,
51
- isScrolledRight: isAtRightBoundary,
52
- isScrolledTop: isAtTopBoundary,
53
- isScrolledBottom: isAtBottomBoundary,
54
- left: scrollLeft,
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,
64
- }
65
- setState(scrollState)
66
- }
67
- }
68
-
69
- handleScroll()
70
- scrollContainer?.addEventListener('scroll', handleScroll)
71
- return () => scrollContainer?.removeEventListener('scroll', handleScroll)
72
- }, [state])
73
-
74
- return {
75
- ref,
76
- state,
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,
83
- }
84
- }
@@ -1,73 +0,0 @@
1
- import { useCallback, useState } from 'react'
2
- import { createScroller } from '../scroller'
3
- import { ScrollOptions } from '../types'
4
- import { useIsoMorphicEffect } from './use-iso-morphic-effect'
5
- import { defaultScrollOptions, resolveScrollValues } from '../utils'
6
-
7
- export function useWindowScroll(props?: Partial<Omit<ScrollOptions, 'direction'>>) {
8
- const [state, setState] = useState(() => ({
9
- left: 0,
10
- top: 0,
11
- isScrolledTop: false,
12
- isScrolledBottom: false,
13
- }))
14
-
15
- const container = window
16
- const scrollOptions = { ...defaultScrollOptions, ...props }
17
-
18
- const scrollContainer = createScroller(container, scrollOptions)
19
-
20
- const handleScroll = useCallback(() => {
21
- const { scrollLeft, scrollTop, clientHeight, scrollHeight } = resolveScrollValues(container)
22
-
23
- const isAtTopBoundary = scrollTop === 0
24
- const isAtBottomBoundary = scrollTop >= scrollHeight - clientHeight
25
-
26
- const scrollState = {
27
- left: scrollLeft,
28
- top: scrollTop,
29
- isScrolledTop: isAtTopBoundary,
30
- isScrolledBottom: isAtBottomBoundary,
31
- }
32
-
33
- setState(scrollState)
34
- }, [container])
35
-
36
- useIsoMorphicEffect(() => {
37
- handleScroll()
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
- )
71
-
72
- return { state, scrollTop, scrollBottom, scrollToTarget, scrollTo }
73
- }
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './types'
2
- export * from './hooks/use-scroll'
3
- export * from './hooks/use-window-scroll'
package/src/scroller.ts DELETED
@@ -1,107 +0,0 @@
1
- import { ScrollOptions } from './types'
2
- import { defaultScrollOptions, getEasing, resolveScrollValues, validateElement } from './utils'
3
-
4
- export function createScroller(
5
- container: HTMLElement | Window,
6
- options: ScrollOptions = defaultScrollOptions
7
- ) {
8
- validateElement(container)
9
- const { duration, easingOption, direction } = options
10
- const { scrollLeft, scrollTop, clientWidth, clientHeight, scrollWidth, scrollHeight } =
11
- resolveScrollValues(container)
12
-
13
- function scroll(from: number, to: number, layout: ScrollOptions['direction'] = direction) {
14
- let startTime: number | null = null
15
- let requestId = 0
16
- const distance = Math.abs(to - from)
17
-
18
- function calculateCurrentPosition(timeFraction: number): number {
19
- const easingFunc = getEasing(easingOption)
20
- return easingFunc(timeFraction) * distance + from
21
- }
22
-
23
- function updateScrollPosition(currentPosition: number) {
24
- container.scrollTo({
25
- left: layout === 'horizontal' ? currentPosition : undefined,
26
- top: layout === 'vertical' ? currentPosition : undefined,
27
- })
28
- }
29
-
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)
40
- } else {
41
- cancelAnimationFrame(requestId)
42
- }
43
- }
44
-
45
- requestId = requestAnimationFrame(animateScroll)
46
- }
47
-
48
- function scrollTo(to: number) {
49
- const from = direction === 'vertical' ? scrollTop : scrollLeft
50
- scroll(from, to)
51
- }
52
-
53
- function scrollToCenter() {
54
- let from = 0
55
- let to = 0
56
-
57
- if (direction === 'vertical') {
58
- const scrollYCenterPosition = (scrollHeight - clientHeight) / 2
59
- from = scrollTop
60
- to = scrollYCenterPosition
61
- }
62
-
63
- if (direction === 'horizontal') {
64
- const scrollXCenterPosition = (scrollWidth - clientWidth) / 2
65
- from = scrollLeft
66
- to = scrollXCenterPosition
67
- }
68
- scroll(from, to, direction)
69
- }
70
-
71
- function scrollToTarget(target: HTMLElement, offset = 0) {
72
- validateElement(target)
73
- const { offsetTop, offsetLeft } = target
74
- let from = 0
75
- let to = 0
76
-
77
- if (direction === 'vertical') {
78
- from = scrollTop
79
- to = offsetTop - offset
80
- }
81
-
82
- if (direction === 'horizontal') {
83
- from = scrollLeft
84
- to = offsetLeft - offset
85
- }
86
-
87
- scroll(from, to, direction)
88
- }
89
-
90
- return {
91
- scrollTo,
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
- },
106
- }
107
- }
package/src/types.ts DELETED
@@ -1,21 +0,0 @@
1
- export type ScrollOptions = {
2
- direction: 'horizontal' | 'vertical'
3
- duration: number
4
- easingOption: EasingOptions
5
- }
6
-
7
- export type ScrollerProps = {
8
- container: HTMLElement | Window
9
- options: ScrollOptions
10
- }
11
-
12
- export type EasingOptions = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out'
13
-
14
- export type EasingFunction = (t: number) => number
15
-
16
- export interface EasingFunctions {
17
- linear: EasingFunction
18
- 'ease-in': EasingFunction
19
- 'ease-out': EasingFunction
20
- 'ease-in-out': EasingFunction
21
- }
package/src/utils.ts DELETED
@@ -1,103 +0,0 @@
1
- import { RefObject } from 'react'
2
- import { EasingFunction, EasingFunctions, EasingOptions, ScrollOptions } from './types'
3
-
4
- // Check if the code is running on the server-side.
5
- export const isServer = typeof window === 'undefined' || typeof document === 'undefined'
6
-
7
- // Default scroll options used if no options are provided.
8
- export const defaultScrollOptions: ScrollOptions = {
9
- direction: 'vertical',
10
- duration: 300,
11
- easingOption: 'ease-in-out',
12
- }
13
-
14
- /**
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.
18
- */
19
- export const resolveScrollValues = (element: HTMLElement | Window) => {
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
- return {
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,
40
- }
41
- }
42
-
43
- /**
44
- * Validate if the element passed to the function is valid.
45
- * @param {HTMLElement | Window} element - The element to validate.
46
- */
47
- export function validateElement(element?: HTMLElement | Window) {
48
- if (element === undefined) {
49
- throw new Error(`The element passed to scroller() was undefined`)
50
- }
51
- if (!(element instanceof HTMLElement || Window)) {
52
- throw new TypeError(
53
- `
54
- The element passed to scroller() must be a valid element.
55
- You passed ${element}.
56
- `
57
- )
58
- }
59
- }
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
- */
66
- export const getElement = (ref: RefObject<HTMLElement>) => {
67
- if (!ref.current) {
68
- throw new Error(`Could not resolve ref object: ${ref.current}`)
69
- }
70
- return ref.current
71
- }
72
-
73
- // Map of easing functions for scroll animations.
74
- export const easingMap: EasingFunctions = {
75
- linear(t: number) {
76
- return t
77
- },
78
- 'ease-in'(t: number) {
79
- return t * t
80
- },
81
- 'ease-out'(t: number) {
82
- return t * (2 - t)
83
- },
84
- 'ease-in-out'(t: number) {
85
- return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t
86
- },
87
- }
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
- */
94
- export const getEasing = (easing?: EasingOptions): EasingFunction => {
95
- const easeFunc = easingMap[easing || defaultScrollOptions.easingOption]
96
- if (!easeFunc) {
97
- const options = Object.keys(easingMap).join(',')
98
- throw new Error(
99
- `Scroll error: scroller does not support an easing option of "${easing}". Supported options are ${options}`
100
- )
101
- }
102
- return easeFunc
103
- }