@arielgonzaguer/michi-router 2.2.3 → 3.0.0
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 +59 -10
- package/dist/core.d.mts +12 -0
- package/dist/core.d.ts +2 -0
- package/dist/core.js +9 -0
- package/dist/core.mjs +1 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +3 -75
- package/dist/index.js +20 -7
- package/dist/index.mjs +7 -7
- package/dist/protected.d.mts +7 -0
- package/dist/protected.d.ts +2 -0
- package/dist/protected.js +8 -0
- package/dist/protected.mjs +7 -0
- package/dist/types-DvzlhMRY.d.mts +58 -0
- package/dist/types-DvzlhMRY.d.ts +58 -0
- package/package.json +82 -57
package/README.md
CHANGED
|
@@ -6,18 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
El objetivo principal de esta herramienta es proporcionar la funcionalidad básica de enrutamiento.
|
|
11
|
-
No requiere de ninguna dependencia externa, ideal para proyectos pequeños.
|
|
12
|
-
Creado con TypeScript.
|
|
9
|
+
Router minimalista para React, enfocado en tamaño, DX y seguridad para navegación interna del lado del cliente.
|
|
13
10
|
|
|
14
11
|
## Características
|
|
15
12
|
|
|
16
|
-
- **
|
|
17
|
-
- **TypeScript**:
|
|
18
|
-
- **Zero dependencias
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
13
|
+
- **Ligero**: pensado para mantenerse pequeño.
|
|
14
|
+
- **TypeScript first**: API completamente tipada.
|
|
15
|
+
- **Zero dependencias de runtime**.
|
|
16
|
+
- **Rutas dinámicas**: soporte para `:params` y wildcard `*`.
|
|
17
|
+
- **Hooks**: `useNavigate`, `useLocation`, `useParams`.
|
|
18
|
+
- **Basename**: útil para apps bajo subrutas (`/app`).
|
|
19
|
+
- **Componente `Protected`** opcional.
|
|
20
|
+
- **Navegación segura interna**: bloquea protocolos inseguros y destinos externos.
|
|
21
21
|
|
|
22
22
|
## Instalación
|
|
23
23
|
|
|
@@ -25,4 +25,53 @@ Creado con TypeScript.
|
|
|
25
25
|
npm install @arielgonzaguer/michi-router
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
## Uso rápido
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { RouterProvider, Link, useNavigate, useParams } from '@arielgonzaguer/michi-router';
|
|
32
|
+
|
|
33
|
+
function Home() {
|
|
34
|
+
const navigate = useNavigate();
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
<h1>Home</h1>
|
|
38
|
+
<Link to="/users/42">Ir al usuario</Link>
|
|
39
|
+
<button onClick={() => navigate('/search?q=michi#top')}>Buscar</button>
|
|
40
|
+
</>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function UserPage() {
|
|
45
|
+
const { id } = useParams<{ id: string }>();
|
|
46
|
+
return <h1>User {id}</h1>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default function App() {
|
|
50
|
+
return (
|
|
51
|
+
<RouterProvider
|
|
52
|
+
basename="/app"
|
|
53
|
+
routes={[
|
|
54
|
+
{ path: '/', component: <Home /> },
|
|
55
|
+
{ path: '/users/:id', component: <UserPage /> },
|
|
56
|
+
{ path: '/docs/*', component: <h1>Docs</h1> }
|
|
57
|
+
]}
|
|
58
|
+
notFound={<h1>404</h1>}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## API
|
|
65
|
+
|
|
66
|
+
- `navigate(to, options?)` con `options.replace` y `options.state`.
|
|
67
|
+
- `useLocation()` retorna `{ pathname, search, hash, fullPath }`.
|
|
68
|
+
- `useParams()` retorna los parámetros de la ruta activa.
|
|
69
|
+
- `Link` está diseñado para rutas internas.
|
|
70
|
+
|
|
71
|
+
## Entradas del paquete
|
|
72
|
+
|
|
73
|
+
- `@arielgonzaguer/michi-router`: API completa.
|
|
74
|
+
- `@arielgonzaguer/michi-router/core`: router base sin `Protected`.
|
|
75
|
+
- `@arielgonzaguer/michi-router/protected`: export del componente `Protected`.
|
|
76
|
+
|
|
77
|
+
Documentación: [https://michirouter.vercel.app/](https://michirouter.vercel.app/)
|
package/dist/core.d.mts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { a as LinkProps, g as RouterProviderProps, f as RouterLocation, N as NavigateFn, d as RouteParams } from './types-DvzlhMRY.mjs';
|
|
2
|
+
export { L as LayoutProps, b as NavigateOptions, R as Route, e as RouterContextType } from './types-DvzlhMRY.mjs';
|
|
3
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
+
import 'react';
|
|
5
|
+
|
|
6
|
+
declare function RouterProvider({ routes, children, notFound, basename, layout: Layout }: RouterProviderProps): react_jsx_runtime.JSX.Element;
|
|
7
|
+
declare const Link: ({ to, children, className, onClick, ...rest }: LinkProps) => react_jsx_runtime.JSX.Element;
|
|
8
|
+
declare const useNavigate: () => NavigateFn;
|
|
9
|
+
declare const useLocation: () => RouterLocation;
|
|
10
|
+
declare const useParams: <T extends RouteParams = RouteParams>() => T;
|
|
11
|
+
|
|
12
|
+
export { Link, LinkProps, NavigateFn, RouteParams, RouterLocation, RouterProvider, RouterProviderProps, useLocation, useNavigate, useParams };
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export type { LayoutProps, LinkProps, NavigateFn, NavigateOptions, Route, RouteParams, RouterContextType, RouterLocation, RouterProviderProps } from './michi-router/types';
|
|
2
|
+
export { Link, RouterProvider, useLocation, useNavigate, useParams } from './michi-router/Michi-router';
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useParams = exports.useNavigate = exports.useLocation = exports.RouterProvider = exports.Link = void 0;
|
|
4
|
+
var Michi_router_1 = require("./michi-router/Michi-router");
|
|
5
|
+
Object.defineProperty(exports, "Link", { enumerable: true, get: function () { return Michi_router_1.Link; } });
|
|
6
|
+
Object.defineProperty(exports, "RouterProvider", { enumerable: true, get: function () { return Michi_router_1.RouterProvider; } });
|
|
7
|
+
Object.defineProperty(exports, "useLocation", { enumerable: true, get: function () { return Michi_router_1.useLocation; } });
|
|
8
|
+
Object.defineProperty(exports, "useNavigate", { enumerable: true, get: function () { return Michi_router_1.useNavigate; } });
|
|
9
|
+
Object.defineProperty(exports, "useParams", { enumerable: true, get: function () { return Michi_router_1.useParams; } });
|
package/dist/core.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useCallback as b,createContext as E,useContext as w,useEffect as F,useMemo as C,useState as A}from"react";var k="https://michi-router.local",I=new Set(["http:","https:"]),N=t=>t.startsWith("/")?t:`/${t}`,g=t=>{let e=t.trim();if(!e)return"/";let n=N(e);return(n.length>1?n.replace(/\/+$/,""):n)||"/"},R=t=>t?g(t):"/",z=(t,e)=>e==="/"?!0:t===e||t.startsWith(`${e}/`),B=(t,e)=>e==="/"?t:t===e?"/":t.startsWith(`${e}/`)?t.slice(e.length)||"/":t,O=(t,e)=>t==="/"?e:e==="/"?t:`${t}${e}`,$=t=>{try{return decodeURIComponent(t)}catch{return t}},P=(t,e="/")=>{if(typeof t!="string")return null;let n=t.trim();if(!n||/[\u0000-\u001f\u007f]/.test(n))return null;let o=R(e),s=typeof window<"u"?window.location.origin:k,i=o==="/"?`${s}/`:`${s}${o}/`,a;try{a=new URL(n,i)}catch{return null}if(!I.has(a.protocol)||typeof window<"u"&&a.origin!==window.location.origin)return null;let r=g(a.pathname),c=z(r,o)?g(B(r,o)):r,u=g(O(o,c)),p=a.search||"",h=a.hash||"",l=`${c}${p}${h}`,m=`${u}${p}${h}`;return{pathname:c,search:p,hash:h,fullPath:l,browserPath:m}},y=(t,e)=>{let n=g(t),o=g(e);if(n==="*")return{"*":o==="/"?"":o.slice(1)};let s=n==="/"?[]:n.slice(1).split("/"),i=o==="/"?[]:o.slice(1).split("/"),a={},r=0,c=0;for(;r<s.length&&c<i.length;){let u=s[r];if(u==="*"){if(r!==s.length-1)return null;a["*"]=i.slice(c).map($).join("/"),c=i.length,r=s.length;break}let p=i[c];if(u.startsWith(":")){let h=u.slice(1);if(!h)return null;a[h]=$(p)}else if(u!==p)return null;r+=1,c+=1}return r<s.length&&s[r]==="*"&&r===s.length-1&&(a["*"]="",r+=1),r!==s.length||c!==i.length?null:a};import{jsx as L}from"react/jsx-runtime";var v=typeof window<"u",T={pathname:"/",search:"",hash:"",fullPath:"/"},S=t=>{if(!v)return T;let e=`${window.location.pathname}${window.location.search}${window.location.hash}`,n=P(e,t);if(n)return{pathname:n.pathname,search:n.search,hash:n.hash,fullPath:n.fullPath};let o=g(window.location.pathname);return{pathname:o,search:window.location.search,hash:window.location.hash,fullPath:`${o}${window.location.search}${window.location.hash}`}},f=E({path:"/",location:T,params:{},basename:"/",navigate:()=>{console.warn("RouterContext usado fuera de RouterProvider")}});function U({routes:t,children:e,notFound:n,basename:o,layout:s}){let i=C(()=>R(o),[o]),[a,r]=A(()=>S(i));F(()=>{if(!v)return;let l=()=>r(S(i));return window.addEventListener("popstate",l),()=>window.removeEventListener("popstate",l)},[i]);let c=b((l,m)=>{let d=P(l,i);if(!d){console.warn(`MichiRouter: navegaci\xF3n bloqueada. URL interna no v\xE1lida: "${l}"`);return}let x={pathname:d.pathname,search:d.search,hash:d.hash,fullPath:d.fullPath};if(!v){r(x);return}m?.replace?window.history.replaceState(m?.state??null,"",d.browserPath):window.history.pushState(m?.state??null,"",d.browserPath),r(x)},[i]),u=C(()=>{for(let l of t){let m=y(l.path,a.pathname);if(m)return{route:l,params:m}}return null},[a.pathname,t]),p=u?.params??{},h=u?u.route.component:n??e;return L(f.Provider,{value:{path:a.pathname,location:a,params:p,basename:i,navigate:c},children:s?L(s,{children:h}):h})}var M=({to:t,children:e,className:n,onClick:o,...s})=>{let{navigate:i,basename:a}=w(f),r=P(t,a),c=r?r.browserPath:"#";return L("a",{href:c,className:n,onClick:u=>{o?.(u),!u.defaultPrevented&&(u.preventDefault(),i(t))},...s,children:e})},W=()=>w(f).navigate,_=()=>w(f).location,D=()=>w(f).params;export{M as Link,U as RouterProvider,_ as useLocation,W as useNavigate,D as useParams};
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { A as AuthState, L as LayoutProps, a as LinkProps, N as NavigateFn, b as NavigateOptions, P as ProtectedConfig, c as ProtectedProps, R as Route, d as RouteParams, e as RouterContextType, f as RouterLocation, g as RouterProviderProps } from './types-DvzlhMRY.mjs';
|
|
2
|
+
export { Link, RouterProvider, useLocation, useNavigate, useParams } from './core.mjs';
|
|
3
|
+
export { Protected } from './protected.mjs';
|
|
4
|
+
import 'react';
|
|
5
|
+
import 'react/jsx-runtime';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,75 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
interface LayoutProps {
|
|
5
|
-
children: ReactNode;
|
|
6
|
-
}
|
|
7
|
-
interface Route {
|
|
8
|
-
path: string;
|
|
9
|
-
component: ReactNode;
|
|
10
|
-
}
|
|
11
|
-
interface RouterContextType {
|
|
12
|
-
path: string;
|
|
13
|
-
navigate: (to: string) => void;
|
|
14
|
-
}
|
|
15
|
-
interface RouterProviderProps {
|
|
16
|
-
routes: Array<{
|
|
17
|
-
path: string;
|
|
18
|
-
component: React.ReactNode;
|
|
19
|
-
}>;
|
|
20
|
-
children?: React.ReactNode;
|
|
21
|
-
layout?: React.ComponentType<{
|
|
22
|
-
children: React.ReactNode;
|
|
23
|
-
}>;
|
|
24
|
-
}
|
|
25
|
-
interface LinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
|
|
26
|
-
to: string;
|
|
27
|
-
children: ReactNode;
|
|
28
|
-
className?: string;
|
|
29
|
-
}
|
|
30
|
-
interface AuthState<TUser = any> {
|
|
31
|
-
user: TUser | null;
|
|
32
|
-
isLoading: boolean;
|
|
33
|
-
}
|
|
34
|
-
interface ProtectedConfig<TUser = any> {
|
|
35
|
-
states: AuthState<TUser>;
|
|
36
|
-
redirectionPath: string;
|
|
37
|
-
loadingComponent?: ReactNode;
|
|
38
|
-
defaultMessage?: string;
|
|
39
|
-
}
|
|
40
|
-
interface ProtectedProps<TUser = any> {
|
|
41
|
-
children: JSX.Element;
|
|
42
|
-
configObject: ProtectedConfig<TUser>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Proveedor principal del enrutador.
|
|
47
|
-
* @param routes - Array de rutas disponibles
|
|
48
|
-
* @param children - Contenido a mostrar cuando no hay coincidencia de ruta (404)
|
|
49
|
-
* @param layout - Componente de layout opcional para envolver todas las rutas
|
|
50
|
-
*/
|
|
51
|
-
declare function RouterProvider({ routes, children, layout: Layout }: RouterProviderProps): react_jsx_runtime.JSX.Element;
|
|
52
|
-
/**
|
|
53
|
-
* Componente Link para navegación declarativa.
|
|
54
|
-
* Previene la recarga de página y utiliza el historial del navegador.
|
|
55
|
-
*/
|
|
56
|
-
declare const Link: ({ to, children, className, ...rest }: LinkProps & React$1.AnchorHTMLAttributes<HTMLAnchorElement>) => react_jsx_runtime.JSX.Element;
|
|
57
|
-
/**
|
|
58
|
-
* Hook para acceder a la función de navegación programática.
|
|
59
|
-
* @returns Función navigate que permite cambiar de ruta
|
|
60
|
-
*/
|
|
61
|
-
declare const useNavigate: () => (to: string) => void;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Un componente que restringe el acceso a sus hijos según el estado de autenticación del usuario.
|
|
65
|
-
*
|
|
66
|
-
* Si el usuario no está autenticado, redirige a la página de landing ("/").
|
|
67
|
-
* De lo contrario, renderiza sus hijos.
|
|
68
|
-
*
|
|
69
|
-
* @param {Object} props - Props del componente
|
|
70
|
-
* @param {React.ReactNode} props.children - Los nodos React a renderizar si el usuario está autenticado.
|
|
71
|
-
* @returns {JSX.Element|null} Los hijos si está autenticado, de lo contrario loader.
|
|
72
|
-
*/
|
|
73
|
-
declare function Protected<TUser = any>({ children, configObject }: ProtectedProps<TUser>): JSX.Element | null;
|
|
74
|
-
|
|
75
|
-
export { type LayoutProps, Link, type LinkProps, Protected, type ProtectedProps, type Route, type RouterContextType, RouterProvider, type RouterProviderProps, useNavigate };
|
|
1
|
+
export * from './core';
|
|
2
|
+
export { Protected } from './protected';
|
|
3
|
+
export type { AuthState, ProtectedConfig, ProtectedProps } from './michi-router/types';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Protected = void 0;
|
|
18
|
+
__exportStar(require("./core"), exports);
|
|
19
|
+
var protected_1 = require("./protected");
|
|
20
|
+
Object.defineProperty(exports, "Protected", { enumerable: true, get: function () { return protected_1.Protected; } });
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{useCallback as
|
|
2
|
-
{
|
|
3
|
-
states: { user: any; isLoading: boolean };
|
|
4
|
-
redirectionPath: string;
|
|
5
|
-
loadingComponent?: React.ReactNode;
|
|
6
|
-
defaultMessage?: string;
|
|
7
|
-
}`),null;let{user:
|
|
1
|
+
import{useCallback as F,createContext as O,useContext as w,useEffect as W,useMemo as N,useState as _}from"react";var z="https://michi-router.local",B=new Set(["http:","https:"]),M=t=>t.startsWith("/")?t:`/${t}`,f=t=>{let e=t.trim();if(!e)return"/";let r=M(e);return(r.length>1?r.replace(/\/+$/,""):r)||"/"},R=t=>t?f(t):"/",A=(t,e)=>e==="/"?!0:t===e||t.startsWith(`${e}/`),U=(t,e)=>e==="/"?t:t===e?"/":t.startsWith(`${e}/`)?t.slice(e.length)||"/":t,b=(t,e)=>t==="/"?e:e==="/"?t:`${t}${e}`,T=t=>{try{return decodeURIComponent(t)}catch{return t}},g=(t,e="/")=>{if(typeof t!="string")return null;let r=t.trim();if(!r||/[\u0000-\u001f\u007f]/.test(r))return null;let n=R(e),s=typeof window<"u"?window.location.origin:z,i=n==="/"?`${s}/`:`${s}${n}/`,o;try{o=new URL(r,i)}catch{return null}if(!B.has(o.protocol)||typeof window<"u"&&o.origin!==window.location.origin)return null;let a=f(o.pathname),c=A(a,n)?f(U(a,n)):a,l=f(b(n,c)),d=o.search||"",h=o.hash||"",u=`${c}${d}${h}`,p=`${l}${d}${h}`;return{pathname:c,search:d,hash:h,fullPath:u,browserPath:p}},k=(t,e)=>{let r=f(t),n=f(e);if(r==="*")return{"*":n==="/"?"":n.slice(1)};let s=r==="/"?[]:r.slice(1).split("/"),i=n==="/"?[]:n.slice(1).split("/"),o={},a=0,c=0;for(;a<s.length&&c<i.length;){let l=s[a];if(l==="*"){if(a!==s.length-1)return null;o["*"]=i.slice(c).map(T).join("/"),c=i.length,a=s.length;break}let d=i[c];if(l.startsWith(":")){let h=l.slice(1);if(!h)return null;o[h]=T(d)}else if(l!==d)return null;a+=1,c+=1}return a<s.length&&s[a]==="*"&&a===s.length-1&&(o["*"]="",a+=1),a!==s.length||c!==i.length?null:o};import{jsx as L}from"react/jsx-runtime";var v=typeof window<"u",I={pathname:"/",search:"",hash:"",fullPath:"/"},E=t=>{if(!v)return I;let e=`${window.location.pathname}${window.location.search}${window.location.hash}`,r=g(e,t);if(r)return{pathname:r.pathname,search:r.search,hash:r.hash,fullPath:r.fullPath};let n=f(window.location.pathname);return{pathname:n,search:window.location.search,hash:window.location.hash,fullPath:`${n}${window.location.search}${window.location.hash}`}},P=O({path:"/",location:I,params:{},basename:"/",navigate:()=>{console.warn("RouterContext usado fuera de RouterProvider")}});function q({routes:t,children:e,notFound:r,basename:n,layout:s}){let i=N(()=>R(n),[n]),[o,a]=_(()=>E(i));W(()=>{if(!v)return;let u=()=>a(E(i));return window.addEventListener("popstate",u),()=>window.removeEventListener("popstate",u)},[i]);let c=F((u,p)=>{let m=g(u,i);if(!m){console.warn(`MichiRouter: navegaci\xF3n bloqueada. URL interna no v\xE1lida: "${u}"`);return}let S={pathname:m.pathname,search:m.search,hash:m.hash,fullPath:m.fullPath};if(!v){a(S);return}p?.replace?window.history.replaceState(p?.state??null,"",m.browserPath):window.history.pushState(p?.state??null,"",m.browserPath),a(S)},[i]),l=N(()=>{for(let u of t){let p=k(u.path,o.pathname);if(p)return{route:u,params:p}}return null},[o.pathname,t]),d=l?.params??{},h=l?l.route.component:r??e;return L(P.Provider,{value:{path:o.pathname,location:o,params:d,basename:i,navigate:c},children:s?L(s,{children:h}):h})}var D=({to:t,children:e,className:r,onClick:n,...s})=>{let{navigate:i,basename:o}=w(P),a=g(t,o),c=a?a.browserPath:"#";return L("a",{href:c,className:r,onClick:l=>{n?.(l),!l.defaultPrevented&&(l.preventDefault(),i(t))},...s,children:e})},x=()=>w(P).navigate,H=()=>w(P).location,G=()=>w(P).params;import{useEffect as K}from"react";import{Fragment as C,jsx as y}from"react/jsx-runtime";var J=t=>{let e=g(t,"/");return e?e.fullPath:"/"};function $({children:t,configObject:e}){let r=x(),n={states:e?.states||{user:null,isLoading:!1},redirectionPath:e?.redirectionPath||"/",loadingComponent:e?.loadingComponent||null,defaultMessage:e?.defaultMessage||void 0};if(!e?.states)return console.error(`Componente Protected: El objeto de configuraci\xF3n es inv\xE1lido. Este es el formato esperado:
|
|
2
|
+
{
|
|
3
|
+
states: { user: any; isLoading: boolean };
|
|
4
|
+
redirectionPath: string;
|
|
5
|
+
loadingComponent?: React.ReactNode;
|
|
6
|
+
defaultMessage?: string;
|
|
7
|
+
}`),null;let s=J(n.redirectionPath),{user:i,isLoading:o}=n.states;return K(()=>{!o&&!i&&(s!==n.redirectionPath&&console.warn(`Protected: redirectionPath inseguro bloqueado ("${n.redirectionPath}"). Se usa "/" como fallback.`),r(s,{replace:!0}))},[o,i,r,s,n.redirectionPath]),o?n.loadingComponent?y(C,{children:n.loadingComponent}):n.defaultMessage?y(C,{children:n.defaultMessage}):null:i?y(C,{children:t}):null}export{D as Link,$ as Protected,q as RouterProvider,H as useLocation,x as useNavigate,G as useParams};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { c as ProtectedProps } from './types-DvzlhMRY.mjs';
|
|
2
|
+
export { A as AuthState, P as ProtectedConfig } from './types-DvzlhMRY.mjs';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
|
|
5
|
+
declare function Protected<TUser = unknown>({ children, configObject }: ProtectedProps<TUser>): React.ReactElement | null;
|
|
6
|
+
|
|
7
|
+
export { Protected, ProtectedProps };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Protected = void 0;
|
|
7
|
+
var Protected_1 = require("./michi-router/Protected");
|
|
8
|
+
Object.defineProperty(exports, "Protected", { enumerable: true, get: function () { return __importDefault(Protected_1).default; } });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{useEffect as z}from"react";import{useCallback as b,createContext as T,useContext as E,useEffect as A,useMemo as F,useState as W}from"react";var v="https://michi-router.local",L=new Set(["http:","https:"]),C=t=>t.startsWith("/")?t:`/${t}`,i=t=>{let e=t.trim();if(!e)return"/";let r=C(e);return(r.length>1?r.replace(/\/+$/,""):r)||"/"},x=t=>t?i(t):"/",$=(t,e)=>e==="/"?!0:t===e||t.startsWith(`${e}/`),S=(t,e)=>e==="/"?t:t===e?"/":t.startsWith(`${e}/`)?t.slice(e.length)||"/":t,y=(t,e)=>t==="/"?e:e==="/"?t:`${t}${e}`;var p=(t,e="/")=>{if(typeof t!="string")return null;let r=t.trim();if(!r||/[\u0000-\u001f\u007f]/.test(r))return null;let n=x(e),a=typeof window<"u"?window.location.origin:v,s=n==="/"?`${a}/`:`${a}${n}/`,o;try{o=new URL(r,s)}catch{return null}if(!L.has(o.protocol)||typeof window<"u"&&o.origin!==window.location.origin)return null;let l=i(o.pathname),c=$(l,n)?i(S(l,n)):l,P=i(y(n,c)),u=o.search||"",h=o.hash||"",w=`${c}${u}${h}`,R=`${P}${u}${h}`;return{pathname:c,search:u,hash:h,fullPath:w,browserPath:R}};import{jsx as _}from"react/jsx-runtime";var I={pathname:"/",search:"",hash:"",fullPath:"/"};var k=T({path:"/",location:I,params:{},basename:"/",navigate:()=>{console.warn("RouterContext usado fuera de RouterProvider")}});var g=()=>E(k).navigate;import{Fragment as d,jsx as f}from"react/jsx-runtime";var B=t=>{let e=p(t,"/");return e?e.fullPath:"/"};function m({children:t,configObject:e}){let r=g(),n={states:e?.states||{user:null,isLoading:!1},redirectionPath:e?.redirectionPath||"/",loadingComponent:e?.loadingComponent||null,defaultMessage:e?.defaultMessage||void 0};if(!e?.states)return console.error(`Componente Protected: El objeto de configuraci\xF3n es inv\xE1lido. Este es el formato esperado:
|
|
2
|
+
{
|
|
3
|
+
states: { user: any; isLoading: boolean };
|
|
4
|
+
redirectionPath: string;
|
|
5
|
+
loadingComponent?: React.ReactNode;
|
|
6
|
+
defaultMessage?: string;
|
|
7
|
+
}`),null;let a=B(n.redirectionPath),{user:s,isLoading:o}=n.states;return z(()=>{!o&&!s&&(a!==n.redirectionPath&&console.warn(`Protected: redirectionPath inseguro bloqueado ("${n.redirectionPath}"). Se usa "/" como fallback.`),r(a,{replace:!0}))},[o,s,r,a,n.redirectionPath]),o?n.loadingComponent?f(d,{children:n.loadingComponent}):n.defaultMessage?f(d,{children:n.defaultMessage}):null:s?f(d,{children:t}):null}export{m as Protected};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ReactNode, AnchorHTMLAttributes, ComponentType } from 'react';
|
|
2
|
+
|
|
3
|
+
interface LayoutProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
type RouteParams = Record<string, string>;
|
|
7
|
+
interface RouterLocation {
|
|
8
|
+
pathname: string;
|
|
9
|
+
search: string;
|
|
10
|
+
hash: string;
|
|
11
|
+
fullPath: string;
|
|
12
|
+
}
|
|
13
|
+
interface NavigateOptions {
|
|
14
|
+
replace?: boolean;
|
|
15
|
+
state?: unknown;
|
|
16
|
+
}
|
|
17
|
+
type NavigateFn = (to: string, options?: NavigateOptions) => void;
|
|
18
|
+
interface Route {
|
|
19
|
+
path: string;
|
|
20
|
+
component: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
interface RouterContextType {
|
|
23
|
+
path: string;
|
|
24
|
+
location: RouterLocation;
|
|
25
|
+
params: RouteParams;
|
|
26
|
+
basename: string;
|
|
27
|
+
navigate: NavigateFn;
|
|
28
|
+
}
|
|
29
|
+
interface RouterProviderProps {
|
|
30
|
+
routes: Route[];
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
notFound?: ReactNode;
|
|
33
|
+
basename?: string;
|
|
34
|
+
layout?: ComponentType<{
|
|
35
|
+
children: ReactNode;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
interface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
|
|
39
|
+
to: string;
|
|
40
|
+
children: ReactNode;
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
interface AuthState<TUser = unknown> {
|
|
44
|
+
user: TUser | null;
|
|
45
|
+
isLoading: boolean;
|
|
46
|
+
}
|
|
47
|
+
interface ProtectedConfig<TUser = unknown> {
|
|
48
|
+
states: AuthState<TUser>;
|
|
49
|
+
redirectionPath: string;
|
|
50
|
+
loadingComponent?: ReactNode;
|
|
51
|
+
defaultMessage?: string;
|
|
52
|
+
}
|
|
53
|
+
interface ProtectedProps<TUser = unknown> {
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
configObject: ProtectedConfig<TUser>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type { AuthState as A, LayoutProps as L, NavigateFn as N, ProtectedConfig as P, Route as R, LinkProps as a, NavigateOptions as b, ProtectedProps as c, RouteParams as d, RouterContextType as e, RouterLocation as f, RouterProviderProps as g };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ReactNode, AnchorHTMLAttributes, ComponentType } from 'react';
|
|
2
|
+
|
|
3
|
+
interface LayoutProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
type RouteParams = Record<string, string>;
|
|
7
|
+
interface RouterLocation {
|
|
8
|
+
pathname: string;
|
|
9
|
+
search: string;
|
|
10
|
+
hash: string;
|
|
11
|
+
fullPath: string;
|
|
12
|
+
}
|
|
13
|
+
interface NavigateOptions {
|
|
14
|
+
replace?: boolean;
|
|
15
|
+
state?: unknown;
|
|
16
|
+
}
|
|
17
|
+
type NavigateFn = (to: string, options?: NavigateOptions) => void;
|
|
18
|
+
interface Route {
|
|
19
|
+
path: string;
|
|
20
|
+
component: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
interface RouterContextType {
|
|
23
|
+
path: string;
|
|
24
|
+
location: RouterLocation;
|
|
25
|
+
params: RouteParams;
|
|
26
|
+
basename: string;
|
|
27
|
+
navigate: NavigateFn;
|
|
28
|
+
}
|
|
29
|
+
interface RouterProviderProps {
|
|
30
|
+
routes: Route[];
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
notFound?: ReactNode;
|
|
33
|
+
basename?: string;
|
|
34
|
+
layout?: ComponentType<{
|
|
35
|
+
children: ReactNode;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
interface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
|
|
39
|
+
to: string;
|
|
40
|
+
children: ReactNode;
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
interface AuthState<TUser = unknown> {
|
|
44
|
+
user: TUser | null;
|
|
45
|
+
isLoading: boolean;
|
|
46
|
+
}
|
|
47
|
+
interface ProtectedConfig<TUser = unknown> {
|
|
48
|
+
states: AuthState<TUser>;
|
|
49
|
+
redirectionPath: string;
|
|
50
|
+
loadingComponent?: ReactNode;
|
|
51
|
+
defaultMessage?: string;
|
|
52
|
+
}
|
|
53
|
+
interface ProtectedProps<TUser = unknown> {
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
configObject: ProtectedConfig<TUser>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type { AuthState as A, LayoutProps as L, NavigateFn as N, ProtectedConfig as P, Route as R, LinkProps as a, NavigateOptions as b, ProtectedProps as c, RouteParams as d, RouterContextType as e, RouterLocation as f, RouterProviderProps as g };
|
package/package.json
CHANGED
|
@@ -1,57 +1,82 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@arielgonzaguer/michi-router",
|
|
3
|
-
"private": false,
|
|
4
|
-
"version": "
|
|
5
|
-
"description": "El router minimalista y simple para React.\nEl objetivo principal de esta herramienta es proporcionar la funcionalidad básica de enrutamiento.",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"module": "dist/index.mjs",
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
}
|
|
57
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@arielgonzaguer/michi-router",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "3.0.0",
|
|
5
|
+
"description": "El router minimalista y simple para React.\nEl objetivo principal de esta herramienta es proporcionar la funcionalidad básica de enrutamiento.",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./core": {
|
|
16
|
+
"types": "./dist/core.d.ts",
|
|
17
|
+
"import": "./dist/core.mjs",
|
|
18
|
+
"require": "./dist/core.js"
|
|
19
|
+
},
|
|
20
|
+
"./protected": {
|
|
21
|
+
"types": "./dist/protected.d.ts",
|
|
22
|
+
"import": "./dist/protected.mjs",
|
|
23
|
+
"require": "./dist/protected.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"prepare": "npm run build:bundle",
|
|
33
|
+
"clean": "rimraf dist",
|
|
34
|
+
"prebuild": "npm run clean",
|
|
35
|
+
"test": "vitest --run",
|
|
36
|
+
"test:watch": "vitest --watch",
|
|
37
|
+
"build:bundle": "npm run clean && tsup src/index.ts src/core.ts src/protected.ts --format esm,cjs --minify --dts --out-dir dist --external react --splitting false",
|
|
38
|
+
"size:check": "node scripts/check-size.js",
|
|
39
|
+
"prepublish": "npm run build:bundle && npm test && npm run size:check",
|
|
40
|
+
"release:patch": "npm version patch && npm publish --access public && git push origin main --tags",
|
|
41
|
+
"release:minor": "npm version minor && npm publish --access public && git push origin main --tags",
|
|
42
|
+
"release:major": "npm version major && npm publish --access public && git push origin main --tags"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"enrutado",
|
|
46
|
+
"react",
|
|
47
|
+
"router",
|
|
48
|
+
"typescript",
|
|
49
|
+
"michi",
|
|
50
|
+
"cats",
|
|
51
|
+
"gatos",
|
|
52
|
+
"front-end"
|
|
53
|
+
],
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"react": ">=17.0.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@swc/core": "1.13.5",
|
|
59
|
+
"@testing-library/jest-dom": "6.0.0",
|
|
60
|
+
"@testing-library/react": "14.0.0",
|
|
61
|
+
"@types/jest": "29.5.3",
|
|
62
|
+
"@types/react": "18.3.18",
|
|
63
|
+
"@types/react-dom": "18.3.5",
|
|
64
|
+
"jsdom": "26.1.0",
|
|
65
|
+
"react": "18.3.1",
|
|
66
|
+
"react-dom": "18.3.1",
|
|
67
|
+
"rimraf": "6.0.1",
|
|
68
|
+
"tsup": "8.5.0",
|
|
69
|
+
"typescript": "4.9.5",
|
|
70
|
+
"vitest": "3.2.4"
|
|
71
|
+
},
|
|
72
|
+
"repository": {
|
|
73
|
+
"type": "git",
|
|
74
|
+
"url": "git+https://github.com/Ariel-GonzAguer/michi-router.git"
|
|
75
|
+
},
|
|
76
|
+
"bugs": {
|
|
77
|
+
"url": "https://github.com/Ariel-GonzAguer/michi-router/issues"
|
|
78
|
+
},
|
|
79
|
+
"homepage": "https://github.com/Ariel-GonzAguer/michi-router#readme",
|
|
80
|
+
"author": "Ariel Gonzales Agüero",
|
|
81
|
+
"license": "MIT"
|
|
82
|
+
}
|