router-kit 0.2.5 → 1.0.2
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 +21 -15
- package/dist/context/RouterProvider.js +44 -16
- package/dist/hooks/useLocation.d.ts +2 -0
- package/dist/hooks/useLocation.js +16 -0
- package/dist/hooks/{hook.d.ts → useParams.d.ts} +0 -3
- package/dist/hooks/{hook.js → useParams.js} +0 -12
- package/dist/hooks/useQuery.d.ts +3 -0
- package/dist/hooks/useQuery.js +10 -0
- package/dist/hooks/useRouter.js +3 -7
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,16 @@ npm install router-kit
|
|
|
41
41
|
|
|
42
42
|
N.B. `react` et `react-dom` sont des peerDependencies ; installez-les dans votre projet si nécessaire.
|
|
43
43
|
|
|
44
|
+
## Important
|
|
45
|
+
|
|
46
|
+
⚠️ Tous les hooks et composants de router-kit doivent être utilisés à l'intérieur du `RouterProvider`. Assurez-vous de wrapper votre application avec le `RouterProvider` au plus haut niveau possible.
|
|
47
|
+
|
|
48
|
+
Si vous utilisez des composants ou hooks en dehors du `RouterProvider`, vous obtiendrez une erreur explicite :
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
RouterKit: Common hooks and components must be used within the RouterProvider returned by createRouter(). Wrap your app with the RouterProvider.
|
|
52
|
+
```
|
|
53
|
+
|
|
44
54
|
## Concepts clés
|
|
45
55
|
|
|
46
56
|
- Route : objet avec `path` (string) et `component` (JSX.Element). Les `children` sont supportés pour construire des arborescences.
|
|
@@ -112,33 +122,29 @@ Exemple :
|
|
|
112
122
|
- `useRouter()` : hook interne retournant le contexte `{ path, fullPathWithParams, navigate }`. Lance une erreur si utilisé hors du provider.
|
|
113
123
|
- `useParams()` : renvoie un objet clé/valeur pour les segments paramétrés de la route (ex: `{ id: "42" }`). Se base sur `fullPathWithParams` et `path`.
|
|
114
124
|
- `useQuery()` : parse `window.location.search` et renvoie un objet `{ [key]: value }`.
|
|
125
|
+
- `useLocation()` : renvoie un objet avec les informations de localisation courante : `{ pathname, search, hash, state }`. Utile pour accéder aux détails de l'URL actuelle.
|
|
115
126
|
|
|
116
127
|
## Exemple complet
|
|
117
128
|
|
|
118
129
|
```tsx
|
|
119
130
|
import React from "react";
|
|
120
|
-
import { createRouter, RouterProvider
|
|
131
|
+
import { createRouter, RouterProvider } from "router-kit";
|
|
121
132
|
|
|
122
|
-
const Home = <div>Accueil</div>;
|
|
123
|
-
const About = <div>À propos</div>;
|
|
133
|
+
const Home = () => <div>Accueil</div>;
|
|
134
|
+
const About = () => <div>À propos</div>;
|
|
124
135
|
|
|
125
136
|
const routes = createRouter([
|
|
126
|
-
{ path: "/", component: Home },
|
|
127
|
-
{ path: "about", component: About },
|
|
137
|
+
{ path: "/", component: <Home /> },
|
|
138
|
+
{ path: "about", component: <About /> },
|
|
128
139
|
{ path: "/404", component: <div>Not Found</div> },
|
|
129
140
|
]);
|
|
130
141
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<nav>
|
|
135
|
-
<Link to="/">Home</Link>
|
|
136
|
-
<Link to="/about">About</Link>
|
|
137
|
-
</nav>
|
|
138
|
-
<RouterProvider routes={routes} />
|
|
139
|
-
</div>
|
|
140
|
-
);
|
|
142
|
+
// Les composants de navigation doivent être à l'intérieur du RouterProvider
|
|
143
|
+
function App() {
|
|
144
|
+
return <RouterProvider routes={routes} />;
|
|
141
145
|
}
|
|
146
|
+
|
|
147
|
+
export default App;
|
|
142
148
|
```
|
|
143
149
|
|
|
144
150
|
## Routes et 404
|
|
@@ -3,10 +3,33 @@ import { useEffect, useState } from "react";
|
|
|
3
3
|
import join from "url-join";
|
|
4
4
|
import Page404 from "../pages/404";
|
|
5
5
|
import RouterContext from "./RouterContext";
|
|
6
|
+
const validateUrl = (url) => {
|
|
7
|
+
try {
|
|
8
|
+
new URL(url, window.location.origin);
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
6
15
|
const RouterProvider = ({ routes }) => {
|
|
7
|
-
const [path, setPath] = useState(
|
|
8
|
-
|
|
16
|
+
const [path, setPath] = useState("");
|
|
17
|
+
const [fullPathWithParams, setFullPathWithParams] = useState("");
|
|
9
18
|
let page404 = null;
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
setPath(window.location.pathname);
|
|
21
|
+
const handleLocationChange = () => {
|
|
22
|
+
setPath(window.location.pathname);
|
|
23
|
+
};
|
|
24
|
+
window.addEventListener("popstate", handleLocationChange);
|
|
25
|
+
window.addEventListener("pushState", handleLocationChange);
|
|
26
|
+
window.addEventListener("replaceState", handleLocationChange);
|
|
27
|
+
return () => {
|
|
28
|
+
window.removeEventListener("popstate", handleLocationChange);
|
|
29
|
+
window.removeEventListener("pushState", handleLocationChange);
|
|
30
|
+
window.removeEventListener("replaceState", handleLocationChange);
|
|
31
|
+
};
|
|
32
|
+
}, []);
|
|
10
33
|
const pathValidation = (routeFullPath, currentPath) => {
|
|
11
34
|
const routePaths = routeFullPath.split("|");
|
|
12
35
|
for (const routePath of routePaths) {
|
|
@@ -39,7 +62,9 @@ const RouterProvider = ({ routes }) => {
|
|
|
39
62
|
}
|
|
40
63
|
const fullPath = join(parentPath, `/${route.path}`);
|
|
41
64
|
if (pathValidation(fullPath, currentPath)) {
|
|
42
|
-
fullPathWithParams
|
|
65
|
+
if (fullPath !== fullPathWithParams) {
|
|
66
|
+
setFullPathWithParams(fullPath);
|
|
67
|
+
}
|
|
43
68
|
return route.component;
|
|
44
69
|
}
|
|
45
70
|
if (route.children) {
|
|
@@ -50,23 +75,26 @@ const RouterProvider = ({ routes }) => {
|
|
|
50
75
|
}
|
|
51
76
|
return null;
|
|
52
77
|
};
|
|
53
|
-
fullPathWithParams = "";
|
|
54
|
-
const matchedComponent = getComponent(routes, path);
|
|
55
|
-
const component = matchedComponent !== null && matchedComponent !== void 0 ? matchedComponent : (page404 || _jsx(Page404, {}));
|
|
56
78
|
const navigate = (to, options) => {
|
|
57
|
-
if (
|
|
58
|
-
|
|
79
|
+
if (!validateUrl(to)) {
|
|
80
|
+
console.error(`RouterKit: Invalid URL "${to}"`);
|
|
81
|
+
return;
|
|
59
82
|
}
|
|
60
|
-
|
|
61
|
-
|
|
83
|
+
try {
|
|
84
|
+
if (options === null || options === void 0 ? void 0 : options.replace) {
|
|
85
|
+
window.history.replaceState((options === null || options === void 0 ? void 0 : options.state) || {}, "", to);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
window.history.pushState((options === null || options === void 0 ? void 0 : options.state) || {}, "", to);
|
|
89
|
+
}
|
|
90
|
+
setPath(to);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
console.error("RouterKit: Navigation failed", error);
|
|
62
94
|
}
|
|
63
|
-
setPath(to);
|
|
64
95
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
window.addEventListener("popstate", handlePop);
|
|
68
|
-
return () => window.removeEventListener("popstate", handlePop);
|
|
69
|
-
}, []);
|
|
96
|
+
const matchedComponent = getComponent(routes, path);
|
|
97
|
+
const component = matchedComponent !== null && matchedComponent !== void 0 ? matchedComponent : (page404 || _jsx(Page404, {}));
|
|
70
98
|
return (_jsx(RouterContext.Provider, { value: { path, fullPathWithParams, navigate }, children: component }));
|
|
71
99
|
};
|
|
72
100
|
export default RouterProvider;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function useLocation() {
|
|
2
|
+
if (typeof window === "undefined") {
|
|
3
|
+
return {
|
|
4
|
+
pathname: "",
|
|
5
|
+
search: "",
|
|
6
|
+
hash: "",
|
|
7
|
+
state: null,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
pathname: window.location.pathname,
|
|
12
|
+
search: window.location.search,
|
|
13
|
+
hash: window.location.hash,
|
|
14
|
+
state: window.history.state,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useRouter } from "./useRouter";
|
|
2
|
-
// Retourne un objet { [paramName]: value }
|
|
3
2
|
export const useParams = () => {
|
|
4
3
|
const { path, fullPathWithParams } = useRouter();
|
|
5
4
|
const params = {};
|
|
@@ -14,14 +13,3 @@ export const useParams = () => {
|
|
|
14
13
|
});
|
|
15
14
|
return params;
|
|
16
15
|
};
|
|
17
|
-
// Parse la query string proprement (ex: ?a=1&b=2)
|
|
18
|
-
export const useQuery = () => {
|
|
19
|
-
const query = {};
|
|
20
|
-
if (typeof window === "undefined")
|
|
21
|
-
return query;
|
|
22
|
-
const usp = new URLSearchParams(window.location.search);
|
|
23
|
-
usp.forEach((value, key) => {
|
|
24
|
-
query[key] = value;
|
|
25
|
-
});
|
|
26
|
-
return query;
|
|
27
|
-
};
|
package/dist/hooks/useRouter.js
CHANGED
|
@@ -27,14 +27,10 @@ import RouterContext from "../context/RouterContext";
|
|
|
27
27
|
export function useRouter() {
|
|
28
28
|
const ctx = useContext(RouterContext);
|
|
29
29
|
if (!ctx) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
console.error("%cRouterKit%c " + message, "color: #fff; background: #d9534f; font-weight: 700; padding: 2px 6px; border-radius: 3px;", "color: #d9534f;");
|
|
30
|
+
if (typeof window === "undefined") {
|
|
31
|
+
throw new Error("RouterKit: useRouter cannot be used during server side rendering");
|
|
33
32
|
}
|
|
34
|
-
|
|
35
|
-
console.error("RouterKit: " + message);
|
|
36
|
-
}
|
|
37
|
-
throw new Error("RouterKit: " + message);
|
|
33
|
+
throw new Error("RouterKit: useRouter must be used within RouterProvider");
|
|
38
34
|
}
|
|
39
35
|
return ctx;
|
|
40
36
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,6 @@ export { default as Link } from "./components/Link";
|
|
|
2
2
|
export { default as NavLink } from "./components/NavLink";
|
|
3
3
|
export { default as RouterProvider } from "./context/RouterProvider";
|
|
4
4
|
export { default as createRouter } from "./core/createRouter";
|
|
5
|
-
export {
|
|
5
|
+
export { useLocation } from "./hooks/useLocation";
|
|
6
|
+
export { useParams } from "./hooks/useParams";
|
|
7
|
+
export { useQuery } from "./hooks/useQuery";
|
package/dist/index.js
CHANGED
|
@@ -2,4 +2,6 @@ export { default as Link } from "./components/Link";
|
|
|
2
2
|
export { default as NavLink } from "./components/NavLink";
|
|
3
3
|
export { default as RouterProvider } from "./context/RouterProvider";
|
|
4
4
|
export { default as createRouter } from "./core/createRouter";
|
|
5
|
-
export {
|
|
5
|
+
export { useLocation } from "./hooks/useLocation";
|
|
6
|
+
export { useParams } from "./hooks/useParams";
|
|
7
|
+
export { useQuery } from "./hooks/useQuery";
|
package/package.json
CHANGED