From 3ff98c7039f6c53d672378b6e6cff081bf34e500 Mon Sep 17 00:00:00 2001 From: zeroqs Date: Wed, 26 Jun 2024 01:19:43 +0300 Subject: [PATCH 1/5] feat: add useScrollTo --- src/hooks/index.ts | 1 + src/hooks/useScrollTo/useScrollTo.demo.tsx | 31 ++++++++++++++ src/hooks/useScrollTo/useScrollTo.test.ts | 47 ++++++++++++++++++++++ src/hooks/useScrollTo/useScrollTo.ts | 38 +++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 src/hooks/useScrollTo/useScrollTo.demo.tsx create mode 100644 src/hooks/useScrollTo/useScrollTo.test.ts create mode 100644 src/hooks/useScrollTo/useScrollTo.ts diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 82aca5a9..b724435d 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -55,6 +55,7 @@ export { useRenderCount } from './useRenderCount/useRenderCount'; export { useRenderInfo } from './useRenderInfo/useRenderInfo'; export { useRerender } from './useRerender/useRerender'; export { useScript } from './useScript/useScript'; +export { useScrollTo } from './useScrollTo/useScrollTo'; export { useSessionStorage } from './useSessionStorage/useSessionStorage'; export { useSet } from './useSet/useSet'; export { useShare } from './useShare/useShare'; diff --git a/src/hooks/useScrollTo/useScrollTo.demo.tsx b/src/hooks/useScrollTo/useScrollTo.demo.tsx new file mode 100644 index 00000000..0f32e4d6 --- /dev/null +++ b/src/hooks/useScrollTo/useScrollTo.demo.tsx @@ -0,0 +1,31 @@ +import { useScrollTo } from "@/hooks/useScrollTo/useScrollTo"; + +const cardStyle = { + border: '1px solid gray', + height: 300, + width: 300, +} + +const Demo = () => { + const {targetToScroll, scrollToTarget} = useScrollTo(); + + const handleClick = (event: React.MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + scrollToTarget(); + }; + + + return ( + <> + +
+
Block 1
+
Block 2
+
Block 3
+
+ + ) +} + +export default Demo \ No newline at end of file diff --git a/src/hooks/useScrollTo/useScrollTo.test.ts b/src/hooks/useScrollTo/useScrollTo.test.ts new file mode 100644 index 00000000..3e5b0c56 --- /dev/null +++ b/src/hooks/useScrollTo/useScrollTo.test.ts @@ -0,0 +1,47 @@ +import { act, renderHook } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; + +import { useScrollTo } from './useScrollTo'; + +describe('useScrollTo', () => { + it('should define scrollTo and targetRef', () => { + const { result } = renderHook(() => useScrollTo()); + + expect(result.current.scrollToTarget).toBeDefined(); + expect(result.current.targetToScroll).toBeDefined(); + }); + + it('should scroll to target element', () => { + const { result } = renderHook(() => useScrollTo()); + const scrollIntoViewMock = vi.fn(); + + const mockElement = document.createElement('div'); + mockElement.scrollIntoView = scrollIntoViewMock; + + act(() => { + (result.current.targetToScroll as React.MutableRefObject).current = + mockElement; + }); + + act(() => { + result.current.scrollToTarget(); + }); + + expect(scrollIntoViewMock).toHaveBeenCalledWith({ + behavior: 'smooth', + block: 'nearest', + inline: 'nearest' + }); + }); + + it('should not scroll if targetRef is not set', () => { + const { result } = renderHook(() => useScrollTo()); + const scrollIntoViewMock = vi.fn(); + + act(() => { + result.current.scrollToTarget(); + }); + + expect(scrollIntoViewMock).not.toHaveBeenCalled(); + }); +}); diff --git a/src/hooks/useScrollTo/useScrollTo.ts b/src/hooks/useScrollTo/useScrollTo.ts new file mode 100644 index 00000000..275bb780 --- /dev/null +++ b/src/hooks/useScrollTo/useScrollTo.ts @@ -0,0 +1,38 @@ +import { useRef } from 'react'; + +const OPTIONS_DEFAULT: ScrollIntoViewOptions = { + behavior: 'smooth', + block: 'nearest', + inline: 'nearest' +}; + +interface UseScrollToReturn { + targetToScroll: React.RefObject; + scrollToTarget: () => void; +} + +/** + * @name useScrollTo + * @description Hook that provides a function to smoothly scroll to a target element. + * + * @param {ScrollIntoViewOptions} [options=OPTIONS_DEFAULT] - Options for the scrollIntoView method. + * + * @returns {Object} An object containing the reference to the target element and the function to scroll to it. + * @returns {React.RefObject} targetToScroll - The ref object to be attached to the element you want to scroll to. + * @returns {function} scrollToTarget - The function to call to scroll to the target element. + * + * @example + * const { targetToScroll, scrollToTarget } = useScrollTo(); + */ +export const useScrollTo = ( + options: ScrollIntoViewOptions = OPTIONS_DEFAULT +): UseScrollToReturn => { + const targetToScroll = useRef(null); + + const scrollToTarget = () => { + if (!targetToScroll.current) return; + targetToScroll.current.scrollIntoView(options); + }; + + return { targetToScroll, scrollToTarget }; +}; From 3554e4e1d3d10aab19a99df32887463457749aa7 Mon Sep 17 00:00:00 2001 From: zeroqs Date: Wed, 26 Jun 2024 01:29:02 +0300 Subject: [PATCH 2/5] docs: add description for options --- src/hooks/useScrollTo/useScrollTo.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/hooks/useScrollTo/useScrollTo.ts b/src/hooks/useScrollTo/useScrollTo.ts index 275bb780..ae1e3f5b 100644 --- a/src/hooks/useScrollTo/useScrollTo.ts +++ b/src/hooks/useScrollTo/useScrollTo.ts @@ -1,8 +1,26 @@ import { useRef } from 'react'; const OPTIONS_DEFAULT: ScrollIntoViewOptions = { + /** + * Defines the transition animation. + * One of 'auto' or 'smooth'. + * + * @default 'smooth' + */ behavior: 'smooth', + /** + * Defines vertical alignment. + * One of `'start'`, `'center'`, `'end'`, or `'nearest'` + * + * @default 'nearest' + */ block: 'nearest', + /** + * Defines horizontal alignment. + * One of `start`, `center`, `end`, or `nearest`. Defaults to nearest. + * + * @default 'nearest' + */ inline: 'nearest' }; From 5e94b441879c4b90e5004ebb80a265d97ec66864 Mon Sep 17 00:00:00 2001 From: Nikita <94167692+zeroqs@users.noreply.github.com> Date: Wed, 26 Jun 2024 01:33:04 +0300 Subject: [PATCH 3/5] fix: fix style naming --- src/hooks/useScrollTo/useScrollTo.demo.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hooks/useScrollTo/useScrollTo.demo.tsx b/src/hooks/useScrollTo/useScrollTo.demo.tsx index 0f32e4d6..6bb0e6d1 100644 --- a/src/hooks/useScrollTo/useScrollTo.demo.tsx +++ b/src/hooks/useScrollTo/useScrollTo.demo.tsx @@ -1,6 +1,6 @@ import { useScrollTo } from "@/hooks/useScrollTo/useScrollTo"; -const cardStyle = { +const blockStyle = { border: '1px solid gray', height: 300, width: 300, @@ -20,12 +20,12 @@ const Demo = () => { <>
-
Block 1
-
Block 2
-
Block 3
+
Block 1
+
Block 2
+
Block 3
) } -export default Demo \ No newline at end of file +export default Demo From 2f6ae2c06a3cfc6207d882c9d025f8b4fa1d3a3c Mon Sep 17 00:00:00 2001 From: zeroqs Date: Wed, 26 Jun 2024 01:42:45 +0300 Subject: [PATCH 4/5] docs: add hook to docs.md --- docs/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/index.md b/docs/index.md index 0f91acea..8991411b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -185,6 +185,9 @@ features: - title: useShare details: Hook that utilize the Web Share API link: /functions/hooks/useShare +- title: useScrollTo + details: Hook that allows scrolling to a specified HTML element + link: /functions/hooks/useScrollTo - title: useTextSelection details: Hook that manages the text selection link: /functions/hooks/useTextSelection From 93b3c939120ee37faa73f635fbc5d64691ff74b2 Mon Sep 17 00:00:00 2001 From: Nikita <94167692+zeroqs@users.noreply.github.com> Date: Wed, 26 Jun 2024 01:46:14 +0300 Subject: [PATCH 5/5] fix: fix styling --- src/hooks/useScrollTo/useScrollTo.demo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useScrollTo/useScrollTo.demo.tsx b/src/hooks/useScrollTo/useScrollTo.demo.tsx index 6bb0e6d1..6e40a61a 100644 --- a/src/hooks/useScrollTo/useScrollTo.demo.tsx +++ b/src/hooks/useScrollTo/useScrollTo.demo.tsx @@ -23,7 +23,7 @@ const Demo = () => {
Block 1
Block 2
Block 3
- + ) }