Skip to content

Commit b490b58

Browse files
committed
Adding ref scroll hook
1 parent 905fe52 commit b490b58

File tree

9 files changed

+226
-64
lines changed

9 files changed

+226
-64
lines changed

.babelrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,8 @@
66
"targets": "> 0.25%, not dead"
77
}
88
]
9+
],
10+
"plugins": [
11+
"@babel/plugin-transform-react-jsx-compat"
912
]
10-
}
13+
}

README.md

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,72 @@ npm install react-use-scroll-navigate
77
```
88

99
## Usage
10+
### useScrollNavigate
1011
```jsx
1112
import useScrollNavigate from 'react-use-scroll-navigate';
1213

1314
const App = () => {
14-
15-
const navgiate = useScrollNavigate();
15+
16+
const { scrollNavigateError, scrollNavigate } = useScrollNavigate();
1617

1718
return (
1819
<div>
19-
<button onClick={ ()=> {navgiate('/') } )}>Go to homepage</button>
20+
<button onClick={ ()=> {
21+
scrollNavigate('/'); //It will navigate & scroll to the top !
22+
}}>
23+
Go to homepage!
24+
</button>
2025
</div>
2126
);
2227
};
2328
```
2429

30+
### NavigationRef
31+
```jsx
32+
33+
//Main app
34+
35+
createRoot(document.getElementById("root")).render(
36+
<StrictMode>
37+
<BrowserRouter>
38+
<NavigateContextProvider> {/*Ref navigation scroll navigation works with context*/}
39+
<App /> {/*here is the rooter */}
40+
</NavigateContextProvider>
41+
</BrowserRouter>
42+
</StrictMode>
43+
)
44+
45+
```
46+
```jsx
47+
48+
//On one page
49+
50+
export default () => {
51+
const { navigateToRef } = useNavigateContext();
52+
53+
return (
54+
<Fragment>
55+
<h1>About</h1>
56+
<button onClick={() => navigateToRef("/")}>Home</button>
57+
</Fragment>
58+
)
59+
}
60+
```
61+
62+
```jsx
63+
// On another page
64+
export default () => {
65+
const { navigationRef } = useNavigateContext();
66+
67+
return (
68+
<Fragment>
69+
<h1>Home</h1>
70+
<div ref={navigationRef} />
71+
</Fragment>
72+
)
73+
}
74+
```
75+
2576
## License
2677
[MIT](https://choosealicense.com/licenses/mit/)
2778

@@ -32,4 +83,5 @@ For major changes, please open an issue first to discuss what you would like to
3283

3384

3485
## Authors and acknowledgment
35-
- [Alexandre BAUDRY](https://github.com/Alexandrebdry)
86+
- [Alexandre BAUDRY](https://github.com/Alexandrebdry)
87+
- [Amin NAIRI](https://github.com/aminnairi)

package-lock.json

Lines changed: 52 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
"name": "react-use-scroll-navgiate",
33
"version": "1.1.0",
44
"description": "A react hook to scroll to the top of the page when navigate to another one",
5-
"main": "cjs/index.js",
6-
"module": "esm/index.js",
5+
"main": "cjs/index.jsx",
6+
"module": "esm/index.jsx",
77
"scripts": {
88
"build": "rollup -c",
99
"release": "standard-version",
@@ -32,15 +32,16 @@
3232
],
3333
"devDependencies": {
3434
"@babel/core": "^7.19.3",
35+
"@babel/plugin-transform-react-jsx-compat": "^7.18.6",
3536
"@babel/preset-env": "^7.19.3",
37+
"@rollup/plugin-babel": "^5.3.0",
38+
"@rollup/plugin-commonjs": "^19.0.2",
39+
"@rollup/plugin-replace": "^3.1.0",
3640
"react": "^18.2.0",
3741
"react-router-dom": "^6.4.2",
3842
"react-test-renderer": "^18.2.0",
3943
"rollup": "^2.79.1",
40-
"@rollup/plugin-babel": "^5.3.0",
41-
"@rollup/plugin-commonjs": "^19.0.2",
42-
"@rollup/plugin-replace": "^3.1.0",
43-
"standard-version": "^9.5.0",
44+
"standard-version": "^9.5.0"
4445
},
4546
"peerDependencies": {
4647
"react-router-dom": "^6.4.2"

rollup.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import commonjs from "@rollup/plugin-commonjs";
44

55

66
export default {
7-
input: './src/index.js',
7+
input: './src/index.jsx',
88
output: [
99
{
10-
file: 'cjs/index.js',
10+
file: 'cjs/index.jsx',
1111
format: 'cjs',
1212
name:"useScrollNavigate",
1313
globals: {

src/errors/useScrollNavigateCoordinateError.js

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/errors/useScrollNavigatePathError.js

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/index.js

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/index.jsx

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import {useNavigate} from "react-router-dom";
2+
import {createContext, useCallback, useContext, useLayoutEffect, useMemo, useRef, useState} from "react";
3+
4+
5+
export class ScrollNavigatePathError extends Error {
6+
constructor(...params) {
7+
super(params);
8+
this.name = "ScrollNavigatePathError" ;
9+
}
10+
}
11+
export class ScrollNavigateLeftError extends Error {
12+
constructor(...parameters) {
13+
super(parameters)
14+
this.name = "ScrollNavigateLeftError"
15+
}
16+
}
17+
18+
export class ScrollNavigateTopError extends Error {
19+
constructor(...parameters) {
20+
super(parameters)
21+
this.name = "ScrollNavigateTopError"
22+
}
23+
}
24+
25+
/**
26+
*
27+
* React hook to redirect to a new page and scroll to somewhere on the page
28+
* It scrolls to the top by default
29+
*
30+
* @param {number} top - The y position to scroll to from top - default = 0 - must be between 0 and 100
31+
* @param {number} left - The x position to scroll to from left - default = 0 - must be between 0 and 100
32+
* @param {string} path - The path to navigate to - default = /
33+
*/
34+
export function useScrollNavigate(path = "/", top = 0 , left = 0 ) {
35+
36+
const navigate = useNavigate();
37+
const [scrollNavigateError, setScrollNavigateError] = useState() ;
38+
const scrollNavigate = useCallback( (path, top, left) => {
39+
if (typeof path != "string") {
40+
setScrollNavigateError(new ScrollNavigatePathError("Path is not a string")) ;
41+
return
42+
}
43+
if (typeof top !== "number") {
44+
setScrollNavigateError(new ScrollNavigateTopError("Top is not a number"))
45+
return
46+
}
47+
if (top > 100 || top < 0) {
48+
setScrollNavigateError(new ScrollNavigateLeftError("Top isn't between 0 and 100"))
49+
}
50+
if(typeof left !== "number") {
51+
setScrollNavigateError(new ScrollNavigateTopError("Left is not a number"))
52+
return
53+
}
54+
if (left > 100 || left < 0) {
55+
setScrollNavigateError(new ScrollNavigateLeftError("Left isn't between 0 and 100"))
56+
}
57+
setScrollNavigateError(false);
58+
navigate(path);
59+
60+
window.scroll({left,top,behavior: 'smooth'}) ;
61+
62+
},[navigate, setScrollNavigateError]);
63+
64+
return {
65+
scrollNavigate,
66+
scrollNavigateError
67+
}
68+
}
69+
70+
/** Scroll to a html ref */
71+
export const NavigateContext = createContext();
72+
export const NavigateContextProvider = ({children}) => {
73+
const navigate = useNavigate();
74+
const [navigationBeacon, setNavigationBeacon] = useState(false) ;
75+
const navigationRef = useRef() ;
76+
77+
const navigateToRef = useCallback((path) => {
78+
navigate(path) ;
79+
setNavigationBeacon(Symbol());
80+
81+
},[navigate, setNavigationBeacon]);
82+
83+
const value = useMemo(() => {navigationRef, navigateToRef},
84+
[navigationRef,navigateToRef()]);
85+
86+
useLayoutEffect(() => {
87+
if (navigationBeacon === false )return
88+
if(navigationRef.current instanceof HTMLElement) {
89+
const {left,top} = navigationRef.current.getBoundingClientRect();
90+
window.scroll({left,top,behavior:'smooth'});
91+
}
92+
setNavigationBeacon(false) ;
93+
},[navigationBeacon,navigationRef,setNavigationBeacon]);
94+
95+
return (
96+
<NavigateContext.Provider value={value}>
97+
{children}
98+
</NavigateContext.Provider>
99+
)
100+
}
101+
102+
export const useNavigationContext = () => useContext(NavigateContext) ;
103+
104+
105+

0 commit comments

Comments
 (0)