npm package: @reliance/simple-router
Description: A lightweight, plug-and-play React routing system with TypeScript support
Author: Reliance Health
Latest version: 1.0.1

# @reliance/simple-router

A lightweight, plug-and-play React routing system with TypeScript support. Designed for microfrontends and applications that need flexible routing without the complexity of larger routing libraries.

## Features

- 🚀 **Lightweight**: Minimal bundle size with zero dependencies
- 🔧 **Framework Agnostic Core**: Core utilities work without React
- 📦 **Plug and Play**: Easy integration with existing applications
- 🎯 **TypeScript First**: Full TypeScript support with comprehensive types
- 🔄 **Route Parameters**: Dynamic route parameters with type safety
- 🔍 **Query Parameters**: Built-in query parameter handling
- 🏗️ **Nested Routes**: Support for complex nested routing structures
- 🛡️ **Route Guards**: Authentication and authorization guards
- 📱 **SSR Compatible**: Works with server-side rendering
- 🎨 **Flexible**: Use with any UI framework or component library

## Installation

```bash
npm install @reliance/simple-router
# or
yarn add @reliance/simple-router
```

## Quick Start

```tsx
import React from "react";
import { Router, Link, useRouteParams } from "@reliance/simple-router";

// Define your route components
const Home = () => <div>Home Page</div>;
const About = () => <div>About Page</div>;
const User = () => {
  const params = useRouteParams<{ id: string }>();
  return <div>User: {params.id}</div>;
};

// Define your routes
const routes = [
  { path: "/", component: Home, exact: true },
  { path: "/about", component: About },
  { path: "/user/:id", component: User },
];

// Use the router
function App() {
  return <Router routes={routes} />;
}

// Navigation example in a component
function Navigation() {
  return (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/about">About</Link>
      <Link to="/user/123">User 123</Link>
    </nav>
  );
}
```

## Core Concepts

### Route Configuration

```tsx
import { RouteConfig } from "@reliance/simple-router";

const routes: RouteConfig[] = [
  {
    path: "/",
    component: HomePage,
    exact: true,
    title: "Home",
  },
  {
    path: "/products",
    component: ProductsLayout,
    children: [
      { path: "", component: ProductsList, exact: true },
      { path: "/:id", component: ProductDetail },
      { path: "/new", component: CreateProduct },
    ],
  },
];
```

### Route Parameters

Access route parameters using the `useRouteParams` hook:

```tsx
import { useRouteParams } from "@reliance/simple-router";

function ProductDetail() {
  const params = useRouteParams<{ id: string }>();
  return <div>Product ID: {params.id}</div>;
}
```

Or use the combined `useParams` hook to get both route and query parameters:

```tsx
import { useParams } from "@reliance/simple-router";

function ProductDetail() {
  const params = useParams<{ id: string; sort?: string }>();
  return (
    <div>
      <div>Product ID: {params.id}</div>
      <div>Sort: {params.sort}</div>
    </div>
  );
}
```

### Query Parameters

```tsx
import { useQueryParams } from "@reliance/simple-router";

function ProductsList() {
  const { queryParams, setQueryParams } = useQueryParams();

  const search = queryParams.search || "";
  const page = Number(queryParams.page) || 1;

  return (
    <div>
      <input
        value={search}
        onChange={(e) => setQueryParams({ search: e.target.value, page: "1" })}
      />
      <div>Page: {page}</div>
    </div>
  );
}
```

### Route Guards

Protect routes with authentication and authorization guards:

```tsx
import {
  createAuthGuard,
  createRoleGuard,
  combineGuards,
} from "@reliance/simple-router";

const authGuard = createAuthGuard(
  () => !!localStorage.getItem("token"),
  "/login"
);

const adminGuard = createRoleGuard(
  (roles) => roles.includes("admin"),
  ["admin"],
  "/unauthorized"
);

const routes = [
  {
    path: "/dashboard",
    component: Dashboard,
    guards: [authGuard],
  },
  {
    path: "/admin",
    component: AdminPanel,
    guards: [combineGuards(authGuard, adminGuard)],
  },
];
```

## Advanced Usage

### Programmatic Navigation

```tsx
import { useNavigate } from "@reliance/simple-router";

function MyComponent() {
  const { navigate, back, forward, replace } = useNavigate();

  const handleNavigation = () => {
    // Navigate to a new route
    navigate("/dashboard");

    // Navigate with query parameters
    navigate("/products", { queryParams: { category: "electronics" } });

    // Replace current route (no history entry)
    replace("/login");

    // Go back/forward in history
    back();
    forward();
  };
}
```

