router-kit 0.1.1

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/dist/Link.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { ReactNode } from "react";
2
+ declare function Link({ to, children, className, }: {
3
+ to: string;
4
+ children: ReactNode;
5
+ className?: string;
6
+ }): import("react/jsx-runtime").JSX.Element;
7
+ export default Link;
package/dist/Link.js ADDED
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useRouter } from "./useRouter";
3
+ function Link({ to, children, className, }) {
4
+ const { navigate } = useRouter();
5
+ return (_jsx("a", { onClick: (e) => {
6
+ e.preventDefault();
7
+ navigate(to);
8
+ }, className: className, href: to, children: children }));
9
+ }
10
+ export default Link;
@@ -0,0 +1,8 @@
1
+ import type { ReactNode } from "react";
2
+ declare function NavLink({ to, children, className, activeClassName, }: {
3
+ to: string;
4
+ children: ReactNode;
5
+ className?: string;
6
+ activeClassName?: string;
7
+ }): import("react/jsx-runtime").JSX.Element;
8
+ export default NavLink;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useRouter } from "./useRouter";
3
+ function NavLink({ to, children, className, activeClassName = "active", }) {
4
+ const { navigate, path } = useRouter();
5
+ const isActive = path === to;
6
+ const combinedClass = [className, isActive ? activeClassName : null]
7
+ .filter(Boolean)
8
+ .join(" ");
9
+ return (_jsx("a", { onClick: (e) => {
10
+ e.preventDefault();
11
+ navigate(to);
12
+ }, className: combinedClass, href: to, children: children }));
13
+ }
14
+ export default NavLink;
@@ -0,0 +1,3 @@
1
+ import type { RouterContextType } from "./types";
2
+ declare const RouterContext: import("react").Context<RouterContextType | undefined>;
3
+ export default RouterContext;
@@ -0,0 +1,3 @@
1
+ import { createContext } from "react";
2
+ const RouterContext = createContext(undefined);
3
+ export default RouterContext;
@@ -0,0 +1,5 @@
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;
@@ -0,0 +1,61 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ import join from "url-join";
4
+ import Page404 from "./pages/404";
5
+ import RouterContext from "./RouterContext";
6
+ const RouterProvider = ({ routes }) => {
7
+ const [path, setPath] = useState(window.location.pathname);
8
+ let fullPathWithParams = "";
9
+ const pathValidation = (fullPath, path) => {
10
+ const fakePathArr = path.split("/");
11
+ let fakePath = "/";
12
+ fullPath.split("/").forEach((e, index) => {
13
+ if (e.startsWith(":")) {
14
+ fakePathArr[index] = e;
15
+ }
16
+ });
17
+ fakePathArr.forEach((e) => {
18
+ fakePath = join(fakePath, `/${e}`);
19
+ });
20
+ if (fullPath === fakePath) {
21
+ fakePath = "";
22
+ return true;
23
+ }
24
+ fakePath = "";
25
+ return false;
26
+ };
27
+ const getComponent = (routes, currentPath, parentPath = "/") => {
28
+ let component = _jsx(Page404, {});
29
+ for (const route of routes) {
30
+ if (route.path === "/404" && route.component)
31
+ component = route.component;
32
+ const fullPath = join(parentPath, `/${route.path}`);
33
+ if (pathValidation(fullPath, currentPath)) {
34
+ fullPathWithParams = fullPath;
35
+ component = route.component;
36
+ break;
37
+ }
38
+ if (route.children) {
39
+ component = getComponent(route.children, currentPath, fullPath);
40
+ }
41
+ }
42
+ return component;
43
+ };
44
+ const component = getComponent(routes, path);
45
+ const navigate = (to, options) => {
46
+ if (options && options.replace) {
47
+ window.history.replaceState({}, "", to);
48
+ }
49
+ else {
50
+ window.history.pushState({}, "", to);
51
+ }
52
+ setPath(to);
53
+ };
54
+ useEffect(() => {
55
+ const handlePop = () => setPath(window.location.pathname);
56
+ window.addEventListener("popstate", handlePop);
57
+ return () => window.removeEventListener("popstate", handlePop);
58
+ }, []);
59
+ return (_jsx(RouterContext.Provider, { value: { path, fullPathWithParams, navigate }, children: component }));
60
+ };
61
+ export default RouterProvider;
@@ -0,0 +1,3 @@
1
+ import type { Route } from "./types";
2
+ declare function createRouter(routes: Route[]): Route[];
3
+ export default createRouter;
@@ -0,0 +1,20 @@
1
+ // Normalize routes: remove leading slashes from paths and normalize children recursively
2
+ function normalizeRoutes(routes) {
3
+ return routes.map((route) => {
4
+ const normalizedPath = route.path.startsWith("/")
5
+ ? route.path.replace(/^\/+/, "")
6
+ : route.path;
7
+ const normalized = {
8
+ ...route,
9
+ path: normalizedPath,
10
+ };
11
+ if (route.children) {
12
+ normalized.children = normalizeRoutes(route.children);
13
+ }
14
+ return normalized;
15
+ });
16
+ }
17
+ function createRouter(routes) {
18
+ return normalizeRoutes(routes);
19
+ }
20
+ export default createRouter;
package/dist/hook.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export declare const useParams: () => {
2
+ [key: string]: string;
3
+ };
4
+ export declare const useQuery: () => {
5
+ [key: string]: string;
6
+ };
package/dist/hook.js ADDED
@@ -0,0 +1,27 @@
1
+ import { useRouter } from "./useRouter";
2
+ // Retourne un objet { [paramName]: value }
3
+ export const useParams = () => {
4
+ const { path, fullPathWithParams } = useRouter();
5
+ const params = {};
6
+ const fullSegments = fullPathWithParams.split("/").filter(Boolean);
7
+ const pathSegments = path.split("/").filter(Boolean);
8
+ fullSegments.forEach((seg, idx) => {
9
+ var _a;
10
+ if (seg.startsWith(":")) {
11
+ const name = seg.slice(1);
12
+ params[name] = (_a = pathSegments[idx]) !== null && _a !== void 0 ? _a : "";
13
+ }
14
+ });
15
+ return params;
16
+ };
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
+ };
@@ -0,0 +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";
package/dist/index.js ADDED
@@ -0,0 +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";
@@ -0,0 +1,3 @@
1
+ import "./styles.css";
2
+ declare const Page404: () => import("react/jsx-runtime").JSX.Element;
3
+ export default Page404;
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRouter } from "../../useRouter";
3
+ import "./styles.css";
4
+ const Page404 = () => {
5
+ 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: () => {
7
+ navigate("/");
8
+ }, className: "error-button", children: "Go Back Home" })] }) }));
9
+ };
10
+ export default Page404;
@@ -0,0 +1 @@
1
+ export declare function useRouter(): import("./types").RouterContextType;
@@ -0,0 +1,8 @@
1
+ import { useContext } from "react";
2
+ import RouterContext from "./RouterContext";
3
+ export function useRouter() {
4
+ const ctx = useContext(RouterContext);
5
+ if (!ctx)
6
+ throw new Error("useRouter must be used within a RouterProvider");
7
+ return ctx;
8
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "router-kit",
3
+ "author": {
4
+ "name": "Mohammed Ben Cheikh",
5
+ "email": "mohammed.bencheikh.dev@gmail.com",
6
+ "url": "https://mohammedbencheikh.com/"
7
+ },
8
+ "version": "0.1.1",
9
+ "description": "A small React routing provider library",
10
+ "main": "dist/index.js",
11
+ "types": "dist/*.d.ts",
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "clean": "rm -rf dist",
17
+ "build": "tsc -p tsconfig.json",
18
+ "build:watch": "tsc -p tsconfig.json --watch",
19
+ "prepare": "npm run build"
20
+ },
21
+ "peerDependencies": {
22
+ "react": ">=17 <19",
23
+ "react-dom": ">=17 <19"
24
+ },
25
+ "dependencies": {
26
+ "url-join": "^5.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "typescript": "^5.2.0",
30
+ "@types/react": "^18.2.0",
31
+ "@types/react-dom": "^18.2.0",
32
+ "@types/url-join": "^4.0.3"
33
+ },
34
+ "keywords": [
35
+ "react",
36
+ "route",
37
+ "provider",
38
+ "routing",
39
+ "route-provider"
40
+ ],
41
+ "license": "MIT"
42
+ }