├── jest.setup.js ├── .npmignore ├── example ├── basic │ ├── src │ │ ├── components │ │ │ ├── Team.tsx │ │ │ ├── About.tsx │ │ │ ├── Products.tsx │ │ │ ├── Navigation.tsx │ │ │ └── App.tsx │ │ └── index.tsx │ ├── package.json │ ├── .babelrc │ ├── public │ │ └── index.html │ └── webpack.config.example.js ├── protect │ ├── package.json │ ├── src │ │ ├── index.tsx │ │ └── components │ │ │ └── App.tsx │ ├── public │ │ └── index.html │ └── webpack.config.example.js ├── transition │ ├── package.json │ ├── src │ │ ├── index.tsx │ │ └── components │ │ │ ├── Card.tsx │ │ │ └── App.tsx │ ├── public │ │ └── index.html │ └── webpack.config.example.js └── README.md ├── .babelrc ├── src ├── __tests_helpers__ │ ├── components │ │ ├── Team.tsx │ │ └── About.tsx │ └── utils.tsx ├── __tests__ │ ├── Base.spec.tsx │ ├── Redirect.spec.tsx │ ├── NotFound.spec.tsx │ ├── hooks.spec.tsx │ ├── Switch.spec.tsx │ ├── NavigoReact.spec.tsx │ └── Route.spec.tsx └── NavigoReact.tsx ├── .babelrc.es ├── tsconfig.json ├── LICENSE ├── webpack.config.js ├── index.d.ts ├── .gitignore ├── package.json ├── lib ├── es │ └── NavigoReact.js ├── cjs │ ├── NavigoReact.js │ └── NavigoReact.js.map ├── NavigoReact.min.js └── NavigoReact.min.js.map └── README.md /jest.setup.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: "jsdom", 3 | }; 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example 2 | node_modules 3 | src 4 | .babelrc 5 | .babelrc.es 6 | jest.setup.js 7 | tsconfig.json 8 | webpack.config.js -------------------------------------------------------------------------------- /example/basic/src/components/Team.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function Team() { 4 | return

Team page

; 5 | } 6 | -------------------------------------------------------------------------------- /example/basic/src/components/About.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function About() { 4 | return

About page

; 5 | } 6 | -------------------------------------------------------------------------------- /example/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "start": "../../node_modules/.bin/webpack-dev-server --config ./webpack.config.example.js" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /example/protect/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "start": "../../node_modules/.bin/webpack-dev-server --config ./webpack.config.example.js" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /example/transition/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "start": "../../node_modules/.bin/webpack-dev-server --config ./webpack.config.example.js" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"], 3 | "plugins": ["@babel/plugin-transform-regenerator", "@babel/plugin-transform-runtime"] 4 | } 5 | -------------------------------------------------------------------------------- /example/basic/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"], 3 | "plugins": ["@babel/plugin-transform-regenerator", "@babel/plugin-transform-runtime"] 4 | } 5 | -------------------------------------------------------------------------------- /example/protect/src/index.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from "react-dom"; 2 | import React from "react"; 3 | 4 | import App from "./components/App"; 5 | 6 | ReactDOM.render(, document.querySelector("#container")); 7 | -------------------------------------------------------------------------------- /example/transition/src/index.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from "react-dom"; 2 | import React from "react"; 3 | 4 | import App from "./components/App"; 5 | 6 | ReactDOM.render(, document.querySelector("#container")); 7 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Run `yarn` in the root of the repo. Then go into the example's directory and run `yarn start`. 4 | 5 | --- 6 | 7 | * [Basic navigation](./basic) 8 | * [Transitions](./transitions) 9 | * [Protecting a route](./protect) -------------------------------------------------------------------------------- /src/__tests_helpers__/components/Team.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { useNavigo } from "../../../src/NavigoReact"; 4 | 5 | export default function Team() { 6 | const { match } = useNavigo(); 7 | if (match) { 8 | return

Team