### Pagination Hook

```tsx
import { usePagination } from "@reliance/simple-router";

function DataTable() {
  const { page, limit, setPage, nextPage, previousPage } = usePagination(1, 20);

  return (
    <div>
      <div>Page {page}</div>
      <button onClick={previousPage} disabled={page === 1}>
        Previous
      </button>
      <button onClick={nextPage}>Next</button>
    </div>
  );
}
```

### Filters Hook

Manage filter state synchronized with URL query parameters:

```tsx
import { useFilters } from "@reliance/simple-router";

function ProductFilters() {
  const { filters, setFilter, resetFilters } = useFilters({
    category: "",
    minPrice: 0,
    maxPrice: 1000,
  });

  return (
    <div>
      <select
        value={filters.category}
        onChange={(e) => setFilter("category", e.target.value)}
      >
        <option value="">All Categories</option>
        <option value="electronics">Electronics</option>
      </select>
      <button onClick={resetFilters}>Reset</button>
    </div>
  );
}
```

### URL State Management

```tsx
import { useUrlState } from "@reliance/simple-router";

function SearchForm() {
  const [searchTerm, setSearchTerm] = useUrlState("search", "");

  return (
    <input value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} />
  );
}
```

### Building URLs with Route Parameters

```tsx
import { buildRoutePath } from "@reliance/simple-router";

// Build URLs with route parameters
const userUrl = buildRoutePath("/users/:id", { id: "123" });
// Result: "/users/123"

const postUrl = buildRoutePath("/users/:userId/posts/:postId", {
  userId: "123",
  postId: "456",
});
// Result: "/users/123/posts/456"
```

## Framework Agnostic Core

The core utilities can be used without React:

```typescript
import {
  parseQueryParams,
  buildRoutePath,
  RouteMatcher,
  Navigator,
} from "@reliance/simple-router";

// Parse query parameters
const params = parseQueryParams("?search=react&page=2");
// { search: 'react', page: '2' }

// Build route with parameters
const path = buildRoutePath("/users/:id/posts/:postId", {
  id: "123",
  postId: "456",
});
// '/users/123/posts/456'

// Match routes
const matcher = new RouteMatcher([{ path: "/users/:id", component: null }]);
const match = matcher.match("/users/123");
// { route: {...}, params: { id: '123' }, ... }

// Create a navigator for programmatic navigation
const navigator = new Navigator();
navigator.navigate("/dashboard");
```

## Patterns & Best Practices

### Centralized Route Configuration

Create a dedicated file for your application routes:

```tsx
// routes.ts
import { RouteConfig } from "@reliance/simple-router";
import {
  HomePage,
  UserPage,
  ProductPage,
  ProductList,
  ProductDetail,
} from "./pages";
import { authGuard } from "./guards";

export const appRoutes: RouteConfig[] = [
  {
    path: "/",
    component: HomePage,
    exact: true,
    title: "Home - My App",
  },
  {
    path: "/users/:id",
    component: UserPage,
    title: "User Profile - My App",
    guards: [authGuard],
  },
  {
    path: "/products",
    component: ProductPage,
    children: [
      { path: "", component: ProductList, exact: true },
      { path: "/:id", component: ProductDetail },
    ],
  },
];
```

### Microfrontend Integration

For microfrontend architectures, each microfrontend can have its own routes that are combined at the shell level:

```tsx
// Wallet microfrontend routes
export const walletRoutes: RouteConfig[] = [
  { path: "/wallet", component: WalletDashboard, exact: true },
  { path: "/wallet/transactions", component: Transactions },
];

// Payment microfrontend routes
export const paymentRoutes: RouteConfig[] = [
  { path: "/payments", component: PaymentDashboard, exact: true },
  { path: "/payments/history", component: PaymentHistory },
];

// Shell app combines all routes
import { Router } from "@reliance/simple-router";

function App() {
  const allRoutes = [...walletRoutes, ...paymentRoutes];
  return <Router routes={allRoutes} />;
}
```

### Using Base Path for Microfrontends

Configure a base path for each microfrontend:

```tsx
// In each microfrontend
function WalletApp() {
  return <Router routes={walletRoutes} basePath="/wallet-ms" />;
}
```

## TypeScript Support

Full TypeScript support with comprehensive type definitions:

