Skip to content

Commit

Permalink
chore(directory): refine file settings
Browse files Browse the repository at this point in the history
  • Loading branch information
SMAKSS committed Jul 27, 2024
1 parent a08c78e commit 7e839a5
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 165 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,5 @@
},
"type": "module",
"types": "./dist/index.d.ts",
"version": "4.2.0-beta.0"
"version": "4.2.0-beta.1"
}
162 changes: 2 additions & 160 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,162 +1,4 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import {
Axis,
Direction,
ScrollInfo,
ScrollPosition,
ScrollProps
} from './types';
import useDetectScroll from './useDetectScroll';

/**
* useDetectScroll hook.
*
* This hook provides a mechanism to detect the scroll direction and position.
* It will return the scroll direction as a string (up, down, left, right, or still) based on user scrolling,
* as well as the scroll position from the top, bottom, left, and right edges of the page.
*
* @example
*
* import useDetectScroll, { Axis, Direction } from '@smakss/react-scroll-direction';
*
* function App() {
* const customElementRef = useRef<HTMLDivElement>(null);
* const [customElement, setCustomElement] = useState<HTMLDivElement>();
*
* const { scrollDir, scrollPosition } = useDetectScroll({
* target: customElement,
* thr: 100,
* axis: Axis.Y,
* scrollUp: Direction.Up,
* scrollDown: Direction.Down,
* still: Direction.Still
* });
*
* useEffect(() => {
* if (customElementRef.current) {
* setCustomElement(customElementRef.current);
* }
* }, [customElementRef]);
*
* return (
* <div>
* <p>Current scroll direction: {scrollDir}</p>
* <p>Scroll position - Top: {scrollPosition.top}, Bottom: {scrollPosition.bottom},
* Left: {scrollPosition.left}, Right: {scrollPosition.right}</p>
* </div>
* );
* }
*
* @param {ScrollProps} props - The properties related to scrolling.
* @returns {ScrollInfo} - The current direction and position of scrolling.
*/
function useDetectScroll(props: ScrollProps = {}): ScrollInfo {
const {
target = typeof window !== 'undefined' ? window : undefined,
thr = 0,
axis = Axis.Y,
scrollUp = axis === Axis.Y ? Direction.Up : Direction.Left,
scrollDown = axis === Axis.Y ? Direction.Down : Direction.Right,
still = Direction.Still
} = props;

const [scrollDir, setScrollDir] = useState<Direction>(still);
const [scrollPosition, setScrollPosition] = useState<ScrollPosition>({
top: 0,
bottom: 0,
left: 0,
right: 0
});

const threshold = Math.max(0, thr);
const ticking = useRef(false);
const lastScroll = useRef(0);

/** Function to update scroll direction */
const updateScrollDir = useCallback(() => {
if (!target) return;

let scroll: number;
if (target instanceof Window) {
scroll = axis === Axis.Y ? target.scrollY : target.scrollX;
} else {
scroll = axis === Axis.Y ? target.scrollTop : target.scrollLeft;
}

if (Math.abs(scroll - lastScroll.current) >= threshold) {
setScrollDir(scroll > lastScroll.current ? scrollDown : scrollUp);
lastScroll.current = Math.max(0, scroll);
}
ticking.current = false;
}, [target, axis, threshold, scrollDown, scrollUp]);

useEffect(() => {
if (!target) {
console.warn(
'useDetectScroll: target is not set. Falling back to window.'
);
return;
}

/** Function to update scroll position */
const updateScrollPosition = () => {
if (!target) return;

const top = target instanceof Window ? target.scrollY : target.scrollTop;
const left =
target instanceof Window ? target.scrollX : target.scrollLeft;

const bottom =
(target instanceof Window
? document.documentElement.scrollHeight - target.innerHeight
: target.scrollHeight - target.clientHeight) - top;
const right =
(target instanceof Window
? document.documentElement.scrollWidth - target.innerWidth
: target.scrollWidth - target.clientWidth) - left;

setScrollPosition({ top, bottom, left, right });
};

updateScrollPosition();

const targetElement = target as EventTarget;
targetElement.addEventListener('scroll', updateScrollPosition);

return () => {
targetElement.removeEventListener('scroll', updateScrollPosition);
};
}, [target]);

useEffect(() => {
if (!target) {
console.warn(
'useDetectScroll: target is not set. Falling back to window.'
);
return;
}

if (target instanceof Window) {
lastScroll.current = axis === Axis.Y ? target.scrollY : target.scrollX;
} else {
lastScroll.current =
axis === Axis.Y ? target.scrollTop : target.scrollLeft;
}

const onScroll = () => {
if (!ticking.current) {
window.requestAnimationFrame(updateScrollDir);
ticking.current = true;
}
};

const targetElement = target as EventTarget;
targetElement.addEventListener('scroll', onScroll);

return () => targetElement.removeEventListener('scroll', onScroll);
}, [target, axis, updateScrollDir]);

return { scrollDir, scrollPosition };
}