; 9 | } 10 | return null; 11 | } 12 | -------------------------------------------------------------------------------- /example/basic/src/index.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from "react-dom"; 2 | import React from "react"; 3 | import { configureRouter } from "navigo-react"; 4 | 5 | import App from "./components/App"; 6 | 7 | configureRouter("/app"); 8 | 9 | ReactDOM.render(, document.querySelector("#container")); 10 | -------------------------------------------------------------------------------- /src/__tests_helpers__/components/About.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { useNavigo } from "../../../src/NavigoReact"; 4 | 5 | export default function About() { 6 | const { match } = useNavigo(); 7 | if (match) { 8 | return

About

; 9 | } 10 | return null; 11 | } 12 | -------------------------------------------------------------------------------- /example/basic/src/components/Products.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { useNavigo } from "navigo-react"; 4 | 5 | export default function Products() { 6 | const { match } = useNavigo(); 7 | 8 | if (match) { 9 | // @ts-ignore 10 | return

Product. Type: {match.data.type}

; 11 | } 12 | return null; 13 | } 14 | -------------------------------------------------------------------------------- /.babelrc.es: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node_modules/**/*"], 3 | "presets": [ 4 | ["@babel/preset-typescript"], 5 | [ 6 | "@babel/preset-env", 7 | { 8 | "loose": true, 9 | "modules": false 10 | } 11 | ], 12 | "@babel/preset-react" 13 | ], 14 | "plugins": ["@babel/plugin-transform-regenerator", "@babel/plugin-transform-runtime"] 15 | } 16 | -------------------------------------------------------------------------------- /src/__tests_helpers__/utils.tsx: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom/extend-expect"; 2 | import { screen, waitFor } from "@testing-library/react"; 3 | import { getRouter } from "../../src/NavigoReact"; 4 | 5 | export async function navigate(path: string) { 6 | // @ts-ignore 7 | await waitFor(() => { 8 | getRouter().navigate(path); 9 | }); 10 | } 11 | export async function delay(ms?: number) { 12 | return new Promise((done) => setTimeout(done, ms || 0)); 13 | } 14 | export function expectContent(html: string) { 15 | expect(screen.getByTestId("container").textContent).toEqual(html); 16 | } 17 | -------------------------------------------------------------------------------- /example/basic/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Project 7 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "esnext", 4 | "outDir": "dist/", 5 | "noImplicitAny": true, 6 | "removeComments": true, 7 | "preserveConstEnums": true, 8 | "sourceMap": true, 9 | "target": "ESNext", 10 | "allowJs": true, 11 | "checkJs": false, 12 | "jsx": "react", 13 | "pretty": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "moduleResolution": "node", 17 | "esModuleInterop": true, 18 | "lib": ["dom", "dom.iterable", "ESNext"], 19 | "allowSyntheticDefaultImports": true, 20 | "forceConsistentCasingInFileNames": true, 21 | "resolveJsonModule": true, 22 | "isolatedModules": true 23 | }, 24 | "include": ["./src"], 25 | "exclude": ["node_modules", "**/*.spec.ts"], 26 | "typescript": "^3.9.7" 27 | } 28 | -------------------------------------------------------------------------------- /src/__tests__/Base.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "@testing-library/jest-dom/extend-expect"; 3 | import { render } from "@testing-library/react"; 4 | import { getRouter, reset, Base } from "../NavigoReact"; 5 | 6 | let warn: jest.SpyInstance; 7 | 8 | describe("Given navigo-react", () => { 9 | beforeEach(() => { 10 | reset(); 11 | warn = jest.spyOn(console, "warn").mockImplementation(() => {}); 12 | history.pushState({}, "", "/"); 13 | }); 14 | afterEach(() => { 15 | if (warn) { 16 | warn.mockReset(); 17 | } 18 | }); 19 | describe("when using the Base component", () => { 20 | it("should allow us to set the root of the router", () => { 21 | render(); 22 | // @ts-ignore 23 | expect(getRouter().root).toEqual("foo/bar"); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /example/basic/src/components/Navigation.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | 4 | import { getRouter } from "navigo-react"; 5 | 6 | const Link = styled.a` 7 | display: inline-block; 8 | margin-right: 1em; 9 | color: #fff; 10 | font-size: 1em; 11 | cursor: pointer; 12 | text-decoration: underline; 13 | `; 14 | 15 | export default function Navigation() { 16 | return ( 17 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /example/protect/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Project 7 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /example/transition/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Project 7 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/__tests__/Redirect.spec.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { Match } from "navigo/index.d"; 3 | import "@testing-library/jest-dom/extend-expect"; 4 | import { render } from "@testing-library/react"; 5 | import { getRouter, reset, Redirect } from "../NavigoReact"; 6 | 7 | let warn: jest.SpyInstance; 8 | 9 | describe("Given navigo-react", () => { 10 | beforeEach(() => { 11 | reset(); 12 | warn = jest.spyOn(console, "warn").mockImplementation(() => {}); 13 | history.pushState({}, "", "/"); 14 | }); 15 | afterEach(() => { 16 | if (warn) { 17 | warn.mockReset(); 18 | } 19 | }); 20 | describe("when using the Redirect component", () => { 21 | it("should navigate to a path", () => { 22 | getRouter().on("foo/bar/moo", () => {}); 23 | expect(getRouter().lastResolved()).toEqual(null); 24 | render(); 25 | expect(getRouter().lastResolved()).toStrictEqual([expect.objectContaining({ url: "foo/bar/moo" })]); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /example/basic/webpack.config.example.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | 4 | module.exports = { 5 | mode: "development", 6 | watch: true, 7 | entry: [__dirname + "/src/index.tsx"], 8 | devtool: "inline-source-map", 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.(js|tsx)$/, 13 | exclude: /node_modules/, 14 | use: ["babel-loader"], 15 | }, 16 | { 17 | test: /\.tsx?$/, 18 | use: "ts-loader", 19 | exclude: /node_modules/, 20 | }, 21 | ], 22 | }, 23 | resolve: { 24 | extensions: [".tsx", ".ts", ".js"], 25 | alias: { 26 | "navigo-react$": path.resolve(__dirname + "/../../src/NavigoReact.tsx"), 27 | }, 28 | }, 29 | output: { 30 | path: `${__dirname}/public`, 31 | publicPath: "/", 32 | filename: "app.js", 33 | }, 34 | devServer: { 35 | contentBase: path.resolve(__dirname, "public"), 36 | liveReload: true, 37 | port: 3000, 38 | historyApiFallback: true, 39 | writeToDisk: true, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /example/protect/webpack.config.example.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | 4 | module.exports = { 5 | mode: "development", 6 | watch: true, 7 | entry: [__dirname + "/src/index.tsx"], 8 | devtool: "inline-source-map", 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.(js|tsx)$/, 13 | exclude: /node_modules/, 14 | use: ["babel-loader"], 15 | }, 16 | { 17 | test: /\.tsx?$/, 18 | use: "ts-loader", 19 | exclude: /node_modules/, 20 | }, 21 | ], 22 | }, 23 | resolve: { 24 | extensions: [".tsx", ".ts", ".js"], 25 | alias: { 26 | "navigo-react$": path.resolve(__dirname + "/../../src/NavigoReact.tsx"), 27 | }, 28 | }, 29 | output: { 30 | path: `${__dirname}/public`, 31 | publicPath: "/", 32 | filename: "app.js", 33 | }, 34 | devServer: { 35 | contentBase: path.resolve(__dirname, "public"), 36 | liveReload: true, 37 | port: 3000, 38 | historyApiFallback: true, 39 | writeToDisk: true, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /example/transition/webpack.config.example.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | 4 | module.exports = { 5 | mode: "development", 6 | watch: true, 7 | entry: [__dirname + "/src/index.tsx"], 8 | devtool: "inline-source-map", 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.(js|tsx)$/, 13 | exclude: /node_modules/, 14 | use: ["babel-loader"], 15 | }, 16 | { 17 | test: /\.tsx?$/, 18 | use: "ts-loader", 19 | exclude: /node_modules/, 20 | }, 21 | ], 22 | }, 23 | resolve: { 24 | extensions: [".tsx", ".ts", ".js"], 25 | alias: { 26 | "navigo-react$": path.resolve(__dirname + "/../../src/NavigoReact.tsx"), 27 | }, 28 | }, 29 | output: { 30 | path: `${__dirname}/public`, 31 | publicPath: "/", 32 | filename: "app.js", 33 | }, 34 | devServer: { 35 | contentBase: path.resolve(__dirname, "public"), 36 | liveReload: true, 37 | port: 3000, 38 | historyApiFallback: true, 39 | writeToDisk: true, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Krasimir Tsonev 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. 22 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mode: "production", 3 | entry: [__dirname + "/src/NavigoReact.tsx"], 4 | devtool: "source-map", 5 | module: { 6 | rules: [ 7 | { 8 | test: /\.(js)$/, 9 | exclude: /node_modules/, 10 | use: ["babel-loader"], 11 | }, 12 | { 13 | test: /\.tsx?$/, 14 | use: "ts-loader", 15 | exclude: /node_modules/, 16 | }, 17 | ], 18 | }, 19 | resolve: { 20 | extensions: [".tsx", ".ts", ".js"], 21 | }, 22 | output: { 23 | path: `${__dirname}/lib`, 24 | publicPath: "/", 25 | filename: "NavigoReact.min.js", 26 | library: "NavigoReact", 27 | libraryTarget: "umd", 28 | libraryExport: "default", 29 | umdNamedDefine: true, 30 | globalObject: "typeof self !== 'undefined' ? self : this", 31 | }, 32 | externals: { 33 | react: { 34 | commonjs: "react", 35 | commonjs2: "react", 36 | amd: "React", 37 | root: "React", 38 | }, 39 | "react-dom": { 40 | commonjs: "react-dom", 41 | commonjs2: "react-dom", 42 | amd: "ReactDOM", 43 | root: "ReactDOM", 44 | }, 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /example/basic/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | 4 | import { Route, Switch } from "navigo-react"; 5 | import Navigation from "./Navigation"; 6 | import About from "./About"; 7 | import Products from "./Products"; 8 | import Team from "./Team"; 9 | 10 | type ContainerProps = { 11 | padding?: string | 0; 12 | margin?: string | 0; 13 | }; 14 | 15 | export const Container = styled.div` 16 | padding: ${(props) => ("padding" in props ? props.padding : "0")}; 17 | margin: ${(props) => ("margin" in props ? props.margin : 0)}; 18 | `; 19 | 20 | export default function App() { 21 | return ( 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | Home 37 |
38 |
39 | 40 |
41 | Team page footer 42 |
43 |
44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /example/transition/src/components/Card.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled, { keyframes } from "styled-components"; 3 | import { useNavigo } from "navigo-react"; 4 | 5 | type CardContainerTypes = { 6 | leaving?: boolean; 7 | bgColor?: string; 8 | }; 9 | 10 | const IN = keyframes` 11 | 0% { opacity: 0; transform: translateX(200px); } 12 | 100% { opacity: 1; transform: translateX(0); } 13 | `; 14 | const OUT = keyframes` 15 | 0% { opacity: 1; transform: translateX(0); } 16 | 100% { opacity: 0; transform: translateX(-200px); } 17 | `; 18 | 19 | const CardContainer = styled.div` 20 | width: 300px; 21 | height: 450px; 22 | border-radius: 10px; 23 | display: grid; 24 | align-items: center; 25 | text-align: center; 26 | background: ${(props) => props.bgColor || "#1f431f"}; 27 | color: #fff; 28 | margin: 0 auto; 29 | transform-origin: center; 30 | border: solid 2px #4f4f4f; 31 | box-shadow: 0px 0px 15px -3px #000000; 32 | animation: ${(props) => (props.leaving ? OUT : IN)} 1000ms cubic-bezier(1, -0.28, 0.28, 1.49); 33 | `; 34 | 35 | const Paragraph = styled.p` 36 | padding: 0 1em; 37 | font-size: 1.2em; 38 | line-height: 1.4; 39 | `; 40 | 41 | export default function Card({ children, bgColor }: { children: any; bgColor?: string }) { 42 | const { leaving } = useNavigo(); 43 | 44 | return ( 45 | 46 | {children} 47 | 48 | ); 49 | } 50 | -------------------------------------------------------------------------------- /example/transition/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | import { Route, Switch } from "navigo-react"; 4 | 5 | import Card from "./Card"; 6 | 7 | const delay = (time: number) => new Promise((done) => setTimeout(done, time)); 8 | 9 | type ContainerProps = { 10 | padding?: string | 0; 11 | margin?: string | 0; 12 | }; 13 | 14 | export const Container = styled.div` 15 | padding: 3em 0 0 0; 16 | margin: ${(props) => ("margin" in props ? props.margin : 0)}; 17 | `; 18 | const leaveHook = (path: string) => async (done: Function) => { 19 | // console.log(`Leave hook for ${path}`); 20 | done({ leaving: true }); 21 | await delay(900); 22 | done(true); 23 | }; 24 | 25 | export default function App() { 26 | return ( 27 | 28 | 29 | 30 | 31 | Card #2. 32 |
33 | 34 | Click here 35 | {" "} 36 | to go back 37 |
38 |
39 | 40 | 41 | Welcome to the transition example.{" "} 42 | 43 | Click here 44 | {" "} 45 | to open the other card. 46 | 47 | 48 |
49 |
50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import Navigo, { Match, RouteHooks } from "navigo"; 2 | 3 | export type NotFoundRouteProps = { 4 | children: any; 5 | hooks?: RouteHooks; 6 | }; 7 | export type NavigoSwitchContextType = { 8 | isInSwitch: boolean; 9 | switchMatch: false | Match; 10 | }; 11 | export type Path = { path: string }; 12 | export type NavigoRouting = { 13 | match: false | Match; 14 | [key: string]: Any; 15 | }; 16 | export type BlockingLifecycleFuncArgs = { render: Function; done: Function; match: Match }; 17 | export type NonBlockingLifecycleFuncArgs = { render: Function; match: Match }; 18 | export type BlockingLifecycleFunc = (arg: BlockingLifecycleFuncArgs) => void; 19 | export type NonBlockingLifecycleFunc = (arg: NonBlockingLifecycleFuncArgs) => void; 20 | export type RouteProps = { 21 | path: string; 22 | children?: any; 23 | name?: string; 24 | before?: BlockingLifecycleFunc; 25 | after?: NonBlockingLifecycleFunc; 26 | already?: NonBlockingLifecycleFunc; 27 | leave?: BlockingLifecycleFunc; 28 | }; 29 | 30 | // utils 31 | export function configureRouter(root: string): Navigo; 32 | export function reset(): void; 33 | export function getRouter(): Navigo; 34 | 35 | // components 36 | export function Base(props: Path); 37 | export function Route(props: RouteProps); 38 | export function NotFound(props: NotFoundRouteProps); 39 | export function Redirect(props: Path); 40 | export function Switch(props: { children?: any }); 41 | 42 | // hooks 43 | export function useNavigo(): NavigoRouting; 44 | export function useLocation(): Match; 45 | -------------------------------------------------------------------------------- /example/protect/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import styled from "styled-components"; 3 | import { Route, Switch, getRouter, useNavigo } from "navigo-react"; 4 | 5 | type ContainerProps = { 6 | padding?: string | 0; 7 | margin?: string | 0; 8 | }; 9 | 10 | const Container = styled.div` 11 | padding: 3em; 12 | margin: ${(props) => ("margin" in props ? props.margin : 0)}; 13 | `; 14 | 15 | const Button = styled.button` 16 | padding: 1em; 17 | border-radius: 4px; 18 | border: solid 2px #17681e; 19 | background: #134907; 20 | color: white; 21 | font-size: 1em; 22 | `; 23 | 24 | let authorized = false; 25 | 26 | function Login() { 27 | const { match } = useNavigo(); 28 | return ( 29 | 38 | ); 39 | } 40 | 41 | export default function App() { 42 | return ( 43 | 44 | 45 | 46 | 47 | 48 | { 51 | if (authorized) { 52 | done(true); 53 | } else { 54 | done(false); 55 | getRouter().navigate("/login?r=get-data"); 56 | } 57 | }} 58 | > 59 |

💰

60 |
61 | 62 | 63 | Get the protected data 64 | 65 | 66 |
67 |
68 | ); 69 | } 70 | -------------------------------------------------------------------------------- /src/__tests__/NotFound.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "@testing-library/jest-dom/extend-expect"; 3 | import { render, waitFor } from "@testing-library/react"; 4 | import { reset, Route, useNavigo, NotFound } from "../NavigoReact"; 5 | 6 | import { expectContent, navigate } from "../__tests_helpers__/utils"; 7 | import About from "../__tests_helpers__/components/About"; 8 | 9 | let warn: jest.SpyInstance; 10 | 11 | describe("Given navigo-react", () => { 12 | beforeEach(() => { 13 | reset(); 14 | warn = jest.spyOn(console, "warn").mockImplementation(() => {}); 15 | history.pushState({}, "", "/"); 16 | }); 17 | afterEach(() => { 18 | if (warn) { 19 | warn.mockReset(); 20 | } 21 | }); 22 | describe("when using the NotFound component", () => { 23 | it("should allow us to handle the not-found route", async () => { 24 | history.pushState({}, "", "/about"); 25 | const spy = jest.fn(); 26 | function Comp() { 27 | const { match } = useNavigo(); 28 | if (match) { 29 | spy(match); 30 | } 31 | return

not found

; 32 | } 33 | 34 | render( 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 | ); 44 | 45 | expectContent("About"); 46 | await waitFor(() => { 47 | navigate("/nah"); 48 | }); 49 | expectContent("not found"); 50 | expect(spy).toBeCalledTimes(1); 51 | expect(spy).toBeCalledWith({ 52 | url: "nah", 53 | queryString: "", 54 | data: null, 55 | route: { 56 | name: "__NOT_FOUND__", 57 | path: "nah", 58 | handler: expect.any(Function), 59 | hooks: expect.any(Object), 60 | }, 61 | params: null, 62 | }); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /src/__tests__/hooks.spec.tsx: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom/extend-expect"; 2 | import React from "react"; 3 | import { render } from "@testing-library/react"; 4 | import { reset, useNavigo, useLocation } from "../NavigoReact"; 5 | 6 | import { expectContent } from "../__tests_helpers__/utils"; 7 | 8 | const ROOT = "something"; 9 | let warn: jest.SpyInstance; 10 | 11 | describe("Given navigo-react", () => { 12 | beforeEach(() => { 13 | reset(); 14 | warn = jest.spyOn(console, "warn").mockImplementation(() => {}); 15 | history.pushState({}, "", "/"); 16 | }); 17 | afterEach(() => { 18 | if (warn) { 19 | warn.mockReset(); 20 | } 21 | }); 22 | describe("when using the `useNavigo` hook", () => { 23 | it("should return `false` from `useNavigo` if there is no match or a context", () => { 24 | const CompA = jest.fn().mockImplementation(() => { 25 | const { match } = useNavigo(); 26 | if (!match) { 27 | return

Nope

; 28 | } 29 | return

Never

; 30 | }); 31 | render( 32 |
33 | 34 |
35 | ); 36 | 37 | expect(CompA).toBeCalledTimes(1); 38 | expectContent("Nope"); 39 | }); 40 | it("should return `false` from `useNavigo` if there is no match or a context", () => { 41 | const CompA = jest.fn().mockImplementation(() => { 42 | const { match } = useNavigo(); 43 | if (!match) { 44 | return

Nope

; 45 | } 46 | return

Never

; 47 | }); 48 | render( 49 |
50 | 51 |
52 | ); 53 | 54 | expect(CompA).toBeCalledTimes(1); 55 | expectContent("Nope"); 56 | }); 57 | }); 58 | describe("when we use the `useLocation` hook", () => { 59 | it("should gives us access to the current location of the browser", () => { 60 | history.pushState({}, "", "/about?a=b"); 61 | expect(useLocation()).toStrictEqual({ 62 | url: "about", 63 | queryString: "a=b", 64 | route: { 65 | name: "about", 66 | path: "about", 67 | handler: expect.any(Function), 68 | hooks: {}, 69 | }, 70 | data: null, 71 | params: { a: "b" }, 72 | }); 73 | }); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /src/__tests__/Switch.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "@testing-library/jest-dom/extend-expect"; 3 | import { render, waitFor } from "@testing-library/react"; 4 | import { reset, Route, Switch, getRouter, configureRouter } from "../NavigoReact"; 5 | 6 | import { expectContent, navigate, delay } from "../__tests_helpers__/utils"; 7 | 8 | let warn: jest.SpyInstance; 9 | 10 | describe("Given navigo-react", () => { 11 | beforeEach(() => { 12 | reset(); 13 | warn = jest.spyOn(console, "warn").mockImplementation(() => {}); 14 | history.pushState({}, "", "/"); 15 | }); 16 | afterEach(() => { 17 | if (warn) { 18 | warn.mockReset(); 19 | } 20 | }); 21 | describe("when using the Switch component", () => { 22 | it("should resolve only one of the routes in the list", async () => { 23 | render( 24 |
25 | 26 | A 27 | B 28 | C 29 | D 30 | 31 |
32 | E 33 |
34 |
35 | ); 36 | 37 | expectContent("C"); 38 | await waitFor(() => { 39 | navigate("bar"); 40 | }); 41 | expectContent("BE"); 42 | await waitFor(() => { 43 | navigate("nope"); 44 | }); 45 | expectContent("D"); 46 | await waitFor(() => { 47 | navigate("foo"); 48 | }); 49 | expectContent("A"); 50 | }); 51 | describe("and when we have a router root set", () => { 52 | it("should resolve only one of the routes in the list #2", async () => { 53 | history.pushState({}, "", "/app"); 54 | configureRouter("/app"); 55 | render( 56 |
57 | 58 | A 59 | B 60 | C 61 | 62 |
63 | E 64 |
65 |
66 | ); 67 | 68 | expectContent("C"); 69 | await waitFor(() => { 70 | navigate("bar"); 71 | }); 72 | expectContent("BE"); 73 | }); 74 | }); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "navigo-react", 3 | "version": "2.0.3", 4 | "main": "lib/cjs/NavigoReact.js", 5 | "browser": "lib/NavigoReact.min.js", 6 | "module": "lib/es/NavigoReact.js", 7 | "types": "./index.d.ts", 8 | "author": { 9 | "name": "Krasimir Tsonev", 10 | "email": "me@krasimir.dev", 11 | "url": "http://krasimirtsonev.com/blog" 12 | }, 13 | "license": "MIT", 14 | "keywords": [ 15 | "router", 16 | "react", 17 | "navigo", 18 | "history" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "git@github.com:krasimir/navigo-react.git" 23 | }, 24 | "devDependencies": { 25 | "@babel/cli": "7.12.10", 26 | "@babel/core": "7.5.0", 27 | "@babel/plugin-transform-regenerator": "7.4.5", 28 | "@babel/plugin-transform-runtime": "7.5.0", 29 | "@babel/preset-env": "7.5.0", 30 | "@babel/preset-react": "7.0.0", 31 | "@babel/preset-typescript": "7.12.7", 32 | "@babel/runtime": "7.5.0", 33 | "@testing-library/jest-dom": "5.11.8", 34 | "@testing-library/react": "11.2.2", 35 | "@types/jest": "26.0.19", 36 | "@types/react": "17.0.0", 37 | "@types/react-dom": "17.0.0", 38 | "@types/styled-components": "5.1.7", 39 | "babel-jest": "26.6.3", 40 | "babel-loader": "8.0.4", 41 | "jest": "26.6.3", 42 | "prettier": "1.19.1", 43 | "prop-types": "15.7.2", 44 | "react": "16.9.0", 45 | "react-dom": "16.9.0", 46 | "regenerator-runtime": "0.13.2", 47 | "styled-components": "5.0.0", 48 | "terser-webpack-plugin": "1.2.3", 49 | "ts-loader": "6.2.1", 50 | "typescript": "3.8.3", 51 | "webpack": "4.41.6", 52 | "webpack-cli": "3.1.2", 53 | "webpack-dev-server": "3.10.3" 54 | }, 55 | "dependencies": { 56 | "navigo": "8.7.1" 57 | }, 58 | "scripts": { 59 | "build": "yarn test && yarn transform", 60 | "transform": "webpack --config ./webpack.config.js && yarn build-es && yarn build-commonjs", 61 | "build-commonjs": "babel src --out-dir lib/cjs --extensions '.ts,.tsx' --ignore '**/*.spec.tsx','src/__tests_helpers__/**/*.tsx' --source-maps", 62 | "build-es": "babel src --no-babelrc --out-dir lib/es --extensions '.ts,.tsx' --ignore '**/*.spec.tsx','src/__tests_helpers__/**/*.tsx' --config-file ./.babelrc.es", 63 | "test": "./node_modules/.bin/jest ./src/__tests__/*.spec.tsx", 64 | "test-watch": "./node_modules/.bin/jest ./src/__tests__/*.spec.tsx --watch" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/__tests__/NavigoReact.spec.tsx: -------------------------------------------------------------------------------- 1 | import { Match } from "navigo/index.d"; 2 | import "@testing-library/jest-dom/extend-expect"; 3 | import React, { useEffect, useRef, useState } from "react"; 4 | import { render, fireEvent, waitFor } from "@testing-library/react"; 5 | import { configureRouter, getRouter, reset, Route, useNavigo, NotFound, Redirect } from "../NavigoReact"; 6 | 7 | import { expectContent, delay } from "../__tests_helpers__/utils"; 8 | 9 | import About from "../__tests_helpers__/components/About"; 10 | import Team from "../__tests_helpers__/components/Team"; 11 | 12 | const ROOT = "something"; 13 | let warn: jest.SpyInstance; 14 | 15 | describe("Given navigo-react", () => { 16 | beforeEach(() => { 17 | reset(); 18 | warn = jest.spyOn(console, "warn").mockImplementation(() => {}); 19 | history.pushState({}, "", "/"); 20 | }); 21 | afterEach(() => { 22 | if (warn) { 23 | warn.mockReset(); 24 | } 25 | }); 26 | describe("when we configure the router", () => { 27 | it("should set a proper root", () => { 28 | const r = configureRouter(ROOT); 29 | // @ts-ignore 30 | expect(r.root).toEqual(ROOT); 31 | }); 32 | }); 33 | describe("when we want to implement a nesting routes", () => { 34 | it("should be possible to do it by using Route and useNavigo", async () => { 35 | function CompA() { 36 | const { match } = useNavigo(); 37 | if (!match) return null; 38 | // @ts-ignore 39 | const id = match.data.id; 40 | return ( 41 | <> 42 |

A

43 | 44 |

B{id}

45 |
46 | 47 | ); 48 | } 49 | 50 | render( 51 |
52 | 53 | 54 | 55 |
56 | ); 57 | expectContent(""); 58 | await waitFor(() => { 59 | getRouter().navigate("/foo/20"); 60 | }); 61 | expectContent("A"); 62 | await waitFor(() => { 63 | getRouter().navigate("/foo/20/save"); 64 | }); 65 | expectContent("AB20"); 66 | }); 67 | }); 68 | describe("when we switch between routes", () => { 69 | it("should properly unload the old components and render the new one", async () => { 70 | history.pushState({}, "", "/about/team"); 71 | 72 | render( 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | Team-footer 81 |
82 | ); 83 | expectContent("TeamTeam-footer"); 84 | await waitFor(() => { 85 | getRouter().navigate("/about"); 86 | }); 87 | expectContent("About"); 88 | }); 89 | }); 90 | describe("when we want to redirect (in case of not-found path)", () => { 91 | it("should provide an API for redirecting", async () => { 92 | history.pushState({}, "", "/nah"); 93 | render( 94 |
95 | 96 | 97 | 98 | 99 | 100 | 101 |
102 | ); 103 | expectContent("About"); 104 | }); 105 | }); 106 | describe("when we want to redirect (in case of not authorized access)", () => { 107 | it("should provide an API for redirecting", async () => { 108 | history.pushState({}, "", "/about"); 109 | const Auth = ({ children }: { children: any }) => { 110 | const [authorized, setAuthorized] = useState(false); 111 | const location = useRef(getRouter().getCurrentLocation()); 112 | 113 | useEffect(() => { 114 | setTimeout(() => { 115 | waitFor(() => { 116 | setAuthorized(true); 117 | getRouter().navigate(location.current.url); 118 | }); 119 | }, 10); 120 | }, []); 121 | 122 | if (authorized) { 123 | return children; 124 | } 125 | return ; 126 | }; 127 | render( 128 |
129 | 130 | 131 | 132 | 133 | 134 | Login 135 |
136 | ); 137 | expectContent("Login"); 138 | await delay(20); 139 | expectContent("About"); 140 | }); 141 | }); 142 | }); 143 | -------------------------------------------------------------------------------- /src/NavigoReact.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect, useState, useContext, useReducer } from "react"; 2 | import Navigo, { Match as NavigoMatch, RouteHooks as NavigoHooks, Route as NavigoRoute } from "navigo"; 3 | // import Navigo, { Match as NavigoMatch, RouteHooks as NavigoHooks, Route as NavigoRoute } from "../../navigo"; 4 | 5 | import { RouteProps, Path, NotFoundRouteProps, NavigoSwitchContextType, NavigoRouting } from "../index.d"; 6 | 7 | let router: Navigo | undefined; 8 | let Context = React.createContext({ match: false } as NavigoRouting); 9 | let SwitchContext = React.createContext({ isInSwitch: false, switchMatch: false } as NavigoSwitchContextType); 10 | 11 | // types 12 | export type Match = NavigoMatch; 13 | export type RouteHooks = NavigoHooks; 14 | 15 | export function getRouter(root?: string): Navigo { 16 | if (router) { 17 | return router; 18 | } 19 | // @ts-ignore 20 | router = window.R = new Navigo(root || "/", { strategy: "ALL", noMatchWarning: true }); 21 | // @ts-ignore 22 | window.router = router; 23 | return router; 24 | } 25 | function nextTick(callback: Function) { 26 | setTimeout(() => callback(), 0); 27 | } 28 | 29 | // utils 30 | export function configureRouter(root: string) { 31 | return getRouter(root); 32 | } 33 | export function reset() { 34 | if (router) { 35 | router.destroy(); 36 | router = undefined; 37 | } 38 | } 39 | 40 | // components 41 | export function Route({ path, children, before, after, already, leave, name }: RouteProps) { 42 | const route = useRef(undefined); 43 | const [context, setContext] = useReducer((state: NavigoRouting, action: NavigoRouting) => ({ ...state, ...action }), { 44 | match: false, 45 | }); 46 | const switchContext = useContext(SwitchContext); 47 | const renderChild = () => {children}; 48 | const noneBlockingHook = (func: Function) => (match: Match) => { 49 | func({ 50 | render: (result: any) => setContext({ ...result, match }), 51 | match, 52 | }); 53 | }; 54 | const blockingHook = (func: Function) => (done: Function, match: Match) => { 55 | func({ 56 | render: (result: any) => setContext({ ...result, match, __allowRender: true }), 57 | done, 58 | match, 59 | }); 60 | }; 61 | 62 | // creating the route + attaching hooks 63 | useEffect(() => { 64 | let isMounted = true; 65 | const router = getRouter(); 66 | const handler = (match: false | Match) => { 67 | if (isMounted) { 68 | setContext({ match }); 69 | } 70 | nextTick(() => getRouter().updatePageLinks()); 71 | }; 72 | // creating the route 73 | router.on(path, handler); 74 | const navigoRoute = (route.current = router.getRoute(handler)); 75 | if (navigoRoute && name) { 76 | navigoRoute.name = name; 77 | } 78 | // hooking 79 | if (before) { 80 | router.addBeforeHook(navigoRoute as NavigoRoute, blockingHook(before)); 81 | } 82 | if (after) { 83 | router.addAfterHook(navigoRoute as NavigoRoute, noneBlockingHook(after)); 84 | } 85 | if (already) { 86 | router.addAlreadyHook(navigoRoute as NavigoRoute, noneBlockingHook(already)); 87 | } 88 | if (leave) { 89 | router.addLeaveHook(navigoRoute as NavigoRoute, blockingHook(leave)); 90 | } 91 | // adding the service leave hook 92 | router.addLeaveHook(navigoRoute as NavigoRoute, (done: Function) => { 93 | if (isMounted) { 94 | setContext({ match: false }); 95 | } 96 | done(); 97 | }); 98 | // initial resolving 99 | router.resolve(); 100 | // initial data-navigo set up 101 | router.updatePageLinks(); 102 | return () => { 103 | isMounted = false; 104 | router.off(handler); 105 | }; 106 | }, []); 107 | 108 | // make sure that the lifecycle funcs have access to the latest local state values 109 | useEffect(() => { 110 | if (before && route.current && route.current.hooks.before && route.current.hooks.before[0]) { 111 | // @ts-ignore 112 | route.current.hooks.before[0] = blockingHook(before); 113 | } 114 | if (after && route.current && route.current.hooks.after && route.current.hooks.after[0]) { 115 | // @ts-ignore 116 | route.current.hooks.after[0] = noneBlockingHook(after); 117 | } 118 | if (already && route.current && route.current.hooks.already && route.current.hooks.already[0]) { 119 | // @ts-ignore 120 | route.current.hooks.already[0] = noneBlockingHook(already); 121 | } 122 | // @ts-ignore 123 | if (leave && route.current && route.current.hooks.leave.length === 2) { 124 | // @ts-ignore 125 | route.current.hooks.leave[0] = blockingHook(leave); 126 | } 127 | }, [before, after, already, leave]); 128 | 129 | if (context.__allowRender) { 130 | return renderChild(); 131 | } else if (switchContext.isInSwitch && context.match) { 132 | if (switchContext.switchMatch) { 133 | if (switchContext.switchMatch.route.path === context.match.route.path) { 134 | return renderChild(); 135 | } 136 | } else { 137 | switchContext.switchMatch = context.match; 138 | return renderChild(); 139 | } 140 | } else if (context.match) { 141 | return renderChild(); 142 | } 143 | return null; 144 | } 145 | export function Base({ path }: Path) { 146 | getRouter(path); 147 | return null; 148 | } 149 | export function Switch({ children }: { children?: any }) { 150 | const [match, setMatch] = useState(false); 151 | useEffect(() => { 152 | function switchHandler(match: Match) { 153 | setMatch(match); 154 | } 155 | getRouter().on("*", switchHandler); 156 | return () => { 157 | getRouter().off(switchHandler); 158 | }; 159 | }, []); 160 | return ( 161 | 165 | {children} 166 | 167 | ); 168 | } 169 | export function NotFound({ children, hooks }: NotFoundRouteProps) { 170 | const match = useNotFound(hooks); 171 | 172 | if (match) { 173 | return {children}; 174 | } 175 | return null; 176 | } 177 | export function Redirect({ path }: Path) { 178 | useEffect(() => { 179 | getRouter().navigate(path); 180 | }, []); 181 | return null; 182 | } 183 | 184 | // hooks 185 | export function useNavigo(): NavigoRouting { 186 | return useContext(Context); 187 | } 188 | export function useLocation(): Match { 189 | return getRouter().getCurrentLocation(); 190 | } 191 | 192 | // internal hooks 193 | function useNotFound(hooks?: RouteHooks | undefined): false | Match { 194 | const [match, setMatch] = useState(false); 195 | const handler = useRef((match: false | Match) => { 196 | setMatch(match); 197 | nextTick(() => getRouter().updatePageLinks()); 198 | }); 199 | 200 | useEffect(() => { 201 | // @ts-ignore 202 | const router = getRouter(); 203 | router.notFound(handler.current, hooks); 204 | router.addLeaveHook("__NOT_FOUND__", (done: Function) => { 205 | setMatch(false); 206 | done(); 207 | }); 208 | router.resolve(); 209 | router.updatePageLinks(); 210 | return () => { 211 | router.off(handler.current); 212 | }; 213 | }, []); 214 | 215 | return match; 216 | } 217 | 218 | const API = { 219 | getRouter, 220 | configureRouter, 221 | reset, 222 | Route, 223 | Base, 224 | Switch, 225 | NotFound, 226 | Redirect, 227 | useNavigo, 228 | useLocation, 229 | }; 230 | 231 | export default API; 232 | -------------------------------------------------------------------------------- /lib/es/NavigoReact.js: -------------------------------------------------------------------------------- 1 | import _extends from "@babel/runtime/helpers/extends"; 2 | import React, { useRef, useEffect, useState, useContext, useReducer } from "react"; 3 | import Navigo from "navigo"; // import Navigo, { Match as NavigoMatch, RouteHooks as NavigoHooks, Route as NavigoRoute } from "../../navigo"; 4 | 5 | var router; 6 | var Context = React.createContext({ 7 | match: false 8 | }); 9 | var SwitchContext = React.createContext({ 10 | isInSwitch: false, 11 | switchMatch: false 12 | }); // types 13 | 14 | export function getRouter(root) { 15 | if (router) { 16 | return router; 17 | } // @ts-ignore 18 | 19 | 20 | router = window.R = new Navigo(root || "/", { 21 | strategy: "ALL", 22 | noMatchWarning: true 23 | }); // @ts-ignore 24 | 25 | window.router = router; 26 | return router; 27 | } 28 | 29 | function nextTick(callback) { 30 | setTimeout(function () { 31 | return callback(); 32 | }, 0); 33 | } // utils 34 | 35 | 36 | export function configureRouter(root) { 37 | return getRouter(root); 38 | } 39 | export function reset() { 40 | if (router) { 41 | router.destroy(); 42 | router = undefined; 43 | } 44 | } // components 45 | 46 | export function Route(_ref) { 47 | var path = _ref.path, 48 | children = _ref.children, 49 | before = _ref.before, 50 | after = _ref.after, 51 | already = _ref.already, 52 | leave = _ref.leave, 53 | name = _ref.name; 54 | var route = useRef(undefined); 55 | 56 | var _useReducer = useReducer(function (state, action) { 57 | return _extends({}, state, action); 58 | }, { 59 | match: false 60 | }), 61 | context = _useReducer[0], 62 | setContext = _useReducer[1]; 63 | 64 | var switchContext = useContext(SwitchContext); 65 | 66 | var renderChild = function renderChild() { 67 | return /*#__PURE__*/React.createElement(Context.Provider, { 68 | value: context 69 | }, children); 70 | }; 71 | 72 | var noneBlockingHook = function noneBlockingHook(func) { 73 | return function (match) { 74 | func({ 75 | render: function render(result) { 76 | return setContext(_extends({}, result, { 77 | match: match 78 | })); 79 | }, 80 | match: match 81 | }); 82 | }; 83 | }; 84 | 85 | var blockingHook = function blockingHook(func) { 86 | return function (done, match) { 87 | func({ 88 | render: function render(result) { 89 | return setContext(_extends({}, result, { 90 | match: match, 91 | __allowRender: true 92 | })); 93 | }, 94 | done: done, 95 | match: match 96 | }); 97 | }; 98 | }; // creating the route + attaching hooks 99 | 100 | 101 | useEffect(function () { 102 | var isMounted = true; 103 | var router = getRouter(); 104 | 105 | var handler = function handler(match) { 106 | if (isMounted) { 107 | setContext({ 108 | match: match 109 | }); 110 | } 111 | 112 | nextTick(function () { 113 | return getRouter().updatePageLinks(); 114 | }); 115 | }; // creating the route 116 | 117 | 118 | router.on(path, handler); 119 | var navigoRoute = route.current = router.getRoute(handler); 120 | 121 | if (navigoRoute && name) { 122 | navigoRoute.name = name; 123 | } // hooking 124 | 125 | 126 | if (before) { 127 | router.addBeforeHook(navigoRoute, blockingHook(before)); 128 | } 129 | 130 | if (after) { 131 | router.addAfterHook(navigoRoute, noneBlockingHook(after)); 132 | } 133 | 134 | if (already) { 135 | router.addAlreadyHook(navigoRoute, noneBlockingHook(already)); 136 | } 137 | 138 | if (leave) { 139 | router.addLeaveHook(navigoRoute, blockingHook(leave)); 140 | } // adding the service leave hook 141 | 142 | 143 | router.addLeaveHook(navigoRoute, function (done) { 144 | if (isMounted) { 145 | setContext({ 146 | match: false 147 | }); 148 | } 149 | 150 | done(); 151 | }); // initial resolving 152 | 153 | router.resolve(); // initial data-navigo set up 154 | 155 | router.updatePageLinks(); 156 | return function () { 157 | isMounted = false; 158 | router.off(handler); 159 | }; 160 | }, []); // make sure that the lifecycle funcs have access to the latest local state values 161 | 162 | useEffect(function () { 163 | if (before && route.current && route.current.hooks.before && route.current.hooks.before[0]) { 164 | // @ts-ignore 165 | route.current.hooks.before[0] = blockingHook(before); 166 | } 167 | 168 | if (after && route.current && route.current.hooks.after && route.current.hooks.after[0]) { 169 | // @ts-ignore 170 | route.current.hooks.after[0] = noneBlockingHook(after); 171 | } 172 | 173 | if (already && route.current && route.current.hooks.already && route.current.hooks.already[0]) { 174 | // @ts-ignore 175 | route.current.hooks.already[0] = noneBlockingHook(already); 176 | } // @ts-ignore 177 | 178 | 179 | if (leave && route.current && route.current.hooks.leave.length === 2) { 180 | // @ts-ignore 181 | route.current.hooks.leave[0] = blockingHook(leave); 182 | } 183 | }, [before, after, already, leave]); 184 | 185 | if (context.__allowRender) { 186 | return renderChild(); 187 | } else if (switchContext.isInSwitch && context.match) { 188 | if (switchContext.switchMatch) { 189 | if (switchContext.switchMatch.route.path === context.match.route.path) { 190 | return renderChild(); 191 | } 192 | } else { 193 | switchContext.switchMatch = context.match; 194 | return renderChild(); 195 | } 196 | } else if (context.match) { 197 | return renderChild(); 198 | } 199 | 200 | return null; 201 | } 202 | export function Base(_ref2) { 203 | var path = _ref2.path; 204 | getRouter(path); 205 | return null; 206 | } 207 | export function Switch(_ref3) { 208 | var children = _ref3.children; 209 | 210 | var _useState = useState(false), 211 | match = _useState[0], 212 | setMatch = _useState[1]; 213 | 214 | useEffect(function () { 215 | function switchHandler(match) { 216 | setMatch(match); 217 | } 218 | 219 | getRouter().on("*", switchHandler); 220 | return function () { 221 | getRouter().off(switchHandler); 222 | }; 223 | }, []); 224 | return /*#__PURE__*/React.createElement(SwitchContext.Provider, { 225 | value: { 226 | switchMatch: false, 227 | isInSwitch: true 228 | }, 229 | key: match ? match.url : "switch" + new Date().getTime() 230 | }, children); 231 | } 232 | export function NotFound(_ref4) { 233 | var children = _ref4.children, 234 | hooks = _ref4.hooks; 235 | var match = useNotFound(hooks); 236 | 237 | if (match) { 238 | return /*#__PURE__*/React.createElement(Context.Provider, { 239 | value: { 240 | match: match 241 | } 242 | }, children); 243 | } 244 | 245 | return null; 246 | } 247 | export function Redirect(_ref5) { 248 | var path = _ref5.path; 249 | useEffect(function () { 250 | getRouter().navigate(path); 251 | }, []); 252 | return null; 253 | } // hooks 254 | 255 | export function useNavigo() { 256 | return useContext(Context); 257 | } 258 | export function useLocation() { 259 | return getRouter().getCurrentLocation(); 260 | } // internal hooks 261 | 262 | function useNotFound(hooks) { 263 | var _useState2 = useState(false), 264 | match = _useState2[0], 265 | setMatch = _useState2[1]; 266 | 267 | var handler = useRef(function (match) { 268 | setMatch(match); 269 | nextTick(function () { 270 | return getRouter().updatePageLinks(); 271 | }); 272 | }); 273 | useEffect(function () { 274 | // @ts-ignore 275 | var router = getRouter(); 276 | router.notFound(handler.current, hooks); 277 | router.addLeaveHook("__NOT_FOUND__", function (done) { 278 | setMatch(false); 279 | done(); 280 | }); 281 | router.resolve(); 282 | router.updatePageLinks(); 283 | return function () { 284 | router.off(handler.current); 285 | }; 286 | }, []); 287 | return match; 288 | } 289 | 290 | var API = { 291 | getRouter: getRouter, 292 | configureRouter: configureRouter, 293 | reset: reset, 294 | Route: Route, 295 | Base: Base, 296 | Switch: Switch, 297 | NotFound: NotFound, 298 | Redirect: Redirect, 299 | useNavigo: useNavigo, 300 | useLocation: useLocation 301 | }; 302 | export default API; -------------------------------------------------------------------------------- /lib/cjs/NavigoReact.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); 4 | 5 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); 6 | 7 | Object.defineProperty(exports, "__esModule", { 8 | value: true 9 | }); 10 | exports.getRouter = getRouter; 11 | exports.configureRouter = configureRouter; 12 | exports.reset = reset; 13 | exports.Route = Route; 14 | exports.Base = Base; 15 | exports.Switch = Switch; 16 | exports.NotFound = NotFound; 17 | exports.Redirect = Redirect; 18 | exports.useNavigo = useNavigo; 19 | exports.useLocation = useLocation; 20 | exports["default"] = void 0; 21 | 22 | var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); 23 | 24 | var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); 25 | 26 | var _react = _interopRequireWildcard(require("react")); 27 | 28 | var _navigo = _interopRequireDefault(require("navigo")); 29 | 30 | function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } 31 | 32 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } 33 | 34 | var router; 35 | 36 | var Context = _react["default"].createContext({ 37 | match: false 38 | }); 39 | 40 | var SwitchContext = _react["default"].createContext({ 41 | isInSwitch: false, 42 | switchMatch: false 43 | }); // types 44 | 45 | 46 | function getRouter(root) { 47 | if (router) { 48 | return router; 49 | } // @ts-ignore 50 | 51 | 52 | router = window.R = new _navigo["default"](root || "/", { 53 | strategy: "ALL", 54 | noMatchWarning: true 55 | }); // @ts-ignore 56 | 57 | window.router = router; 58 | return router; 59 | } 60 | 61 | function nextTick(callback) { 62 | setTimeout(function () { 63 | return callback(); 64 | }, 0); 65 | } // utils 66 | 67 | 68 | function configureRouter(root) { 69 | return getRouter(root); 70 | } 71 | 72 | function reset() { 73 | if (router) { 74 | router.destroy(); 75 | router = undefined; 76 | } 77 | } // components 78 | 79 | 80 | function Route(_ref) { 81 | var path = _ref.path, 82 | children = _ref.children, 83 | before = _ref.before, 84 | after = _ref.after, 85 | already = _ref.already, 86 | leave = _ref.leave, 87 | name = _ref.name; 88 | var route = (0, _react.useRef)(undefined); 89 | 90 | var _useReducer = (0, _react.useReducer)(function (state, action) { 91 | return _objectSpread(_objectSpread({}, state), action); 92 | }, { 93 | match: false 94 | }), 95 | _useReducer2 = (0, _slicedToArray2["default"])(_useReducer, 2), 96 | context = _useReducer2[0], 97 | setContext = _useReducer2[1]; 98 | 99 | var switchContext = (0, _react.useContext)(SwitchContext); 100 | 101 | var renderChild = function renderChild() { 102 | return /*#__PURE__*/_react["default"].createElement(Context.Provider, { 103 | value: context 104 | }, children); 105 | }; 106 | 107 | var noneBlockingHook = function noneBlockingHook(func) { 108 | return function (match) { 109 | func({ 110 | render: function render(result) { 111 | return setContext(_objectSpread(_objectSpread({}, result), {}, { 112 | match: match 113 | })); 114 | }, 115 | match: match 116 | }); 117 | }; 118 | }; 119 | 120 | var blockingHook = function blockingHook(func) { 121 | return function (done, match) { 122 | func({ 123 | render: function render(result) { 124 | return setContext(_objectSpread(_objectSpread({}, result), {}, { 125 | match: match, 126 | __allowRender: true 127 | })); 128 | }, 129 | done: done, 130 | match: match 131 | }); 132 | }; 133 | }; // creating the route + attaching hooks 134 | 135 | 136 | (0, _react.useEffect)(function () { 137 | var isMounted = true; 138 | var router = getRouter(); 139 | 140 | var handler = function handler(match) { 141 | if (isMounted) { 142 | setContext({ 143 | match: match 144 | }); 145 | } 146 | 147 | nextTick(function () { 148 | return getRouter().updatePageLinks(); 149 | }); 150 | }; // creating the route 151 | 152 | 153 | router.on(path, handler); 154 | var navigoRoute = route.current = router.getRoute(handler); 155 | 156 | if (navigoRoute && name) { 157 | navigoRoute.name = name; 158 | } // hooking 159 | 160 | 161 | if (before) { 162 | router.addBeforeHook(navigoRoute, blockingHook(before)); 163 | } 164 | 165 | if (after) { 166 | router.addAfterHook(navigoRoute, noneBlockingHook(after)); 167 | } 168 | 169 | if (already) { 170 | router.addAlreadyHook(navigoRoute, noneBlockingHook(already)); 171 | } 172 | 173 | if (leave) { 174 | router.addLeaveHook(navigoRoute, blockingHook(leave)); 175 | } // adding the service leave hook 176 | 177 | 178 | router.addLeaveHook(navigoRoute, function (done) { 179 | if (isMounted) { 180 | setContext({ 181 | match: false 182 | }); 183 | } 184 | 185 | done(); 186 | }); // initial resolving 187 | 188 | router.resolve(); // initial data-navigo set up 189 | 190 | router.updatePageLinks(); 191 | return function () { 192 | isMounted = false; 193 | router.off(handler); 194 | }; 195 | }, []); // make sure that the lifecycle funcs have access to the latest local state values 196 | 197 | (0, _react.useEffect)(function () { 198 | if (before && route.current && route.current.hooks.before && route.current.hooks.before[0]) { 199 | // @ts-ignore 200 | route.current.hooks.before[0] = blockingHook(before); 201 | } 202 | 203 | if (after && route.current && route.current.hooks.after && route.current.hooks.after[0]) { 204 | // @ts-ignore 205 | route.current.hooks.after[0] = noneBlockingHook(after); 206 | } 207 | 208 | if (already && route.current && route.current.hooks.already && route.current.hooks.already[0]) { 209 | // @ts-ignore 210 | route.current.hooks.already[0] = noneBlockingHook(already); 211 | } // @ts-ignore 212 | 213 | 214 | if (leave && route.current && route.current.hooks.leave.length === 2) { 215 | // @ts-ignore 216 | route.current.hooks.leave[0] = blockingHook(leave); 217 | } 218 | }, [before, after, already, leave]); 219 | 220 | if (context.__allowRender) { 221 | return renderChild(); 222 | } else if (switchContext.isInSwitch && context.match) { 223 | if (switchContext.switchMatch) { 224 | if (switchContext.switchMatch.route.path === context.match.route.path) { 225 | return renderChild(); 226 | } 227 | } else { 228 | switchContext.switchMatch = context.match; 229 | return renderChild(); 230 | } 231 | } else if (context.match) { 232 | return renderChild(); 233 | } 234 | 235 | return null; 236 | } 237 | 238 | function Base(_ref2) { 239 | var path = _ref2.path; 240 | getRouter(path); 241 | return null; 242 | } 243 | 244 | function Switch(_ref3) { 245 | var children = _ref3.children; 246 | 247 | var _useState = (0, _react.useState)(false), 248 | _useState2 = (0, _slicedToArray2["default"])(_useState, 2), 249 | match = _useState2[0], 250 | setMatch = _useState2[1]; 251 | 252 | (0, _react.useEffect)(function () { 253 | function switchHandler(match) { 254 | setMatch(match); 255 | } 256 | 257 | getRouter().on("*", switchHandler); 258 | return function () { 259 | getRouter().off(switchHandler); 260 | }; 261 | }, []); 262 | return /*#__PURE__*/_react["default"].createElement(SwitchContext.Provider, { 263 | value: { 264 | switchMatch: false, 265 | isInSwitch: true 266 | }, 267 | key: match ? match.url : "switch".concat(new Date().getTime()) 268 | }, children); 269 | } 270 | 271 | function NotFound(_ref4) { 272 | var children = _ref4.children, 273 | hooks = _ref4.hooks; 274 | var match = useNotFound(hooks); 275 | 276 | if (match) { 277 | return /*#__PURE__*/_react["default"].createElement(Context.Provider, { 278 | value: { 279 | match: match 280 | } 281 | }, children); 282 | } 283 | 284 | return null; 285 | } 286 | 287 | function Redirect(_ref5) { 288 | var path = _ref5.path; 289 | (0, _react.useEffect)(function () { 290 | getRouter().navigate(path); 291 | }, []); 292 | return null; 293 | } // hooks 294 | 295 | 296 | function useNavigo() { 297 | return (0, _react.useContext)(Context); 298 | } 299 | 300 | function useLocation() { 301 | return getRouter().getCurrentLocation(); 302 | } // internal hooks 303 | 304 | 305 | function useNotFound(hooks) { 306 | var _useState3 = (0, _react.useState)(false), 307 | _useState4 = (0, _slicedToArray2["default"])(_useState3, 2), 308 | match = _useState4[0], 309 | setMatch = _useState4[1]; 310 | 311 | var handler = (0, _react.useRef)(function (match) { 312 | setMatch(match); 313 | nextTick(function () { 314 | return getRouter().updatePageLinks(); 315 | }); 316 | }); 317 | (0, _react.useEffect)(function () { 318 | // @ts-ignore 319 | var router = getRouter(); 320 | router.notFound(handler.current, hooks); 321 | router.addLeaveHook("__NOT_FOUND__", function (done) { 322 | setMatch(false); 323 | done(); 324 | }); 325 | router.resolve(); 326 | router.updatePageLinks(); 327 | return function () { 328 | router.off(handler.current); 329 | }; 330 | }, []); 331 | return match; 332 | } 333 | 334 | var API = { 335 | getRouter: getRouter, 336 | configureRouter: configureRouter, 337 | reset: reset, 338 | Route: Route, 339 | Base: Base, 340 | Switch: Switch, 341 | NotFound: NotFound, 342 | Redirect: Redirect, 343 | useNavigo: useNavigo, 344 | useLocation: useLocation 345 | }; 346 | var _default = API; 347 | exports["default"] = _default; 348 | //# sourceMappingURL=NavigoReact.js.map -------------------------------------------------------------------------------- /lib/NavigoReact.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react")):"function"==typeof define&&define.amd?define("NavigoReact",["React"],e):"object"==typeof exports?exports.NavigoReact=e(require("react")):t.NavigoReact=e(t.React)}("undefined"!=typeof self?self:this,(function(t){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/",n(n.s=2)}([function(e,n){e.exports=t},function(t,e,n){"undefined"!=typeof self&&self,t.exports=(()=>{"use strict";var t={783:(t,e,n)=>{n.d(e,{default:()=>S});var r=/([:*])(\w+)/g,o=/\*/g,a=/\/\?/g;function i(t){return void 0===t&&(t="/"),p()?location.pathname+location.search+location.hash:t}function u(t){return t.replace(/\/+$/,"").replace(/^\/+/,"")}function c(t){return"string"==typeof t}function s(t){var e=u(t).split(/\?(.*)?$/);return[u(e[0]),e.slice(1).join("")]}function h(t){for(var e={},n=t.split("&"),r=0;r0?1===t.matches.length?t.matches[0]:t.matches:void 0)}})).concat([function(){return r()}])):r()}else r()}})),{},(function(){return e()})):e()}var P=[function(t,e){var n=t.instance.lastResolved();if(n&&n[0]&&n[0].route===t.match.route&&n[0].url===t.match.url&&n[0].queryString===t.match.queryString)return n.forEach((function(e){e.route.hooks&&e.route.hooks.already&&d(t.navigateOptions,"callHooks")&&e.route.hooks.already.forEach((function(e){return e(t.match)}))})),void e(!1);e()},function(t,e){t.match.route.hooks&&t.match.route.hooks.before&&d(t.navigateOptions,"callHooks")?g(t.match.route.hooks.before.map((function(e){return function(n,r){return e(r,t.match)}})).concat([function(){return e()}])):e()},function(t,e){d(t.navigateOptions,"callHandler")&&t.match.route.handler(t.match),t.instance.updatePageLinks(),e()},function(t,e){t.match.route.hooks&&t.match.route.hooks.after&&d(t.navigateOptions,"callHooks")&&t.match.route.hooks.after.forEach((function(e){return e(t.match)})),e()}],_=[R,function(t,e){var n=t.instance._notFoundRoute;if(n){t.notFoundHandled=!0;var r=s(t.currentLocationPath),o=r[0],a=r[1];n.path=u(o);var i={url:n.path,queryString:a,data:null,route:n,params:""!==a?h(a):null};t.matches=[i],t.match=i}e()},g.if((function(t){return t.notFoundHandled}),P,[function(t,e){t.resolveOptions&&!1!==t.resolveOptions.noMatchWarning&&void 0!==t.resolveOptions.noMatchWarning||console.warn('Navigo: "'+t.currentLocationPath+"\" didn't match any of the registered routes."),e()}]),function(t,e){t.instance._setCurrent(null),e()}];function j(){return(j=Object.assign||function(t){for(var e=1;e=0&&(t=!0===r.hash?t.split("#")[1]||"/":t.split("#")[0]),t}function S(t){return u(a+"/"+u(t))}function x(t,e,n,r){return t=c(t)?S(t):t,{name:r||u(String(t)),path:t,handler:e,hooks:v(n)}}function E(t,e){var n={instance:o,currentLocationPath:t?u(a)+"/"+u(t):void 0,navigateOptions:{},resolveOptions:e||r};return g([m,y,g.if((function(t){var e=t.matches;return e&&e.length>0}),A,_)],n),!!n.matches&&n.matches}function H(t,e){t=u(a)+"/"+u(t);var n={instance:o,to:t,navigateOptions:e||{},resolveOptions:e&&e.resolveOptions?e.resolveOptions:r,currentLocationPath:j(t)};g([k,O,y,g.if((function(t){var e=t.matches;return e&&e.length>0}),A,_),L],n)}function M(){if(P)return(P?[].slice.call(document.querySelectorAll("[data-navigo]")):[]).forEach((function(t){"false"!==t.getAttribute("data-navigo")&&"_blank"!==t.getAttribute("target")?t.hasListenerAttached||(t.hasListenerAttached=!0,t.navigoHandler=function(e){if((e.ctrlKey||e.metaKey)&&"a"===e.target.tagName.toLowerCase())return!1;var n=t.getAttribute("href");if(null==n)return!1;if(n.match(/^(http|https)/)&&"undefined"!=typeof URL)try{var r=new URL(n);n=r.pathname+r.search}catch(t){}var a=function(t){if(!t)return{};var e,n=t.split(","),r={};return n.forEach((function(t){var n=t.split(":").map((function(t){return t.replace(/(^ +| +$)/g,"")}));switch(n[0]){case"historyAPIMethod":r.historyAPIMethod=n[1];break;case"resolveOptionsStrategy":e||(e={}),e.strategy=n[1];break;case"resolveOptionsHash":e||(e={}),e.hash="true"===n[1];break;case"updateBrowserURL":case"callHandler":case"updateState":case"force":r[n[0]]="true"===n[1]}})),e&&(r.resolveOptions=e),r}(t.getAttribute("data-navigo-options"));w||(e.preventDefault(),e.stopPropagation(),o.navigate(u(n),a))},t.addEventListener("click",t.navigoHandler)):t.hasListenerAttached&&t.removeEventListener("click",t.navigoHandler)})),o}function N(t,e){var n=b.find((function(e){return e.name===t}));if(n){var r=n.path;if(e)for(var o in e)r=r.replace(":"+o,e[o]);return r.match(/^\//)?r:"/"+r}return null}function C(t){var e=s(u(t)),r=e[0],o=e[1],a=""===o?null:h(o);return{url:r,queryString:o,route:x(r,(function(){}),[n],r),data:null,params:a}}function F(t,e,n){return"string"==typeof e&&(e=I(e)),e?(e.hooks[t]||(e.hooks[t]=[]),e.hooks[t].push(n),function(){e.hooks[t]=e.hooks[t].filter((function(t){return t!==n}))}):(console.warn("Route doesn't exists: "+e),function(){})}function I(t){return"string"==typeof t?b.find((function(e){return e.name===S(t)})):b.find((function(e){return e.handler===t}))}t?a=u(t):console.warn('Navigo requires a root path in its constructor. If not provided will use "/" as default.'),this.root=a,this.routes=b,this.destroyed=w,this.current=d,this.on=function(t,e,r){var o=this;return"object"!=typeof t||t instanceof RegExp?("function"==typeof t&&(r=e,e=t,t=a),b.push(x(t,e,[n,r])),this):(Object.keys(t).forEach((function(e){if("function"==typeof t[e])o.on(e,t[e]);else{var r=t[e],a=r.uses,i=r.as,u=r.hooks;b.push(x(e,a,[n,u],i))}})),this)},this.off=function(t){return this.routes=b=b.filter((function(e){return c(t)?u(e.path)!==u(t):"function"==typeof t?t!==e.handler:String(e.path)!==String(t)})),this},this.resolve=E,this.navigate=H,this.navigateByName=function(t,e,n){var r=N(t,e);return null!==r&&(H(r,n),!0)},this.destroy=function(){this.routes=b=[],R&&window.removeEventListener("popstate",this.__popstateListener),this.destroyed=w=!0},this.notFound=function(t,e){return o._notFoundRoute=x("*",t,[n,e],"__NOT_FOUND__"),this},this.updatePageLinks=M,this.link=function(t){return"/"+a+"/"+u(t)},this.hooks=function(t){return n=t,this},this.extractGETParameters=function(t){return s(j(t))},this.lastResolved=function(){return d},this.generate=N,this.getLinkPath=function(t){return t.getAttribute("href")},this.match=function(t){var e={instance:o,currentLocationPath:t,navigateOptions:{},resolveOptions:r};return y(e,(function(){})),!!e.matches&&e.matches},this.matchLocation=function(t,e){var n={instance:o,currentLocationPath:e};return m(n,(function(){})),t=u(t),f(n.currentLocationPath,{name:t,path:t,handler:function(){},hooks:{}})||!1},this.getCurrentLocation=function(){return C(u(i(a)).replace(new RegExp("^"+a),""))},this.addBeforeHook=F.bind(this,"before"),this.addAfterHook=F.bind(this,"after"),this.addAlreadyHook=F.bind(this,"already"),this.addLeaveHook=F.bind(this,"leave"),this.getRoute=I,this._pathToMatchObject=C,this._clean=u,this._checkForAHash=j,this._setCurrent=function(t){return d=o.current=t},function(){R&&(this.__popstateListener=function(){E()},window.addEventListener("popstate",this.__popstateListener))}.call(this),M.call(this)}}},e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={exports:{}};return t[r](o,o.exports,n),o.exports}return n.d=(t,e)=>{for(var r in e)n.o(e,r)&&!n.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),n(783)})().default},function(t,e,n){t.exports=n(3)},function(t,e,n){"use strict";n.r(e),n.d(e,"getRouter",(function(){return h})),n.d(e,"configureRouter",(function(){return l})),n.d(e,"reset",(function(){return d})),n.d(e,"Route",(function(){return p})),n.d(e,"Base",(function(){return v})),n.d(e,"Switch",(function(){return g})),n.d(e,"NotFound",(function(){return m})),n.d(e,"Redirect",(function(){return y})),n.d(e,"useNavigo",(function(){return k})),n.d(e,"useLocation",(function(){return O}));var r=n(0),o=n.n(r),a=n(1),i=n.n(a);let u,c=o.a.createContext({match:!1}),s=o.a.createContext({isInSwitch:!1,switchMatch:!1});function h(t){return u||(u=window.R=new i.a(t||"/",{strategy:"ALL",noMatchWarning:!0}),window.router=u,u)}function f(t){setTimeout(()=>t(),0)}function l(t){return h(t)}function d(){u&&(u.destroy(),u=void 0)}function p({path:t,children:e,before:n,after:a,already:i,leave:u,name:l}){const d=Object(r.useRef)(void 0),[p,v]=Object(r.useReducer)((t,e)=>({...t,...e}),{match:!1}),g=Object(r.useContext)(s),m=()=>o.a.createElement(c.Provider,{value:p},e),y=t=>e=>{t({render:t=>v({...t,match:e}),match:e})},k=t=>(e,n)=>{t({render:t=>v({...t,match:n,__allowRender:!0}),done:e,match:n})};if(Object(r.useEffect)(()=>{let e=!0;const r=h(),o=t=>{e&&v({match:t}),f(()=>h().updatePageLinks())};r.on(t,o);const c=d.current=r.getRoute(o);return c&&l&&(c.name=l),n&&r.addBeforeHook(c,k(n)),a&&r.addAfterHook(c,y(a)),i&&r.addAlreadyHook(c,y(i)),u&&r.addLeaveHook(c,k(u)),r.addLeaveHook(c,t=>{e&&v({match:!1}),t()}),r.resolve(),r.updatePageLinks(),()=>{e=!1,r.off(o)}},[]),Object(r.useEffect)(()=>{n&&d.current&&d.current.hooks.before&&d.current.hooks.before[0]&&(d.current.hooks.before[0]=k(n)),a&&d.current&&d.current.hooks.after&&d.current.hooks.after[0]&&(d.current.hooks.after[0]=y(a)),i&&d.current&&d.current.hooks.already&&d.current.hooks.already[0]&&(d.current.hooks.already[0]=y(i)),u&&d.current&&2===d.current.hooks.leave.length&&(d.current.hooks.leave[0]=k(u))},[n,a,i,u]),p.__allowRender)return m();if(g.isInSwitch&&p.match){if(!g.switchMatch)return g.switchMatch=p.match,m();if(g.switchMatch.route.path===p.match.route.path)return m()}else if(p.match)return m();return null}function v({path:t}){return h(t),null}function g({children:t}){const[e,n]=Object(r.useState)(!1);return Object(r.useEffect)(()=>{function t(t){n(t)}return h().on("*",t),()=>{h().off(t)}},[]),o.a.createElement(s.Provider,{value:{switchMatch:!1,isInSwitch:!0},key:e?e.url:"switch"+(new Date).getTime()},t)}function m({children:t,hooks:e}){const n=function(t){const[e,n]=Object(r.useState)(!1),o=Object(r.useRef)(t=>{n(t),f(()=>h().updatePageLinks())});return Object(r.useEffect)(()=>{const e=h();return e.notFound(o.current,t),e.addLeaveHook("__NOT_FOUND__",t=>{n(!1),t()}),e.resolve(),e.updatePageLinks(),()=>{e.off(o.current)}},[]),e}(e);return n?o.a.createElement(c.Provider,{value:{match:n}},t):null}function y({path:t}){return Object(r.useEffect)(()=>{h().navigate(t)},[]),null}function k(){return Object(r.useContext)(c)}function O(){return h().getCurrentLocation()}const b={getRouter:h,configureRouter:l,reset:d,Route:p,Base:v,Switch:g,NotFound:m,Redirect:y,useNavigo:k,useLocation:O};e.default=b}]).default})); 2 | //# sourceMappingURL=NavigoReact.min.js.map -------------------------------------------------------------------------------- /lib/cjs/NavigoReact.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../../src/NavigoReact.tsx"],"names":["router","Context","React","createContext","match","SwitchContext","isInSwitch","switchMatch","getRouter","root","window","R","Navigo","strategy","noMatchWarning","nextTick","callback","setTimeout","configureRouter","reset","destroy","undefined","Route","path","children","before","after","already","leave","name","route","state","action","context","setContext","switchContext","renderChild","noneBlockingHook","func","render","result","blockingHook","done","__allowRender","isMounted","handler","updatePageLinks","on","navigoRoute","current","getRoute","addBeforeHook","addAfterHook","addAlreadyHook","addLeaveHook","resolve","off","hooks","length","Base","Switch","setMatch","switchHandler","url","Date","getTime","NotFound","useNotFound","Redirect","navigate","useNavigo","useLocation","getCurrentLocation","notFound","API"],"mappings":"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","sourcesContent":["import React, { useRef, useEffect, useState, useContext, useReducer } from \"react\";\nimport Navigo, { Match as NavigoMatch, RouteHooks as NavigoHooks, Route as NavigoRoute } from \"navigo\";\n// import Navigo, { Match as NavigoMatch, RouteHooks as NavigoHooks, Route as NavigoRoute } from \"../../navigo\";\n\nimport { RouteProps, Path, NotFoundRouteProps, NavigoSwitchContextType, NavigoRouting } from \"../index.d\";\n\nlet router: Navigo | undefined;\nlet Context = React.createContext({ match: false } as NavigoRouting);\nlet SwitchContext = React.createContext({ isInSwitch: false, switchMatch: false } as NavigoSwitchContextType);\n\n// types\nexport type Match = NavigoMatch;\nexport type RouteHooks = NavigoHooks;\n\nexport function getRouter(root?: string): Navigo {\n if (router) {\n return router;\n }\n // @ts-ignore\n router = window.R = new Navigo(root || \"/\", { strategy: \"ALL\", noMatchWarning: true });\n // @ts-ignore\n window.router = router;\n return router;\n}\nfunction nextTick(callback: Function) {\n setTimeout(() => callback(), 0);\n}\n\n// utils\nexport function configureRouter(root: string) {\n return getRouter(root);\n}\nexport function reset() {\n if (router) {\n router.destroy();\n router = undefined;\n }\n}\n\n// components\nexport function Route({ path, children, before, after, already, leave, name }: RouteProps) {\n const route = useRef(undefined);\n const [context, setContext] = useReducer((state: NavigoRouting, action: NavigoRouting) => ({ ...state, ...action }), {\n match: false,\n });\n const switchContext = useContext(SwitchContext);\n const renderChild = () => {children};\n const noneBlockingHook = (func: Function) => (match: Match) => {\n func({\n render: (result: any) => setContext({ ...result, match }),\n match,\n });\n };\n const blockingHook = (func: Function) => (done: Function, match: Match) => {\n func({\n render: (result: any) => setContext({ ...result, match, __allowRender: true }),\n done,\n match,\n });\n };\n\n // creating the route + attaching hooks\n useEffect(() => {\n let isMounted = true;\n const router = getRouter();\n const handler = (match: false | Match) => {\n if (isMounted) {\n setContext({ match });\n }\n nextTick(() => getRouter().updatePageLinks());\n };\n // creating the route\n router.on(path, handler);\n const navigoRoute = (route.current = router.getRoute(handler));\n if (navigoRoute && name) {\n navigoRoute.name = name;\n }\n // hooking\n if (before) {\n router.addBeforeHook(navigoRoute as NavigoRoute, blockingHook(before));\n }\n if (after) {\n router.addAfterHook(navigoRoute as NavigoRoute, noneBlockingHook(after));\n }\n if (already) {\n router.addAlreadyHook(navigoRoute as NavigoRoute, noneBlockingHook(already));\n }\n if (leave) {\n router.addLeaveHook(navigoRoute as NavigoRoute, blockingHook(leave));\n }\n // adding the service leave hook\n router.addLeaveHook(navigoRoute as NavigoRoute, (done: Function) => {\n if (isMounted) {\n setContext({ match: false });\n }\n done();\n });\n // initial resolving\n router.resolve();\n // initial data-navigo set up\n router.updatePageLinks();\n return () => {\n isMounted = false;\n router.off(handler);\n };\n }, []);\n\n // make sure that the lifecycle funcs have access to the latest local state values\n useEffect(() => {\n if (before && route.current && route.current.hooks.before && route.current.hooks.before[0]) {\n // @ts-ignore\n route.current.hooks.before[0] = blockingHook(before);\n }\n if (after && route.current && route.current.hooks.after && route.current.hooks.after[0]) {\n // @ts-ignore\n route.current.hooks.after[0] = noneBlockingHook(after);\n }\n if (already && route.current && route.current.hooks.already && route.current.hooks.already[0]) {\n // @ts-ignore\n route.current.hooks.already[0] = noneBlockingHook(already);\n }\n // @ts-ignore\n if (leave && route.current && route.current.hooks.leave.length === 2) {\n // @ts-ignore\n route.current.hooks.leave[0] = blockingHook(leave);\n }\n }, [before, after, already, leave]);\n\n if (context.__allowRender) {\n return renderChild();\n } else if (switchContext.isInSwitch && context.match) {\n if (switchContext.switchMatch) {\n if (switchContext.switchMatch.route.path === context.match.route.path) {\n return renderChild();\n }\n } else {\n switchContext.switchMatch = context.match;\n return renderChild();\n }\n } else if (context.match) {\n return renderChild();\n }\n return null;\n}\nexport function Base({ path }: Path) {\n getRouter(path);\n return null;\n}\nexport function Switch({ children }: { children?: any }) {\n const [match, setMatch] = useState(false);\n useEffect(() => {\n function switchHandler(match: Match) {\n setMatch(match);\n }\n getRouter().on(\"*\", switchHandler);\n return () => {\n getRouter().off(switchHandler);\n };\n }, []);\n return (\n \n {children}\n \n );\n}\nexport function NotFound({ children, hooks }: NotFoundRouteProps) {\n const match = useNotFound(hooks);\n\n if (match) {\n return {children};\n }\n return null;\n}\nexport function Redirect({ path }: Path) {\n useEffect(() => {\n getRouter().navigate(path);\n }, []);\n return null;\n}\n\n// hooks\nexport function useNavigo(): NavigoRouting {\n return useContext(Context);\n}\nexport function useLocation(): Match {\n return getRouter().getCurrentLocation();\n}\n\n// internal hooks\nfunction useNotFound(hooks?: RouteHooks | undefined): false | Match {\n const [match, setMatch] = useState(false);\n const handler = useRef((match: false | Match) => {\n setMatch(match);\n nextTick(() => getRouter().updatePageLinks());\n });\n\n useEffect(() => {\n // @ts-ignore\n const router = getRouter();\n router.notFound(handler.current, hooks);\n router.addLeaveHook(\"__NOT_FOUND__\", (done: Function) => {\n setMatch(false);\n done();\n });\n router.resolve();\n router.updatePageLinks();\n return () => {\n router.off(handler.current);\n };\n }, []);\n\n return match;\n}\n\nconst API = {\n getRouter,\n configureRouter,\n reset,\n Route,\n Base,\n Switch,\n NotFound,\n Redirect,\n useNavigo,\n useLocation,\n};\n\nexport default API;\n"],"file":"NavigoReact.js"} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # navigo-react 2 | 3 | [Navigo](https://github.com/krasimir/navigo) router for React. 4 | 5 | - [navigo-react](#navigo-react) 6 | - [Quick example](#quick-example) 7 | - [Navigating between routes](#navigating-between-routes) 8 | - [Components](#components) 9 | - [Route](#route) 10 | - [Route lifecycle functions](#route-lifecycle-functions) 11 | - [Navigating using named routes](#navigating-using-named-routes) 12 | - [Switch](#switch) 13 | - [Base](#base) 14 | - [NotFound](#notfound) 15 | - [Redirect](#redirect) 16 | - [Hooks](#hooks) 17 | - [useNavigo](#usenavigo) 18 | - [useLocation](#uselocation) 19 | - [Other functions](#other-functions) 20 | - [configureRouter](#configurerouter) 21 | - [reset](#reset) 22 | - [getRouter](#getrouter) 23 | - [Examples](#examples) 24 | - [Basic example](#basic-example) 25 | - [Accessing URL and GET parameters](#accessing-url-and-get-parameters) 26 | - [Redirecting](#redirecting) 27 | - [Get data required by a Route](#get-data-required-by-a-route) 28 | - [Block opening a route](#block-opening-a-route) 29 | - [Handling transitions](#handling-transitions) 30 | 31 | ## Quick example 32 | 33 | ```jsx 34 | import { Switch, Route } from "navigo-react"; 35 | 36 | export default function App() { 37 | return ( 38 | <> 39 | 43 | 44 | 45 | Package documentation here. 46 | 47 | 48 | NavigoReact is a router for React applications based on Navigo 49 | project. 50 | 51 | 52 | 53 | ); 54 | } 55 | ``` 56 | 57 | Live demo here [https://codesandbox.io/s/navigo-react-example-w9l1d](https://codesandbox.io/s/navigo-react-example-w9l1d). 58 | 59 | ## Navigating between routes 60 | 61 | The navigation in Navigo happens in two ways: 62 | 63 | * Via `` tags. The only requirement is to add `data-navigo` attribute to the link. For example `View users`. For more details on the exact API check out [this page](https://github.com/krasimir/navigo/blob/master/DOCUMENTATION.md#augment-your-a-tags). 64 | * Via the `navigate` or `navigateByName` methods. First you have to access the router with `getRouter()` and then use one of these two methods. For example: 65 | ```js 66 | import { getRouter } from 'navigo-react'; 67 | 68 | // Somewhere in your React components 69 | 72 | 73 | // or if you have a named route like 74 | 75 | ... 76 | 77 | 78 | // Somewhere in your React components 79 | 85 | ``` 86 | 87 | ## Components 88 | 89 | ### Route 90 | 91 | ```jsx 92 | {} } 96 | after={ (cb) => {} } 97 | already={ (cb) => {} } 98 | leave={ (cb) => {} }> 99 |

Hey

100 |
101 | ``` 102 | 103 | The basic building block. Shortly, it's a component that renders its children based on the `path` prop. 104 | 105 | | Prop | type | required | Description | 106 | | ---- | ---- | -------- | ----------- | 107 | | **path** | string | yes | Specifies the path for which the children will be rendered. URL parameters are supported with the well known syntax `/users/:id/:action`. You can access the values via the [useNavigo](#usenavigo) hook | 108 | | name | string | no | Sets a name of the route so we can later navigate to it easily. Check out [this section](#navigating-using-named-routes) for an example | 109 | | before | function | no | It sets a function that is executed before the route gets switched. Checkout [Hooking to the routing lifecycle](#route-lifecycle-functions) section to see how to use it. | 110 | | after | function | no | It sets a function that is executed after the route gets switched. Checkout [Hooking to the routing lifecycle](#route-lifecycle-functions) section to see how to use it. | 111 | | already | function | no | It sets a function that is executed the current route is equal to the one specified. Or in other words - in case you land on the same route again. Checkout [Hooking to the routing lifecycle](#route-lifecycle-functions) section to see how to use it. | 112 | | leave | function | no | It sets a function that is executed when the user is about to leave the route. Checkout [Hooking to the routing lifecycle](#route-lifecycle-functions) section to see how to use it. | 113 | 114 | #### Route lifecycle functions 115 | 116 | The `before`, `after`, `already` and `leave` are functions that execute during the route resolving. They give you the opportunity to hook some logic to each one of this moments and pause/reject some of them. Each of this functions receive an object: 117 | 118 | | function | example | 119 | | -------- | ------- | 120 | | before | `function handleBefore({ render, done, match }) {...}` | 121 | | after | `function handleBefore({ render, match }) {...}` | 122 | | already | `function handleBefore({ render, match }) {...}` | 123 | | leave | `function handleBefore({ render, done, match }) {...}` | 124 | 125 | Where `render` gives you an opportunity to render the children of the `` by setting data into the Navigo context. For example: 126 | 127 | ```jsx 128 | import { Route, useNavigo } from "navigo-react"; 129 | 130 | function Print() { 131 | const { pic } = useNavigo(); 132 | 133 | if (pic === null) { 134 | return

Loading ...

; 135 | } 136 | return ; 137 | } 138 | 139 | export default function App() { 140 | async function before({ render, done }) { 141 | render({ pic: null }); 142 | const res = await ( 143 | await fetch("https://api.thecatapi.com/v1/images/search") 144 | ).json(); 145 | render({ pic: res[0].url }); 146 | done(); 147 | } 148 | return ( 149 | <> 150 | 155 | 156 | 157 | 158 | 159 | ); 160 | } 161 | ``` 162 | 163 | Pay attention to the `before` function inside the `` component. `render` calls trigger rendering of the `` component with specific context which we can access via the `useNavigo` hook. Finally when we are ready we call `done()` to indicate that the routing could be fully resolved. Which means changing the browser's URL and potentially executing `after` or `already` lifecycle methods. 164 | 165 | We can completely block the routing to specific place by calling `done(false)`. For example: 166 | 167 | ```jsx 168 | export default function App() { 169 | const [authorized, loggedIn] = useState(false); 170 | const before = (cb) => { 171 | if (!authorized) { 172 | cb(false); 173 | } else { 174 | cb(true); 175 | } 176 | }; 177 | 178 | return ( 179 | <> 180 | 181 | 182 | 183 | 184 | ); 185 | } 186 | ``` 187 | (Full example [here](#block-opening-a-route)) 188 | 189 | #### Navigating using named routes 190 | 191 | Sometimes we need to construct a URL based on some data. The library offers an imperative API for that: 192 | 193 | ```jsx 194 | import { getRouter, Route } from "navigo-react"; 195 | 196 | export default function App() { 197 | return ( 198 | <> 199 | 206 | 207 | I'm a user 208 | 209 | 210 | ); 211 | } 212 | ``` 213 | 214 | https://codesandbox.io/s/navigo-react-named-routes-0h2bh 215 | 216 | ### Switch 217 | 218 | ```jsx 219 | 220 | About 221 | Products 222 | Home 223 | 224 | ``` 225 | 226 | It forces the router to pick only one of the routes. Without this component multiple matches are possible. Like in the example above, if there is no `` the `"Home"` string will be rendered no mather what because `*` matches every route. 227 | 228 | ### Base 229 | 230 | ```jsx 231 | 232 | ``` 233 | 234 | It specifies the root of your application. If you deploy you code at specific path you have to either use this component or [`configureRouter`](#configurerouter) to tell Navigo where to start from. 235 | 236 | | Prop | type | required | Description | 237 | | ---- | ---- | -------- | ----------- | 238 | | **path** | string | yes | The root of your application. | 239 | 240 | ### NotFound 241 | 242 | ```jsx 243 | I'm 404 page. 244 | ``` 245 | 246 | It renders its content in case of a no match is found. 247 | 248 | ### Redirect 249 | 250 | ```jsx 251 | 252 | ``` 253 | 254 | It indirectly calls the `navigate` method of the router. Checkout [redirecting](#redirecting) example below. 255 | 256 | | Prop | type | required | Description | 257 | | ---- | ---- | -------- | ----------- | 258 | | **path** | string | yes | The path where you want to go to. | 259 | 260 | ## Hooks 261 | 262 | ### useNavigo 263 | 264 | `useNavigo` is a hook that gives you access to the Navigo context. The main role of the context is to pass a [Match](https://github.com/krasimir/navigo/blob/master/DOCUMENTATION.md#match) object. It gives you access to the matched URL, URL and GET parameters. For example: 265 | 266 | ```js 267 | import { Route, useNavigo } from "navigo-react"; 268 | 269 | function User() { 270 | const { match } = useNavigo(); 271 | 272 | return ( 273 |

274 | {match.params.action} user with id {match.data.id} 275 |

276 | ); 277 | } 278 | 279 | export default function App() { 280 | return ( 281 | <> 282 | 283 | Click me 284 | 285 | 286 | 287 | 288 | 289 | ); 290 | } 291 | ``` 292 | 293 | The Navigo context also gives you access to key-value paris that we send via the router [lifecycle functions](#route-lifecycle-functions). Check out this example [Get data required by a Route](#get-data-required-by-a-route). 294 | 295 | ### useLocation 296 | 297 | `useLocation` gives you a [Match](https://github.com/krasimir/navigo/blob/master/DOCUMENTATION.md#match) object that represents the current URL of the browser. 298 | 299 | ```js 300 | const match = useLocation(); 301 | ``` 302 | 303 | ## Other functions 304 | 305 | ### configureRouter 306 | 307 | `configureRouter` could be used outside React and its purpose is to set the base root path of the router. Same as [``](#base) component. 308 | 309 | ```js 310 | configureRouter('/my/app'); 311 | ``` 312 | 313 | ### reset 314 | 315 | Calling this function means flushing all the registered routes. 316 | 317 | ### getRouter 318 | 319 | It gives you access to the [Navigo](https://github.com/krasimir/navigo/blob/master/DOCUMENTATION.md) router. Mostly you'll be using `navigate` and `navigateByName` functions. For example: 320 | 321 | ```js 322 | getRouter().navigate('/users/list'); 323 | ``` 324 | 325 | ## Examples 326 | 327 | ### Basic example 328 | 329 | ```jsx 330 | import { Switch, Route } from "navigo-react"; 331 | 332 | export default function App() { 333 | return ( 334 | <> 335 | 339 | 340 | 341 |
    342 |
  • Size: ~15KB
  • 343 |
  • Dependencies: no
  • 344 |
  • 345 | Documentation: here 346 |
  • 347 |
348 |
349 | 350 | NavigoReact is a router for React applications based on Navigo project. 351 | 352 |
353 | 354 | ); 355 | } 356 | ``` 357 | 358 | https://codesandbox.io/s/navigo-react-example-w9l1d 359 | 360 | ### Accessing URL and GET parameters 361 | 362 | ```jsx 363 | import { Route, useNavigo } from "navigo-react"; 364 | 365 | function User() { 366 | const { match } = useNavigo(); 367 | 368 | return ( 369 |

370 | {match.params.action} user with id {match.data.id} 371 |

372 | ); 373 | } 374 | 375 | export default function App() { 376 | return ( 377 | <> 378 | 379 | Click me 380 | 381 | 382 | 383 | 384 | 385 | ); 386 | } 387 | ``` 388 | 389 | https://codesandbox.io/s/navigo-url-and-get-parameters-5few6 390 | 391 | ### Redirecting 392 | 393 | ```jsx 394 | import { Route, Switch, Redirect } from "navigo-react"; 395 | 396 | export default function App() { 397 | return ( 398 | <> 399 | 404 | 405 | 406 | 407 | 408 | Hey user! 409 | 410 | 411 | ); 412 | } 413 | ``` 414 | 415 | https://codesandbox.io/s/navigo-redirecting-cxzbb 416 | 417 | ### Get data required by a Route 418 | 419 | ```jsx 420 | import { Route, useNavigo } from "navigo-react"; 421 | 422 | function Print() { 423 | const { pic } = useNavigo(); 424 | 425 | if (pic === null) { 426 | return

Loading ...

; 427 | } 428 | return ; 429 | } 430 | 431 | export default function App() { 432 | async function before({ render, done }) { 433 | render({ pic: null }); 434 | const res = await ( 435 | await fetch("https://api.thecatapi.com/v1/images/search") 436 | ).json(); 437 | render({ pic: res[0].url }); 438 | done(); 439 | } 440 | return ( 441 | <> 442 | 447 | 448 | 449 | 450 | 451 | ); 452 | } 453 | ``` 454 | 455 | https://codesandbox.io/s/navigo-before-lifecycle-function-hgeld 456 | 457 | ### Block opening a route 458 | 459 | The user can't go to `/user` route. 460 | 461 | ```jsx 462 | import { Route } from "navigo-react"; 463 | 464 | export default function App() { 465 | const before = ({ done }) => { 466 | done(false); 467 | }; 468 | 469 | return ( 470 | <> 471 | 476 | 477 | Hey user!!! 478 | 479 | 480 | ); 481 | } 482 | ``` 483 | 484 | https://codesandbox.io/s/navigo-block-routing-e2qvw 485 | 486 | ### Handling transitions 487 | 488 | ```jsx 489 | import { Route, Switch, useNavigo } from "navigo-react"; 490 | 491 | const delay = (time) => new Promise((done) => setTimeout(done, time)); 492 | 493 | const leaveHook = async ({ render, done }) => { 494 | render({ leaving: true }); 495 | await delay(900); 496 | done(); 497 | }; 498 | 499 | function Card({ children, bgColor }) { 500 | const { leaving } = useNavigo(); 501 | const animation = `${ 502 | leaving ? "out" : "in" 503 | } 1000ms cubic-bezier(1, -0.28, 0.28, 1.49)`; 504 | 505 | return ( 506 |
510 |

{children}

511 |
512 | ); 513 | } 514 | 515 | export default function App() { 516 | return ( 517 | <> 518 | 519 | 520 | 521 | Card #2. 522 |
523 | 524 | Click here 525 | {" "} 526 | to go back 527 |
528 |
529 | 530 | 531 | Welcome to the transition example.{" "} 532 | 533 | Click here 534 | {" "} 535 | to open the other card. 536 | 537 | 538 |
539 | 540 | ); 541 | } 542 | ``` 543 | 544 | https://codesandbox.io/s/navigo-handling-transitions-ipprc -------------------------------------------------------------------------------- /src/__tests__/Route.spec.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import "@testing-library/jest-dom/extend-expect"; 3 | import { render, waitFor, fireEvent, screen } from "@testing-library/react"; 4 | import { getRouter, reset, Route, useNavigo, Base, configureRouter, Switch } from "../NavigoReact"; 5 | 6 | import { expectContent, navigate, delay } from "../__tests_helpers__/utils"; 7 | 8 | let warn: jest.SpyInstance; 9 | 10 | describe("Given navigo-react", () => { 11 | beforeEach(() => { 12 | reset(); 13 | warn = jest.spyOn(console, "warn").mockImplementation(() => {}); 14 | history.pushState({}, "", "/"); 15 | }); 16 | afterEach(() => { 17 | if (warn) { 18 | warn.mockReset(); 19 | } 20 | }); 21 | describe("when using the Route component", () => { 22 | it("should render the children if the path matches on the first render", async () => { 23 | history.pushState({}, "", "/app/foo/bar"); 24 | function CompA() { 25 | const { match } = useNavigo(); 26 | if (match) { 27 | return

A

; 28 | } 29 | return null; 30 | } 31 | 32 | render( 33 |
34 | 35 | 36 | 37 | 38 | 39 |

B

40 |
41 |
42 | ); 43 | expectContent("AB"); 44 | }); 45 | it("should gives us access to the Match object", () => { 46 | history.pushState({}, "", "/foo/bar"); 47 | const CompB = jest.fn().mockImplementation(() => { 48 | const { match } = useNavigo(); 49 | // @ts-ignore 50 | return

B{match.data.id}

; 51 | }); 52 | render( 53 |
54 | 55 | 56 | 57 |
58 | ); 59 | 60 | expect(CompB).toBeCalledTimes(1); 61 | expect(CompB.mock.calls[0][0]).toStrictEqual({ 62 | a: "b", 63 | }); 64 | }); 65 | it("should add a route and remove it when we unmount the component", async () => { 66 | function Wrapper() { 67 | const [count, setCount] = useState(0); 68 | if (count >= 2 && count < 4) { 69 | return ( 70 | <> 71 | 72 | 73 | 74 | 75 | 76 | ); 77 | } 78 | return ; 79 | } 80 | function Comp() { 81 | const { match } = useNavigo(); 82 | return match ?

Match

:

No Match

; 83 | } 84 | 85 | const { getByText } = render( 86 |
87 | 88 |
89 | ); 90 | 91 | fireEvent.click(getByText("button")); 92 | fireEvent.click(getByText("button")); 93 | fireEvent.click(getByText("button")); 94 | expect(getRouter().routes).toHaveLength(1); 95 | await waitFor(() => { 96 | navigate("/foo"); 97 | }); 98 | expectContent("Matchbutton"); 99 | await waitFor(() => { 100 | fireEvent.click(getByText("button")); 101 | }); 102 | await waitFor(() => { 103 | fireEvent.click(getByText("button")); 104 | fireEvent.click(getByText("button")); 105 | }); 106 | expectContent("button"); 107 | expect(getRouter().routes).toHaveLength(0); 108 | }); 109 | it("should give us proper Match object if the path matches on the first render", async () => { 110 | history.pushState({}, "", "/foo/bar"); 111 | function Comp() { 112 | const { match } = useNavigo(); 113 | if (match) { 114 | // @ts-ignore 115 | return

Matching {match.data.id}

; 116 | } 117 | return

Nope

; 118 | } 119 | 120 | render( 121 |
122 | 123 | 124 | 125 |
126 | ); 127 | expectContent("Matching bar"); 128 | }); 129 | describe("and we have multiple components", () => { 130 | it("should properly resolve the paths", async () => { 131 | function CompA() { 132 | const { match } = useNavigo(); 133 | if (match) { 134 | // @ts-ignore 135 | return

About

; 136 | } 137 | return null; 138 | } 139 | function CompB() { 140 | const { match } = useNavigo(); 141 | if (match) { 142 | // @ts-ignore 143 | return

Products

; 144 | } 145 | return null; 146 | } 147 | 148 | render( 149 |
150 | 151 | 152 | 153 | 154 | 155 | 156 |
157 | ); 158 | expect(screen.getByTestId("container").textContent).toEqual(""); 159 | await navigate("/about"); 160 | expect(screen.getByTestId("container").textContent).toEqual("About"); 161 | await navigate("products"); 162 | expect(screen.getByTestId("container").textContent).toEqual("Products"); 163 | }); 164 | it("should resolve even tho there is the same path in multiple components", async () => { 165 | function CompA() { 166 | const { match } = useNavigo(); 167 | if (match) { 168 | // @ts-ignore 169 | return

About1

; 170 | } 171 | return null; 172 | } 173 | function CompB() { 174 | const { match } = useNavigo(); 175 | if (match) { 176 | // @ts-ignore 177 | return

About2

; 178 | } 179 | return null; 180 | } 181 | 182 | render( 183 |
184 | 185 | 186 | 187 | 188 | 189 | 190 |
191 | ); 192 | expectContent(""); 193 | await navigate("/about"); 194 | expectContent("About1About2"); 195 | await navigate("products"); 196 | expectContent(""); 197 | }); 198 | }); 199 | describe("and when we have links with data-navigo attribute", () => { 200 | it("should properly navigate to the new route", async () => { 201 | configureRouter("/app"); 202 | function CompA() { 203 | return ( 204 | 205 | click me 206 | 207 | ); 208 | } 209 | function CompB() { 210 | const { match } = useNavigo(); 211 | if (match) { 212 | // @ts-ignore 213 | return ( 214 | <> 215 |

About

216 | 217 | home 218 | 219 | 220 | ); 221 | } 222 | return null; 223 | } 224 | 225 | const { getByText } = render( 226 |
227 | 228 | 229 | 230 | 231 |
232 | ); 233 | expectContent("click me"); 234 | fireEvent.click(getByText("click me")); 235 | expectContent("click meAbouthome"); 236 | await delay(); 237 | fireEvent.click(getByText("home")); 238 | expectContent("click me"); 239 | }); 240 | }); 241 | }); 242 | describe("when passing a `before` function", () => { 243 | it("should create a before hook and allow us render with specific args", async () => { 244 | const handler = jest.fn().mockImplementation(async ({ render, done }) => { 245 | render({ myName: "Krasimir" }); 246 | await delay(5); 247 | waitFor(() => { 248 | render({ myName: "Tsonev" }); 249 | }); 250 | await delay(5); 251 | waitFor(() => { 252 | done(); 253 | }); 254 | }); 255 | history.pushState({}, "", "/about"); 256 | function Comp() { 257 | const { match, myName } = useNavigo(); 258 | 259 | if (match) { 260 | return

Hello, {myName}

; 261 | } 262 | return

Nope

; 263 | } 264 | 265 | render( 266 |
267 | 268 | 269 | 270 |
271 | ); 272 | 273 | expectContent("Hello, Krasimir"); 274 | await delay(7); 275 | expectContent("Hello, Tsonev"); 276 | await delay(20); 277 | expectContent("Hello, Tsonev"); 278 | expect(handler).toBeCalledTimes(1); 279 | expect(handler).toBeCalledWith({ 280 | render: expect.any(Function), 281 | done: expect.any(Function), 282 | match: expect.objectContaining({ url: "about" }), 283 | }); 284 | }); 285 | it("should allow us to block the routing", async () => { 286 | history.pushState({}, "", "/"); 287 | function Comp() { 288 | return

About

; 289 | } 290 | 291 | render( 292 |
293 | { 296 | done(false); 297 | }} 298 | > 299 | 300 | 301 |
302 | ); 303 | 304 | expectContent(""); 305 | getRouter().navigate("/about"); 306 | expectContent(""); 307 | expect(location.pathname).toEqual("/"); 308 | }); 309 | it("should accumulate state", async () => { 310 | history.pushState({}, "", "/about"); 311 | const spy = jest.fn(); 312 | function Comp() { 313 | spy(useNavigo()); 314 | 315 | return

Hey

; 316 | } 317 | 318 | render( 319 |
320 | { 323 | render({ a: "b" }); 324 | await delay(2); 325 | waitFor(() => { 326 | render({ c: "d" }); 327 | }); 328 | await delay(2); 329 | waitFor(() => { 330 | done(); 331 | }); 332 | }} 333 | > 334 | 335 | 336 |
337 | ); 338 | 339 | await delay(20); 340 | expect(spy).toBeCalledTimes(3); 341 | expect(spy.mock.calls[0][0]).toStrictEqual({ 342 | match: expect.objectContaining({ url: "about" }), 343 | a: "b", 344 | __allowRender: true, 345 | }); 346 | expect(spy.mock.calls[1][0]).toStrictEqual({ 347 | match: expect.objectContaining({ url: "about" }), 348 | a: "b", 349 | c: "d", 350 | __allowRender: true, 351 | }); 352 | expect(spy.mock.calls[2][0]).toStrictEqual({ 353 | match: expect.objectContaining({ url: "about" }), 354 | a: "b", 355 | c: "d", 356 | __allowRender: true, 357 | }); 358 | }); 359 | it("should keep the scope of the before hook and give access to the latest state values", () => { 360 | history.pushState({}, "", "/"); 361 | const spy = jest.fn(); 362 | function Comp() { 363 | const [count, setCount] = useState(0); 364 | const before = ({ done }: { done: Function }) => { 365 | spy(count); 366 | done(); 367 | }; 368 | 369 | return ( 370 | <> 371 | 372 | about 373 | 374 | 375 | About page 376 | 377 | 380 | 381 | ); 382 | } 383 | const { getByTestId, getByText } = render( 384 |
385 | 386 |
387 | ); 388 | 389 | fireEvent.click(getByTestId("c")); 390 | fireEvent.click(getByTestId("c")); 391 | fireEvent.click(getByTestId("c")); 392 | expectContent("aboutclick me 3"); 393 | fireEvent.click(getByText("about")); 394 | expect(spy).toBeCalledTimes(1); 395 | expect(spy).toBeCalledWith(3); 396 | }); 397 | it("should keep the scope of the after hook and give access to the latest state values", () => { 398 | history.pushState({}, "", "/"); 399 | const spy = jest.fn(); 400 | function Comp() { 401 | const [count, setCount] = useState(0); 402 | const after = ({ render }: { render: Function }) => { 403 | spy(count); 404 | }; 405 | 406 | return ( 407 | <> 408 | 409 | about 410 | 411 | 412 | About 413 | 414 | 417 | 418 | ); 419 | } 420 | const { getByTestId, getByText } = render( 421 |
422 | 423 |
424 | ); 425 | 426 | fireEvent.click(getByTestId("c")); 427 | fireEvent.click(getByTestId("c")); 428 | fireEvent.click(getByTestId("c")); 429 | expectContent("aboutclick me 3"); 430 | fireEvent.click(getByText("about")); 431 | expect(spy).toBeCalledTimes(1); 432 | expect(spy).toBeCalledWith(3); 433 | expectContent("aboutAboutclick me 3"); 434 | }); 435 | it("should keep the scope of the already hook and give access to the latest state values", () => { 436 | history.pushState({}, "", "/"); 437 | const spy = jest.fn(); 438 | function Comp() { 439 | const [count, setCount] = useState(0); 440 | const already = ({ render }: { render: Function }) => { 441 | spy(count); 442 | }; 443 | 444 | return ( 445 | <> 446 | 447 | about 448 | 449 | 450 | About 451 | 452 | 455 | 456 | ); 457 | } 458 | const { getByTestId, getByText } = render( 459 |
460 | 461 |
462 | ); 463 | 464 | fireEvent.click(getByTestId("c")); 465 | fireEvent.click(getByTestId("c")); 466 | fireEvent.click(getByTestId("c")); 467 | expectContent("aboutclick me 3"); 468 | fireEvent.click(getByText("about")); 469 | fireEvent.click(getByText("about")); 470 | expect(spy).toBeCalledTimes(1); 471 | expect(spy).toBeCalledWith(3); 472 | expectContent("aboutAboutclick me 3"); 473 | }); 474 | it("should keep the scope of the leave hook and give access to the latest state values", () => { 475 | history.pushState({}, "", "/about"); 476 | const spy = jest.fn(); 477 | function Comp() { 478 | const [count, setCount] = useState(0); 479 | const leave = ({ render, done }: { done: Function; render: Function }) => { 480 | spy(count); 481 | }; 482 | 483 | return ( 484 | <> 485 | 486 | About 487 | 488 | 491 | 492 | ); 493 | } 494 | const { getByTestId } = render( 495 |
496 | 497 |
498 | ); 499 | 500 | fireEvent.click(getByTestId("c")); 501 | fireEvent.click(getByTestId("c")); 502 | fireEvent.click(getByTestId("c")); 503 | expectContent("Aboutclick me 3"); 504 | getRouter().navigate("/nope"); 505 | expect(spy).toBeCalledTimes(1); 506 | expect(spy).toBeCalledWith(3); 507 | }); 508 | }); 509 | describe("when passing `after`", () => { 510 | it("should create an after hook and allow us to send props to useNavigo hook", async () => { 511 | history.pushState({}, "", "/about"); 512 | function Comp() { 513 | const { match, userName } = useNavigo(); 514 | 515 | if (userName) { 516 | return

Hey, {userName}

; 517 | } 518 | return

Nope

; 519 | } 520 | 521 | render( 522 |
523 | { 526 | await delay(10); 527 | await waitFor(() => { 528 | render({ userName: "Foo Bar" }); 529 | }); 530 | }} 531 | > 532 | 533 | 534 |
535 | ); 536 | 537 | expectContent("Nope"); 538 | await delay(20); 539 | expectContent("Hey, Foo Bar"); 540 | }); 541 | }); 542 | describe("when passing `already`", () => { 543 | it("should create an already hook and allow us to send props to useNavigo hook", async () => { 544 | history.pushState({}, "", "/about"); 545 | function Comp() { 546 | const { again } = useNavigo(); 547 | 548 | if (again) { 549 | return

Rendering again

; 550 | } 551 | return

Nope

; 552 | } 553 | 554 | render( 555 |
556 | { 559 | render({ again: true }); 560 | }} 561 | > 562 | 563 | 564 |
565 | ); 566 | 567 | expectContent("Nope"); 568 | await waitFor(() => { 569 | getRouter().navigate("/about"); 570 | }); 571 | expectContent("Rendering again"); 572 | }); 573 | }); 574 | describe("when passing a `leave` function", () => { 575 | it("should create a leave hook and allow us to send props to useNavigo hook", async () => { 576 | history.pushState({}, "", "/about"); 577 | function Comp() { 578 | const { leaving } = useNavigo(); 579 | 580 | if (leaving) { 581 | return

Leaving...

; 582 | } 583 | return

Nope

; 584 | } 585 | 586 | render( 587 |
588 | { 591 | render({ leaving: true }); 592 | await delay(10); 593 | waitFor(() => { 594 | render({ leaving: false }); 595 | done(); 596 | }); 597 | }} 598 | > 599 | 600 | 601 |
602 | ); 603 | 604 | expectContent("Nope"); 605 | await waitFor(() => { 606 | getRouter().navigate("/nah"); 607 | }); 608 | expectContent("Leaving..."); 609 | await delay(20); 610 | expectContent("Nope"); 611 | }); 612 | it("should allow us to block the routing", async () => { 613 | history.pushState({}, "", "/about"); 614 | function Comp() { 615 | return

Not leaving!

; 616 | } 617 | 618 | render( 619 |
620 | { 623 | done(false); 624 | }} 625 | > 626 | 627 | 628 |
629 | ); 630 | 631 | expectContent("Not leaving!"); 632 | await waitFor(() => { 633 | getRouter().navigate("/nah"); 634 | }); 635 | expectContent("Not leaving!"); 636 | expect(location.pathname).toEqual("/about"); 637 | }); 638 | }); 639 | describe("when passing a name", () => { 640 | it("should be possible to navigate to that same route later", async () => { 641 | history.pushState({}, "", "/"); 642 | function Users() { 643 | const { match } = useNavigo(); 644 | // @ts-ignore 645 | return

Hello, {match.data.name}

; 646 | } 647 | 648 | render( 649 |
650 | 651 | 652 | 653 | 654 | 655 |
656 | ); 657 | 658 | expectContent(""); 659 | await waitFor(() => { 660 | getRouter().navigateByName("user", { name: "krasimir" }); 661 | }); 662 | expectContent("Hello, krasimir"); 663 | }); 664 | }); 665 | }); 666 | -------------------------------------------------------------------------------- /lib/NavigoReact.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://NavigoReact/webpack/universalModuleDefinition","webpack://NavigoReact/webpack/bootstrap","webpack://NavigoReact/external {\"commonjs\":\"react\",\"commonjs2\":\"react\",\"amd\":\"React\",\"root\":\"React\"}","webpack://NavigoReact/./node_modules/navigo/lib/navigo.min.js","webpack://NavigoReact/./src/NavigoReact.tsx"],"names":["root","factory","exports","module","require","define","amd","self","this","__WEBPACK_EXTERNAL_MODULE__0__","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","783","e","default","H","a","location","pathname","search","hash","replace","u","split","slice","join","h","length","decodeURIComponent","Array","isArray","push","f","path","url","queryString","route","data","params","v","RegExp","g","match","reduce","window","history","pushState","filter","forEach","splice","apply","concat","currentLocationPath","instance","_checkForAHash","y","routes","matches","resolveOptions","strategy","O","navigateOptions","shouldResolve","console","warn","silent","k","force","_setCurrent","_pathToMatchObject","to","if","L","b","w","historyAPIMethod","stateObj","title","setTimeout","href","P","lastResolved","map","hooks","leave","matchLocation","find","A","already","before","handler","updatePageLinks","after","_","_notFoundRoute","notFoundHandled","noMatchWarning","R","assign","arguments","E","indexOf","S","String","x","j","N","document","querySelectorAll","getAttribute","hasListenerAttached","navigoHandler","ctrlKey","metaKey","target","tagName","toLowerCase","URL","preventDefault","stopPropagation","navigate","addEventListener","removeEventListener","C","U","q","F","destroyed","current","on","keys","uses","as","off","resolve","navigateByName","destroy","__popstateListener","notFound","link","extractGETParameters","generate","getLinkPath","getCurrentLocation","addBeforeHook","addAfterHook","addAlreadyHook","addLeaveHook","getRoute","_clean","router","Context","createContext","SwitchContext","isInSwitch","switchMatch","getRouter","nextTick","callback","configureRouter","reset","undefined","Route","children","context","setContext","state","action","switchContext","renderChild","Provider","noneBlockingHook","func","render","result","blockingHook","done","__allowRender","isMounted","navigoRoute","Base","Switch","setMatch","switchHandler","Date","getTime","NotFound","useNotFound","Redirect","useNavigo","useLocation","API"],"mappings":"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","file":"NavigoReact.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"react\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"NavigoReact\", [\"React\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"NavigoReact\"] = factory(require(\"react\"));\n\telse\n\t\troot[\"NavigoReact\"] = factory(root[\"React\"]);\n})(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE__0__) {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 2);\n","module.exports = __WEBPACK_EXTERNAL_MODULE__0__;","!function(t,n){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=n():\"function\"==typeof define&&define.amd?define(\"Navigo\",[],n):\"object\"==typeof exports?exports.Navigo=n():t.Navigo=n()}(\"undefined\"!=typeof self?self:this,(function(){return(()=>{\"use strict\";var t={783:(t,n,e)=>{e.d(n,{default:()=>H});var o=/([:*])(\\w+)/g,r=/\\*/g,a=/\\/\\?/g;function i(t){return void 0===t&&(t=\"/\"),d()?location.pathname+location.search+location.hash:t}function s(t){return t.replace(/\\/+$/,\"\").replace(/^\\/+/,\"\")}function c(t){return\"string\"==typeof t}function u(t){var n=s(t).split(/\\?(.*)?$/);return[s(n[0]),n.slice(1).join(\"\")]}function h(t){for(var n={},e=t.split(\"&\"),o=0;o0?1===t.matches.length?t.matches[0]:t.matches:void 0)}})).concat([function(){return o()}])):o()}else o()}})),{},(function(){return n()})):n()}var A=[function(t,n){var e=t.instance.lastResolved();if(e&&e[0]&&e[0].route===t.match.route&&e[0].url===t.match.url&&e[0].queryString===t.match.queryString)return e.forEach((function(n){n.route.hooks&&n.route.hooks.already&&p(t.navigateOptions,\"callHooks\")&&n.route.hooks.already.forEach((function(n){return n(t.match)}))})),void n(!1);n()},function(t,n){t.match.route.hooks&&t.match.route.hooks.before&&p(t.navigateOptions,\"callHooks\")?g(t.match.route.hooks.before.map((function(n){return function(e,o){return n(o,t.match)}})).concat([function(){return n()}])):n()},function(t,n){p(t.navigateOptions,\"callHandler\")&&t.match.route.handler(t.match),t.instance.updatePageLinks(),n()},function(t,n){t.match.route.hooks&&t.match.route.hooks.after&&p(t.navigateOptions,\"callHooks\")&&t.match.route.hooks.after.forEach((function(n){return n(t.match)})),n()}],_=[P,function(t,n){var e=t.instance._notFoundRoute;if(e){t.notFoundHandled=!0;var o=u(t.currentLocationPath),r=o[0],a=o[1];e.path=s(r);var i={url:e.path,queryString:a,data:null,route:e,params:\"\"!==a?h(a):null};t.matches=[i],t.match=i}n()},g.if((function(t){return t.notFoundHandled}),A,[function(t,n){t.resolveOptions&&!1!==t.resolveOptions.noMatchWarning&&void 0!==t.resolveOptions.noMatchWarning||console.warn('Navigo: \"'+t.currentLocationPath+\"\\\" didn't match any of the registered routes.\"),n()}]),function(t,n){t.instance._setCurrent(null),n()}];function R(){return(R=Object.assign||function(t){for(var n=1;n=0&&(t=!0===o.hash?t.split(\"#\")[1]||\"/\":t.split(\"#\")[0]),t}function H(t){return s(a+\"/\"+s(t))}function S(t,n,e,o){return t=c(t)?H(t):t,{name:o||s(String(t)),path:t,handler:n,hooks:v(e)}}function x(t,n){var e={instance:r,currentLocationPath:t?s(a)+\"/\"+s(t):void 0,navigateOptions:{},resolveOptions:n||o};return g([m,y,g.if((function(t){var n=t.matches;return n&&n.length>0}),E,_)],e),!!e.matches&&e.matches}function j(t,n){t=s(a)+\"/\"+s(t);var e={instance:r,to:t,navigateOptions:n||{},resolveOptions:n&&n.resolveOptions?n.resolveOptions:o,currentLocationPath:R(t)};g([O,k,y,g.if((function(t){var n=t.matches;return n&&n.length>0}),E,_),w],e)}function N(){if(A)return(A?[].slice.call(document.querySelectorAll(\"[data-navigo]\")):[]).forEach((function(t){\"false\"!==t.getAttribute(\"data-navigo\")&&\"_blank\"!==t.getAttribute(\"target\")?t.hasListenerAttached||(t.hasListenerAttached=!0,t.navigoHandler=function(n){if((n.ctrlKey||n.metaKey)&&\"a\"===n.target.tagName.toLowerCase())return!1;var e=t.getAttribute(\"href\");if(null==e)return!1;if(e.match(/^(http|https)/)&&\"undefined\"!=typeof URL)try{var o=new URL(e);e=o.pathname+o.search}catch(t){}var a=function(t){if(!t)return{};var n,e=t.split(\",\"),o={};return e.forEach((function(t){var e=t.split(\":\").map((function(t){return t.replace(/(^ +| +$)/g,\"\")}));switch(e[0]){case\"historyAPIMethod\":o.historyAPIMethod=e[1];break;case\"resolveOptionsStrategy\":n||(n={}),n.strategy=e[1];break;case\"resolveOptionsHash\":n||(n={}),n.hash=\"true\"===e[1];break;case\"updateBrowserURL\":case\"callHandler\":case\"updateState\":case\"force\":o[e[0]]=\"true\"===e[1]}})),n&&(o.resolveOptions=n),o}(t.getAttribute(\"data-navigo-options\"));b||(n.preventDefault(),n.stopPropagation(),r.navigate(s(e),a))},t.addEventListener(\"click\",t.navigoHandler)):t.hasListenerAttached&&t.removeEventListener(\"click\",t.navigoHandler)})),r}function C(t,n){var e=L.find((function(n){return n.name===t}));if(e){var o=e.path;if(n)for(var r in n)o=o.replace(\":\"+r,n[r]);return o.match(/^\\//)?o:\"/\"+o}return null}function U(t){var n=u(s(t)),o=n[0],r=n[1],a=\"\"===r?null:h(r);return{url:o,queryString:r,route:S(o,(function(){}),[e],o),data:null,params:a}}function q(t,n,e){return\"string\"==typeof n&&(n=F(n)),n?(n.hooks[t]||(n.hooks[t]=[]),n.hooks[t].push(e),function(){n.hooks[t]=n.hooks[t].filter((function(t){return t!==e}))}):(console.warn(\"Route doesn't exists: \"+n),function(){})}function F(t){return\"string\"==typeof t?L.find((function(n){return n.name===H(t)})):L.find((function(n){return n.handler===t}))}t?a=s(t):console.warn('Navigo requires a root path in its constructor. If not provided will use \"/\" as default.'),this.root=a,this.routes=L,this.destroyed=b,this.current=p,this.on=function(t,n,o){var r=this;return\"object\"!=typeof t||t instanceof RegExp?(\"function\"==typeof t&&(o=n,n=t,t=a),L.push(S(t,n,[e,o])),this):(Object.keys(t).forEach((function(n){if(\"function\"==typeof t[n])r.on(n,t[n]);else{var o=t[n],a=o.uses,i=o.as,s=o.hooks;L.push(S(n,a,[e,s],i))}})),this)},this.off=function(t){return this.routes=L=L.filter((function(n){return c(t)?s(n.path)!==s(t):\"function\"==typeof t?t!==n.handler:String(n.path)!==String(t)})),this},this.resolve=x,this.navigate=j,this.navigateByName=function(t,n,e){var o=C(t,n);return null!==o&&(j(o,e),!0)},this.destroy=function(){this.routes=L=[],P&&window.removeEventListener(\"popstate\",this.__popstateListener),this.destroyed=b=!0},this.notFound=function(t,n){return r._notFoundRoute=S(\"*\",t,[e,n],\"__NOT_FOUND__\"),this},this.updatePageLinks=N,this.link=function(t){return\"/\"+a+\"/\"+s(t)},this.hooks=function(t){return e=t,this},this.extractGETParameters=function(t){return u(R(t))},this.lastResolved=function(){return p},this.generate=C,this.getLinkPath=function(t){return t.getAttribute(\"href\")},this.match=function(t){var n={instance:r,currentLocationPath:t,navigateOptions:{},resolveOptions:o};return y(n,(function(){})),!!n.matches&&n.matches},this.matchLocation=function(t,n){var e={instance:r,currentLocationPath:n};return m(e,(function(){})),t=s(t),f(e.currentLocationPath,{name:t,path:t,handler:function(){},hooks:{}})||!1},this.getCurrentLocation=function(){return U(s(i(a)).replace(new RegExp(\"^\"+a),\"\"))},this.addBeforeHook=q.bind(this,\"before\"),this.addAfterHook=q.bind(this,\"after\"),this.addAlreadyHook=q.bind(this,\"already\"),this.addLeaveHook=q.bind(this,\"leave\"),this.getRoute=F,this._pathToMatchObject=U,this._clean=s,this._checkForAHash=R,this._setCurrent=function(t){return p=r.current=t},function(){P&&(this.__popstateListener=function(){x()},window.addEventListener(\"popstate\",this.__popstateListener))}.call(this),N.call(this)}}},n={};function e(o){if(n[o])return n[o].exports;var r=n[o]={exports:{}};return t[o](r,r.exports,e),r.exports}return e.d=(t,n)=>{for(var o in n)e.o(n,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:n[o]})},e.o=(t,n)=>Object.prototype.hasOwnProperty.call(t,n),e(783)})().default}));\n//# sourceMappingURL=navigo.min.js.map","import React, { useRef, useEffect, useState, useContext, useReducer } from \"react\";\nimport Navigo, { Match as NavigoMatch, RouteHooks as NavigoHooks, Route as NavigoRoute } from \"navigo\";\n// import Navigo, { Match as NavigoMatch, RouteHooks as NavigoHooks, Route as NavigoRoute } from \"../../navigo\";\n\nimport { RouteProps, Path, NotFoundRouteProps, NavigoSwitchContextType, NavigoRouting } from \"../index.d\";\n\nlet router: Navigo | undefined;\nlet Context = React.createContext({ match: false } as NavigoRouting);\nlet SwitchContext = React.createContext({ isInSwitch: false, switchMatch: false } as NavigoSwitchContextType);\n\n// types\nexport type Match = NavigoMatch;\nexport type RouteHooks = NavigoHooks;\n\nexport function getRouter(root?: string): Navigo {\n if (router) {\n return router;\n }\n // @ts-ignore\n router = window.R = new Navigo(root || \"/\", { strategy: \"ALL\", noMatchWarning: true });\n // @ts-ignore\n window.router = router;\n return router;\n}\nfunction nextTick(callback: Function) {\n setTimeout(() => callback(), 0);\n}\n\n// utils\nexport function configureRouter(root: string) {\n return getRouter(root);\n}\nexport function reset() {\n if (router) {\n router.destroy();\n router = undefined;\n }\n}\n\n// components\nexport function Route({ path, children, before, after, already, leave, name }: RouteProps) {\n const route = useRef(undefined);\n const [context, setContext] = useReducer((state: NavigoRouting, action: NavigoRouting) => ({ ...state, ...action }), {\n match: false,\n });\n const switchContext = useContext(SwitchContext);\n const renderChild = () => {children};\n const noneBlockingHook = (func: Function) => (match: Match) => {\n func({\n render: (result: any) => setContext({ ...result, match }),\n match,\n });\n };\n const blockingHook = (func: Function) => (done: Function, match: Match) => {\n func({\n render: (result: any) => setContext({ ...result, match, __allowRender: true }),\n done,\n match,\n });\n };\n\n // creating the route + attaching hooks\n useEffect(() => {\n let isMounted = true;\n const router = getRouter();\n const handler = (match: false | Match) => {\n if (isMounted) {\n setContext({ match });\n }\n nextTick(() => getRouter().updatePageLinks());\n };\n // creating the route\n router.on(path, handler);\n const navigoRoute = (route.current = router.getRoute(handler));\n if (navigoRoute && name) {\n navigoRoute.name = name;\n }\n // hooking\n if (before) {\n router.addBeforeHook(navigoRoute as NavigoRoute, blockingHook(before));\n }\n if (after) {\n router.addAfterHook(navigoRoute as NavigoRoute, noneBlockingHook(after));\n }\n if (already) {\n router.addAlreadyHook(navigoRoute as NavigoRoute, noneBlockingHook(already));\n }\n if (leave) {\n router.addLeaveHook(navigoRoute as NavigoRoute, blockingHook(leave));\n }\n // adding the service leave hook\n router.addLeaveHook(navigoRoute as NavigoRoute, (done: Function) => {\n if (isMounted) {\n setContext({ match: false });\n }\n done();\n });\n // initial resolving\n router.resolve();\n // initial data-navigo set up\n router.updatePageLinks();\n return () => {\n isMounted = false;\n router.off(handler);\n };\n }, []);\n\n // make sure that the lifecycle funcs have access to the latest local state values\n useEffect(() => {\n if (before && route.current && route.current.hooks.before && route.current.hooks.before[0]) {\n // @ts-ignore\n route.current.hooks.before[0] = blockingHook(before);\n }\n if (after && route.current && route.current.hooks.after && route.current.hooks.after[0]) {\n // @ts-ignore\n route.current.hooks.after[0] = noneBlockingHook(after);\n }\n if (already && route.current && route.current.hooks.already && route.current.hooks.already[0]) {\n // @ts-ignore\n route.current.hooks.already[0] = noneBlockingHook(already);\n }\n // @ts-ignore\n if (leave && route.current && route.current.hooks.leave.length === 2) {\n // @ts-ignore\n route.current.hooks.leave[0] = blockingHook(leave);\n }\n }, [before, after, already, leave]);\n\n if (context.__allowRender) {\n return renderChild();\n } else if (switchContext.isInSwitch && context.match) {\n if (switchContext.switchMatch) {\n if (switchContext.switchMatch.route.path === context.match.route.path) {\n return renderChild();\n }\n } else {\n switchContext.switchMatch = context.match;\n return renderChild();\n }\n } else if (context.match) {\n return renderChild();\n }\n return null;\n}\nexport function Base({ path }: Path) {\n getRouter(path);\n return null;\n}\nexport function Switch({ children }: { children?: any }) {\n const [match, setMatch] = useState(false);\n useEffect(() => {\n function switchHandler(match: Match) {\n setMatch(match);\n }\n getRouter().on(\"*\", switchHandler);\n return () => {\n getRouter().off(switchHandler);\n };\n }, []);\n return (\n \n {children}\n \n );\n}\nexport function NotFound({ children, hooks }: NotFoundRouteProps) {\n const match = useNotFound(hooks);\n\n if (match) {\n return {children};\n }\n return null;\n}\nexport function Redirect({ path }: Path) {\n useEffect(() => {\n getRouter().navigate(path);\n }, []);\n return null;\n}\n\n// hooks\nexport function useNavigo(): NavigoRouting {\n return useContext(Context);\n}\nexport function useLocation(): Match {\n return getRouter().getCurrentLocation();\n}\n\n// internal hooks\nfunction useNotFound(hooks?: RouteHooks | undefined): false | Match {\n const [match, setMatch] = useState(false);\n const handler = useRef((match: false | Match) => {\n setMatch(match);\n nextTick(() => getRouter().updatePageLinks());\n });\n\n useEffect(() => {\n // @ts-ignore\n const router = getRouter();\n router.notFound(handler.current, hooks);\n router.addLeaveHook(\"__NOT_FOUND__\", (done: Function) => {\n setMatch(false);\n done();\n });\n router.resolve();\n router.updatePageLinks();\n return () => {\n router.off(handler.current);\n };\n }, []);\n\n return match;\n}\n\nconst API = {\n getRouter,\n configureRouter,\n reset,\n Route,\n Base,\n Switch,\n NotFound,\n Redirect,\n useNavigo,\n useLocation,\n};\n\nexport default API;\n"],"sourceRoot":""} --------------------------------------------------------------------------------