```tsx
import { useRouteParams, useQueryParams } from "@reliance/simple-router";
import type { RouteParams, QueryParams } from "@reliance/simple-router";

interface UserParams extends RouteParams {
  id: string;
}

interface UserQuery extends QueryParams {
  tab?: string;
  section?: string;
}

function UserProfile() {
  const params = useRouteParams<UserParams>();
  const { queryParams } = useQueryParams();

  // params.id is typed as string
  // queryParams.tab is typed as string | string[] | undefined
  const tab = queryParams.tab as string | undefined;
}
```

## API Reference

### Components

#### `Router`

Main router component that manages navigation and renders matched routes.

**Props:**

- `routes: RouteConfig[]` - Array of route configurations
- `basePath?: string` - Base path for all routes (default: "")
- `hashMode?: boolean` - Use hash-based routing (default: false)
- `caseSensitive?: boolean` - Case-sensitive route matching (default: false)
- `onNotFound?: React.ComponentType` - Custom 404 component
- `onLoading?: React.ComponentType` - Custom loading component

#### `Link`

Navigation link component.

**Props:**

- `to: string` - Target path
- `replace?: boolean` - Replace current history entry
- `className?: string` - CSS class
- `activeClassName?: string` - CSS class when link is active
- `exact?: boolean` - Exact path matching for active state
- `onClick?: () => void` - Click handler

### Hooks

#### `useRoute()`

Get current route match information.

**Returns:** `RouteMatch | null`

#### `useRouteParams<T>()`

Get route parameters (e.g., `/users/:id`).

**Returns:** `T extends RouteParams`

#### `useParams<T>()`

Get combined route and query parameters.

**Returns:** `T extends Record<string, any>`

#### `useQueryParams()`

Manage URL query parameters.

**Returns:**

```typescript
{
  queryParams: QueryParams;
  setQueryParam: (key: string, value: string | undefined) => void;
  setQueryParams: (params: QueryParams, replace?: boolean) => void;
  getQueryParam: (key: string) => string | undefined;
  removeQueryParam: (key: string) => void;
  clearQueryParams: () => void;
}
```

#### `useNavigate()`

Programmatic navigation.

**Returns:**

```typescript
{
  navigate: (path: string, options?: NavigateOptions) => void;
  back: () => void;
  forward: () => void;
  go: (delta: number) => void;
  replace: (path: string, options?) => void;
  buildUrl: (path: string, params?, queryParams?) => string;
  canNavigate: () => boolean;
}
```

#### `useIsActive()`

Check if a route is currently active.

**Returns:**

```typescript
{
  isActive: (path: string, exact?: boolean) => boolean;
  getActiveClass: (path: string, activeClassName?: string, exact?: boolean) =>
    string;
}
```

#### `useRouter()`

Access router context with all navigation methods and current route state.

#### `usePagination(defaultPage?, defaultLimit?, paramNames?)`

Manage pagination with URL state.

**Returns:**

```typescript
{
  page: number;
  limit: number;
  setPage: (page: number) => void;
  setLimit: (limit: number) => void;
  nextPage: () => void;
  previousPage: () => void;
  resetPagination: () => void;
}
```

#### `useFilters<T>(defaultFilters, paramPrefix?)`

Manage filters with URL state.

**Returns:**

```typescript
{
  filters: T;
  setFilter: (key: keyof T, value: T[key]) => void;
  setFilters: (filters: Partial<T>) => void;
  resetFilters: () => void;
  clearFilter: (key: keyof T) => void;
}
```

#### `useUrlState<T>(key, defaultValue, serialize?, deserialize?)`

Manage single value in URL state.

**Returns:** `[T, (value: T) => void]`

### Utilities

#### Route Guards

- `createAuthGuard(isAuthenticated, redirectTo)` - Authentication guard
- `createRoleGuard(hasRole, requiredRoles, redirectTo)` - Role-based guard
- `createPermissionGuard(hasPermission, requiredPermission, redirectTo)` - Permission guard
- `combineGuards(...guards)` - Combine guards with AND logic
- `combineGuardsOr(...guards)` - Combine guards with OR logic

#### URL Utilities

- `parseQueryParams(search)` - Parse query string
- `buildQueryString(params)` - Build query string
- `buildRoutePath(routePath, params)` - Build path with parameters
- `normalizePath(path)` - Normalize URL path
- `joinPaths(...paths)` - Join path segments

#### Route Matching

- `RouteMatcher` - Class for route matching
- `createRouteMatcher(routes, basePath?, caseSensitive?)` - Create matcher instance
- `flattenRoutes(routes, parentPath?)` - Flatten nested routes

#### Navigation

- `Navigator` - Class for navigation management
- `createNavigator(basePath?, hashMode?)` - Create navigator instance

## Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.