export { Axis, Direction };
export default useDetectScroll;
export { Axis, Direction } from './types';
9 changes: 5 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** Enumeration for axis values */
// Enumeration for axis values
export enum Axis {
/**
* The x-axis represents the horizontal direction.
Expand All @@ -10,7 +10,7 @@ export enum Axis {
Y = 'y'
}

/** Enumeration for direction values */
// Enumeration for direction values
export enum Direction {
/**
* The up direction represents the scroll direction moving towards the top.
Expand All @@ -34,6 +34,7 @@ export enum Direction {
Still = 'still'
}

// Type declaration for scroll position
export type ScrollPosition = {
/**
* The top position represents the distance from the top edge of the page.
Expand All @@ -53,7 +54,7 @@ export type ScrollPosition = {
right: number;
};

/** Type declaration for the returned scroll information */
// Type declaration for the returned scroll information
export type ScrollInfo = {
/**
* The scrollDir represents the current scroll direction.
Expand All @@ -65,7 +66,7 @@ export type ScrollInfo = {
scrollPosition: ScrollPosition;
};

/** Type declaration for scroll properties */
// Type declaration for scroll properties
export type ScrollProps = {
/**
* The target represents the scrollable element to check for scroll detection.
Expand Down
161 changes: 161 additions & 0 deletions src/useDetectScroll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import {
Axis,
Direction,
ScrollInfo,
ScrollPosition,
ScrollProps
} from './types';

/**
* useDetectScroll hook.
*
* This hook provides a mechanism to detect the scroll direction and position.
* It will return the scroll direction as a string (up, down, left, right, or still) based on user scrolling,
* as well as the scroll position from the top, bottom, left, and right edges of the page.
*
* @example
*
* import useDetectScroll, { Axis, Direction } from '@smakss/react-scroll-direction';
*
* function App() {
* const customElementRef = useRef<HTMLDivElement>(null);
* const [customElement, setCustomElement] = useState<HTMLDivElement>();
*
* const { scrollDir, scrollPosition } = useDetectScroll({
* target: customElement,
* thr: 100,
* axis: Axis.Y,
* scrollUp: Direction.Up,
* scrollDown: Direction.Down,
* still: Direction.Still
* });
*
* useEffect(() => {
* if (customElementRef.current) {
* setCustomElement(customElementRef.current);
* }
* }, [customElementRef]);
*
* return (
* <div>
* <p>Current scroll direction: {scrollDir}</p>
* <p>Scroll position - Top: {scrollPosition.top}, Bottom: {scrollPosition.bottom},
* Left: {scrollPosition.left}, Right: {scrollPosition.right}</p>
* </div>
* );
* }
*
* @param {ScrollProps} props - The properties related to scrolling.
* @returns {ScrollInfo} - The current direction and position of scrolling.
*/
function useDetectScroll(props: ScrollProps = {}): ScrollInfo {
const {
target = typeof window !== 'undefined' ? window : undefined,
thr = 0,
axis = Axis.Y,
scrollUp = axis === Axis.Y ? Direction.Up : Direction.Left,
scrollDown = axis === Axis.Y ? Direction.Down : Direction.Right,
still = Direction.Still
} = props;

const [scrollDir, setScrollDir] = useState<Direction>(still);
const [scrollPosition, setScrollPosition] = useState<ScrollPosition>({
top: 0,
bottom: 0,
left: 0,
right: 0
});

const threshold = Math.max(0, thr);
const ticking = useRef(false);
const lastScroll = useRef(0);

/** Function to update scroll direction */
const updateScrollDir = useCallback(() => {
if (!target) return;

let scroll: number;
if (target instanceof Window) {
scroll = axis === Axis.Y ? target.scrollY : target.scrollX;
} else {
scroll = axis === Axis.Y ? target.scrollTop : target.scrollLeft;
}

if (Math.abs(scroll - lastScroll.current) >= threshold) {
setScrollDir(scroll > lastScroll.current ? scrollDown : scrollUp);
lastScroll.current = Math.max(0, scroll);
}
ticking.current = false;
}, [target, axis, threshold, scrollDown, scrollUp]);

useEffect(() => {
if (!target) {
console.warn(
'useDetectScroll: target is not set. Falling back to window.'
);
return;
}

/** Function to update scroll position */
const updateScrollPosition = () => {
if (!target) return;

const top = target instanceof Window ? target.scrollY : target.scrollTop;
const left =
target instanceof Window ? target.scrollX : target.scrollLeft;

const bottom =
(target instanceof Window
? document.documentElement.scrollHeight - target.innerHeight
: target.scrollHeight - target.clientHeight) - top;
const right =
(target instanceof Window
? document.documentElement.scrollWidth - target.innerWidth
: target.scrollWidth - target.clientWidth) - left;

setScrollPosition({ top, bottom, left, right });
};

updateScrollPosition();

const targetElement = target as EventTarget;
targetElement.addEventListener('scroll', updateScrollPosition);

return () => {
targetElement.removeEventListener('scroll', updateScrollPosition);
};
}, [target]);

useEffect(() => {
if (!target) {
console.warn(
'useDetectScroll: target is not set. Falling back to window.'
);
return;
}

if (target instanceof Window) {
lastScroll.current = axis === Axis.Y ? target.scrollY : target.scrollX;
} else {
lastScroll.current =
axis === Axis.Y ? target.scrollTop : target.scrollLeft;
}

const onScroll = () => {
if (!ticking.current) {
window.requestAnimationFrame(updateScrollDir);
ticking.current = true;
}
};

const targetElement = target as EventTarget;
targetElement.addEventListener('scroll', onScroll);

return () => targetElement.removeEventListener('scroll', onScroll);
}, [target, axis, updateScrollDir]);

return { scrollDir, scrollPosition };
}

export default useDetectScroll;

0 comments on commit 7e839a5

Please sign in to comment.