router-kit 0.1.3 → 0.1.5

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mohammed Ben Cheikh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,180 @@
1
+ # Router Kit
2
+
3
+ Un petit fournisseur de routing pour React, minimal et léger, créé par Mohammed Ben Cheikh.
4
+
5
+ Ce README documente l'utilisation publique du package `router-kit` : installation, API, exemples d'utilisation et bonnes pratiques.
6
+
7
+ ## Table des matières
8
+
9
+ - Introduction
10
+ - Installation
11
+ - Concepts clés
12
+ - API publique
13
+ - `createRouter(routes)`
14
+ - `<RouterProvider routes={...} />`
15
+ - `<Link to="...">` et `<NavLink to="...">`
16
+ - Hooks : `useParams()`, `useQuery()` et `useRouter()`
17
+ - Exemple d'utilisation
18
+ - Routes et 404
19
+ - Développement
20
+ - Contribuer
21
+ - Licence
22
+
23
+ ## Introduction
24
+
25
+ `router-kit` fournit un routeur côté client très simple pour les applications React. Il ne dépend que de React et d'une petite utilité `url-join` pour composer les chemins.
26
+
27
+ Le routeur :
28
+
29
+ - Résout les composants en fonction du `window.location.pathname`.
30
+ - Expose un contexte pour naviguer (`navigate`) et connaître le `path` courant.
31
+ - Prend en charge des paramètres de route de type `/:id` et l'extraction via `useParams()`.
32
+ - Fournit un 404 configurable.
33
+
34
+ ## Installation
35
+
36
+ Installer en tant que dépendance (ex : npm) :
37
+
38
+ ```bash
39
+ npm install router-kit
40
+ ```
41
+
42
+ N.B. `react` et `react-dom` sont des peerDependencies ; installez-les dans votre projet si nécessaire.
43
+
44
+ ## Concepts clés
45
+
46
+ - Route : objet avec `path` (string) et `component` (JSX.Element). Les `children` sont supportés pour construire des arborescences.
47
+ - `createRouter(routes)` : normalise les chemins (supprime les slashs initiaux) et retourne la structure de routes.
48
+ - `RouterProvider` : fournit le contexte et rend le composant correspondant au `path` courant.
49
+ - `navigate(to, { replace })` : change l'URL en utilisant l'API History et met à jour le rendu.
50
+
51
+ ## API publique
52
+
53
+ Voici l'API exposée par le package (extraits depuis `src/index.ts`).
54
+
55
+ - export { default as Link } from "./components/Link";
56
+ - export { default as NavLink } from "./components/NavLink";
57
+ - export { default as RouterProvider } from "./context/RouterProvider";
58
+ - export { default as createRouter } from "./core/createRouter";
59
+ - export { useParams, useQuery } from "./hooks/hook";
60
+
61
+ ### createRouter(routes)
62
+
63
+ Fonction d'aide qui normalise une liste de routes. Elle supprime les slashs initiaux dans les `path` et renvoie la structure prête à être passée à `RouterProvider`.
64
+
65
+ Signature :
66
+
67
+ ```ts
68
+ createRouter(routes: Route[]): Route[]
69
+ ```
70
+
71
+ ### RouterProvider
72
+
73
+ Composant qui prend une prop `routes` (Route[]) et rend le composant correspondant à l'URL actuelle.
74
+
75
+ Usage :
76
+
77
+ ```tsx
78
+ import { RouterProvider } from "router-kit";
79
+
80
+ const routes = createRouter([
81
+ { path: "/", component: <Home /> },
82
+ { path: "users/:id", component: <User /> },
83
+ { path: "/404", component: <NotFound /> },
84
+ ]);
85
+
86
+ function App() {
87
+ return <RouterProvider routes={routes} />;
88
+ }
89
+ ```
90
+
91
+ Le provider expose via le contexte :
92
+
93
+ - `path` : le pathname courant (ex: `/users/42`)
94
+ - `fullPathWithParams` : le chemin défini dans la route incluant les paramètres (ex: `/users/:id`)
95
+ - `navigate(to: string, options?: { replace?: boolean })`
96
+
97
+ ### Link et NavLink
98
+
99
+ `<Link to="...">` : rend un lien <a> qui empêche le comportement par défaut et appelle `navigate(to)`.
100
+
101
+ `<NavLink to="..." activeClassName="...">` : comme `Link` mais ajoute `activeClassName` quand la route est active (comparaison stricte `path === to`).
102
+
103
+ Exemple :
104
+
105
+ ```tsx
106
+ <Link to="/about">À propos</Link>
107
+ <NavLink to="/">Accueil</NavLink>
108
+ ```
109
+
110
+ ### Hooks
111
+
112
+ - `useRouter()` : hook interne retournant le contexte `{ path, fullPathWithParams, navigate }`. Lance une erreur si utilisé hors du provider.
113
+ - `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
+ - `useQuery()` : parse `window.location.search` et renvoie un objet `{ [key]: value }`.
115
+
116
+ ## Exemple complet
117
+
118
+ ```tsx
119
+ import React from "react";
120
+ import { createRouter, RouterProvider, Link } from "router-kit";
121
+
122
+ const Home = <div>Accueil</div>;
123
+ const About = <div>À propos</div>;
124
+
125
+ const routes = createRouter([
126
+ { path: "/", component: Home },
127
+ { path: "about", component: About },
128
+ { path: "/404", component: <div>Not Found</div> },
129
+ ]);
130
+
131
+ export default function App() {
132
+ return (
133
+ <div>
134
+ <nav>
135
+ <Link to="/">Home</Link>
136
+ <Link to="/about">About</Link>
137
+ </nav>
138
+ <RouterProvider routes={routes} />
139
+ </div>
140
+ );
141
+ }
142
+ ```
143
+
144
+ ## Routes et 404
145
+
146
+ Le provider recherche les routes et compare le `fullPath` de chaque route avec le pathname courant en remplaçant dynamiquement les segments commençant par `:` (ex: `/:id`).
147
+
148
+ Pour afficher une page 404 personnalisée, ajoutez une route avec `path: "/404"` et `component` : elle sera utilisée par défaut quand aucune route ne matche.
149
+
150
+ ## Développement
151
+
152
+ Scripts disponibles (définis dans `package.json`) :
153
+
154
+ - `npm run build` : compile TypeScript vers `dist/` (utilise `tsc`).
155
+ - `npm run typecheck` : vérifie les types sans émettre de fichiers.
156
+ - `npm run clean` : supprime `dist`.
157
+
158
+ Pour développer localement :
159
+
160
+ 1. Cloner le dépôt et installer les dépendances.
161
+ 2. Lancer `npm run build:watch` si vous modifiez le package et voulez recompiler automatiquement.
162
+
163
+ ## Contribuer
164
+
165
+ Les contributions sont bienvenues. Pour des petites améliorations :
166
+
167
+ 1. Ouvrir une issue décrivant le problème ou la fonctionnalité.
168
+ 2. Soumettre une PR avec un seul changement logique par PR.
169
+
170
+ Propositions d'améliorations possibles :
171
+
172
+ - Support d'URL basées sur hash (/#/path).
173
+ - Support plus riche du matching (wildcards, regex, exact/partial).
174
+ - Tests unitaires et CI.
175
+
176
+ ## Licence
177
+
178
+ MIT — voir le fichier `LICENSE`.
179
+
180
+ ---
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRouter } from "./useRouter";
2
+ import { useRouter } from "../hooks/useRouter";
3
3
  function Link({ to, children, className, }) {
4
4
  const { navigate } = useRouter();
5
5
  return (_jsx("a", { onClick: (e) => {
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRouter } from "./useRouter";
2
+ import { useRouter } from "../hooks/useRouter";
3
3
  function NavLink({ to, children, className, activeClassName = "active", }) {
4
4
  const { navigate, path } = useRouter();
5
5
  const isActive = path === to;
@@ -1,3 +1,3 @@
1
- import type { RouterContextType } from "./types";
1
+ import type { RouterContextType } from "../types";
2
2
  declare const RouterContext: import("react").Context<RouterContextType | undefined>;
3
3
  export default RouterContext;
@@ -0,0 +1,2 @@
1
+ declare const RouterProvider: () => import("react/jsx-runtime").JSX.Element;
2
+ export default RouterProvider;
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
3
  import join from "url-join";
4
- import Page404 from "./pages/404";
4
+ import Page404 from "../pages/404";
5
5
  import RouterContext from "./RouterContext";
6
- const RouterProvider = ({ routes }) => {
6
+ import { router } from "../core/createRouter";
7
+ const RouterProvider = () => {
7
8
  const [path, setPath] = useState(window.location.pathname);
8
9
  let fullPathWithParams = "";
9
10
  const pathValidation = (fullPath, path) => {
@@ -41,7 +42,7 @@ const RouterProvider = ({ routes }) => {
41
42
  }
42
43
  return component;
43
44
  };
44
- const component = getComponent(routes, path);
45
+ const component = getComponent(router, path);
45
46
  const navigate = (to, options) => {
46
47
  if (options && options.replace) {
47
48
  window.history.replaceState({}, "", to);
@@ -0,0 +1,4 @@
1
+ import type { Route } from "../types";
2
+ export declare let router: Route[];
3
+ declare function createRouter(routes: Route[]): void;
4
+ export default createRouter;
@@ -1,9 +1,10 @@
1
- // Normalize routes: remove leading slashes from paths and normalize children recursively
1
+ export let router = [];
2
2
  function normalizeRoutes(routes) {
3
- return routes.map((route) => {
4
- const normalizedPath = route.path.startsWith("/")
3
+ const normalizedRoutes = routes.map((route) => {
4
+ var _a, _b;
5
+ const normalizedPath = ((_a = route.path) === null || _a === void 0 ? void 0 : _a.startsWith("/"))
5
6
  ? route.path.replace(/^\/+/, "")
6
- : route.path;
7
+ : (_b = route.path) !== null && _b !== void 0 ? _b : "";
7
8
  const normalized = {
8
9
  ...route,
9
10
  path: normalizedPath,
@@ -13,8 +14,10 @@ function normalizeRoutes(routes) {
13
14
  }
14
15
  return normalized;
15
16
  });
17
+ router = normalizedRoutes;
18
+ return normalizedRoutes;
16
19
  }
17
20
  function createRouter(routes) {
18
- return normalizeRoutes(routes);
21
+ normalizeRoutes(routes);
19
22
  }
20
23
  export default createRouter;
@@ -0,0 +1 @@
1
+ export declare function useRouter(): import("../types").RouterContextType;
@@ -1,5 +1,5 @@
1
1
  import { useContext } from "react";
2
- import RouterContext from "./RouterContext";
2
+ import RouterContext from "../context/RouterContext";
3
3
  export function useRouter() {
4
4
  const ctx = useContext(RouterContext);
5
5
  if (!ctx)
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { default as createRouter } from "./createRouter";
2
- export { useParams, useQuery } from "./hook";
3
- export { default as Link } from "./Link";
4
- export { default as NavLink } from "./NavLink";
5
- export { default as RouterProvider } from "./RouterProvider";
1
+ export { default as Link } from "./components/Link";
2
+ export { default as NavLink } from "./components/NavLink";
3
+ export { default as RouterProvider } from "./context/RouterProvider";
4
+ export { default as createRouter } from "./core/createRouter";
5
+ export { useParams, useQuery } from "./hooks/hook";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { default as createRouter } from "./createRouter";
2
- export { useParams, useQuery } from "./hook";
3
- export { default as Link } from "./Link";
4
- export { default as NavLink } from "./NavLink";
5
- export { default as RouterProvider } from "./RouterProvider";
1
+ export { default as Link } from "./components/Link";
2
+ export { default as NavLink } from "./components/NavLink";
3
+ export { default as RouterProvider } from "./context/RouterProvider";
4
+ export { default as createRouter } from "./core/createRouter";
5
+ export { useParams, useQuery } from "./hooks/hook";
@@ -1,3 +1,2 @@
1
- import "./styles.css";
2
1
  declare const Page404: () => import("react/jsx-runtime").JSX.Element;
3
2
  export default Page404;
@@ -1,10 +1,56 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRouter } from "../../useRouter";
3
- import "./styles.css";
2
+ import { useState } from "react";
3
+ import { useRouter } from "../../hooks/useRouter";
4
+ const staile = {
5
+ errorPage: {
6
+ minHeight: "100vh",
7
+ display: "flex",
8
+ alignItems: "center",
9
+ justifyContent: "center",
10
+ backgroundColor: "#f3f4f6",
11
+ },
12
+ errorContainer: {
13
+ textAlign: "center",
14
+ padding: "0 1rem",
15
+ },
16
+ errorTitle: {
17
+ fontSize: "9rem",
18
+ fontWeight: 700,
19
+ color: "#1f2937",
20
+ margin: 0,
21
+ },
22
+ errorSubtitle: {
23
+ fontSize: "1.5rem",
24
+ fontWeight: 600,
25
+ color: "#4b5563",
26
+ marginTop: "1rem",
27
+ marginBottom: 0,
28
+ },
29
+ errorMessage: {
30
+ color: "#6b7280",
31
+ margin: "1rem 0 2rem 0",
32
+ },
33
+ errorButton: {
34
+ padding: "0.75rem 1.5rem",
35
+ backgroundColor: "#2563eb",
36
+ color: "white",
37
+ border: "none",
38
+ borderRadius: "0.5rem",
39
+ cursor: "pointer",
40
+ transition: "background-color 0.2s",
41
+ },
42
+ errorButtonHover: {
43
+ backgroundColor: "#1d4ed8",
44
+ },
45
+ };
4
46
  const Page404 = () => {
5
47
  const { navigate } = useRouter();
6
- return (_jsx("div", { className: "error-page", children: _jsxs("div", { className: "error-container", children: [_jsx("h1", { className: "error-title", children: "404" }), _jsx("h2", { className: "error-subtitle", children: "Page Not Found" }), _jsx("p", { className: "error-message", children: "Sorry, the page you are looking for does not exist or has been moved." }), _jsx("button", { onClick: () => {
48
+ const [hover, setHover] = useState(false);
49
+ return (_jsx("div", { style: staile.errorPage, children: _jsxs("div", { style: staile.errorContainer, children: [_jsx("h1", { style: staile.errorTitle, children: "404" }), _jsx("h2", { style: staile.errorSubtitle, children: "Page Not Found" }), _jsx("p", { style: staile.errorMessage, children: "Sorry, the page you are looking for does not exist or has been moved." }), _jsx("button", { onClick: () => {
7
50
  navigate("/");
8
- }, className: "error-button", children: "Go Back Home" })] }) }));
51
+ }, onMouseEnter: () => setHover(true), onMouseLeave: () => setHover(false), style: {
52
+ ...staile.errorButton,
53
+ ...(hover ? staile.errorButtonHover : {}),
54
+ }, children: "Go Back Home" })] }) }));
9
55
  };
10
56
  export default Page404;
package/package.json CHANGED
@@ -5,10 +5,10 @@
5
5
  "email": "mohammed.bencheikh.dev@gmail.com",
6
6
  "url": "https://mohammedbencheikh.com/"
7
7
  },
8
- "version": "0.1.3",
8
+ "version": "0.1.5",
9
9
  "description": "A small React routing provider library",
10
10
  "main": "dist/index.js",
11
- "types": "dist/*.d.ts",
11
+ "types": "dist/index.d.ts",
12
12
  "files": [
13
13
  "dist"
14
14
  ],
@@ -16,7 +16,9 @@
16
16
  "clean": "rm -rf dist",
17
17
  "build": "tsc -p tsconfig.json",
18
18
  "build:watch": "tsc -p tsconfig.json --watch",
19
- "prepare": "npm run build"
19
+ "prepare": "npm run build",
20
+ "typecheck": "tsc -p tsconfig.json --noEmit",
21
+ "pack:verify": "npm pack --dry-run"
20
22
  },
21
23
  "peerDependencies": {
22
24
  "react": ">=16 <20",
@@ -35,8 +37,10 @@
35
37
  "react",
36
38
  "route",
37
39
  "provider",
40
+ "kit",
38
41
  "routing",
39
- "route-provider"
42
+ "route-provider",
43
+ "route-kit"
40
44
  ],
41
45
  "license": "MIT"
42
46
  }
@@ -1,5 +0,0 @@
1
- import type { Route } from "./types";
2
- declare const RouterProvider: ({ routes }: {
3
- routes: Route[];
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- export default RouterProvider;
@@ -1,3 +0,0 @@
1
- import type { Route } from "./types";
2
- declare function createRouter(routes: Route[]): Route[];
3
- export default createRouter;
@@ -1 +0,0 @@
1
- export declare function useRouter(): import("./types").RouterContextType;
File without changes
File without changes
File without changes
File without changes