npm package: @flightdev/router
Description: Agnostic client-side routing primitives for Flight Framework
Author: Flight Framework
Latest version: 0.5.0

# @flightdev/router

Universal client-side routing primitives for Flight Framework. Zero external dependencies. Works with any UI framework.

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Prefetch Strategies](#prefetch-strategies)
- [Smart Prefetching](#smart-prefetching)
- [Intercepting Routes](#intercepting-routes)
- [Programmatic Prefetching](#programmatic-prefetching)
- [Prefetch Queue](#prefetch-queue)
- [React Hooks](#react-hooks)
- [Programmatic Navigation](#programmatic-navigation)
- [Route Matching](#route-matching)
- [Link Component](#link-component)
- [Framework Integration](#framework-integration)
- [SSR Support](#ssr-support)
- [Browser Support](#browser-support)
- [License](#license)

---

## Features

- Multiple prefetch strategies (none, intent, render, viewport, idle)
- Network-aware smart prefetching (respects Save-Data and connection speed)
- Intercepting routes with modal support
- Prefetch queue with concurrency control
- SSR-safe implementation
- Framework-agnostic with React adapters
- TypeScript-first design
- IntersectionObserver for viewport prefetching
- Zero external dependencies

---

## Installation

```bash
npm install @flightdev/router
```

---

## Quick Start

### With React

```tsx
import { RouterProvider, Link, useRouter } from '@flightdev/router';

function App() {
    return (
        <RouterProvider initialPath={url}>
            <Navigation />
            <Content />
        </RouterProvider>
    );
}

function Navigation() {
    return (
        <nav>
            <Link href="/">Home</Link>
            <Link href="/docs" prefetch="intent">Docs</Link>
            <Link href="/about">About</Link>
        </nav>
    );
}

function Content() {
    const { path, navigate } = useRouter();

    return (
        <main>
            <p>Current path: {path}</p>
            <button onClick={() => navigate('/dashboard')}>
                Go to Dashboard
            </button>
        </main>
    );
}
```

---

## Prefetch Strategies

Flight Router supports multiple prefetch strategies to optimize navigation performance:

| Strategy | Behavior | Best For |
|----------|----------|----------|
| `'none'` | No prefetching (default) | Low-priority links |
| `'intent'` | Prefetch on hover/focus | Most navigation links |
| `'render'` | Prefetch immediately | Critical paths (checkout) |
| `'viewport'` | Prefetch when visible | Mobile, infinite scroll |
| `'idle'` | Prefetch when browser is idle | Background preloading |

### Usage Examples

```tsx
// No prefetching (default)
<Link href="/docs">Docs</Link>
<Link href="/docs" prefetch="none">Docs</Link>

// Prefetch on hover/focus (recommended for most cases)
<Link href="/docs" prefetch="intent">Docs</Link>
<Link href="/docs" prefetch>Docs</Link>  // boolean true = "intent"

// Prefetch immediately when link renders
<Link href="/checkout" prefetch="render">Checkout</Link>

// Prefetch when link enters viewport (good for mobile)
<Link href="/products" prefetch="viewport">Products</Link>

// Prefetch when browser is idle
<Link href="/settings" prefetch="idle">Settings</Link>
```

---

## Smart Prefetching

Network-aware prefetching that respects user preferences and connection quality.

### Features

- Respects `Save-Data` header (users on limited data plans)
- Detects connection type (2G, 3G, 4G)
- Configurable minimum network requirements
- Automatic throttling on slow connections

### API

```typescript
import {
    smartPrefetch,
    shouldSkipPrefetch,
    canPrefetchOnNetwork,
} from '@flightdev/router';

// Respects network conditions automatically
smartPrefetch('/dashboard');

// Check if prefetching should be skipped
if (shouldSkipPrefetch()) {
    console.log('Skipping due to network conditions');
}

// Custom network requirements
const canPrefetch = canPrefetchOnNetwork({
    respectSaveData: true,      // Skip if Save-Data enabled
    respectSlowNetwork: true,   // Skip on 2G/slow-2G
    minEffectiveType: '3g',     // Minimum 3G required
});
```

### Configuration

```typescript
smartPrefetch('/page', {
    respectSaveData: true,      // Default: true
    respectSlowNetwork: true,   // Default: true
    minEffectiveType: '3g',     // Default: '3g'
    priority: 'high',           // Optional priority override
});
```

---

## Intercepting Routes

Render routes in modals while preserving URL state. Perfect for photo galleries, user profiles, and detail views.

### React Integration

```tsx
import {
    InterceptedRouteProvider,
    useInterceptedRoute,
} from '@flightdev/router';

// Wrap your layout
function RootLayout({ children }) {
    return (
        <InterceptedRouteProvider>
            {children}
            <ModalRenderer />
        </InterceptedRouteProvider>
    );
}

// Render intercepted content in a modal
function ModalRenderer() {
    const intercepted = useInterceptedRoute();

    if (!intercepted) return null;

    return (
        <Dialog open onClose={intercepted.dismiss}>
            <intercepted.Component />
            <button onClick={intercepted.navigateToPage}>
                View Full Page
            </button>
        </Dialog>
    );
}
```

### Intercepted Route State

| Property | Type | Description |
|----------|------|-------------|
| `Component` | `() => unknown` | The component to render |
| `pathname` | `string` | The intercepted URL path |
| `params` | `Record<string, string>` | Route parameters |
| `dismiss()` | `() => void` | Go back (close modal) |
| `navigateToPage()` | `() => void` | Navigate to actual page |

### Additional Hooks

```typescript
import {
    useInterceptedRoute,
    useSetInterceptedRoute,
    useIsIntercepting,
} from '@flightdev/router';

// Check if currently intercepting
const isIntercepting = useIsIntercepting();

// Programmatically set intercepted state (for router integration)
const setIntercepted = useSetInterceptedRoute();
```

---

## Programmatic Prefetching

```typescript
import {
    prefetch,
    prefetchAll,
    prefetchWhenIdle,
    isPrefetched,
    clearPrefetchCache,
} from '@flightdev/router';

// Basic prefetch
prefetch('/docs');

// High priority prefetch
prefetch('/checkout', { priority: 'high' });

// Prefetch with data loaders
prefetch('/products', { includeData: true });

// Prefetch multiple pages
prefetchAll(['/page1', '/page2', '/page3']);

// Prefetch when browser is idle
prefetchWhenIdle('/dashboard');

// Check if already prefetched
if (!isPrefetched('/docs')) {
    prefetch('/docs');
}

// Clear prefetch cache (useful for testing)
clearPrefetchCache();
```

---

## Prefetch Queue

Control concurrent prefetch requests to avoid overwhelming the network:

```typescript
import { PrefetchQueue } from '@flightdev/router';

// Create queue with max 3 concurrent prefetches
const queue = new PrefetchQueue(3);

// Add URLs to queue
queue.add('/page1');
queue.add('/page2', { priority: 'high' });
queue.addAll(['/page3', '/page4', '/page5']);

// Control queue
queue.pause();   // Stop processing
queue.resume();  // Continue processing
queue.clear();   // Remove pending items

// Check state
console.log(queue.pending);     // Items waiting
console.log(queue.activeCount); // Currently prefetching
```

---

## React Hooks

```tsx
import {
    useRouter,
    useParams,
    useSearchParams,
    usePathname,
} from '@flightdev/router';

// Get current path and navigation functions
const { path, searchParams, navigate, back, forward } = useRouter();

// Get route parameters (from dynamic routes like [slug])
const { slug } = useParams<{ slug: string }>();

// Get and set search params
const [searchParams, setSearchParams] = useSearchParams();

// Get current pathname
const pathname = usePathname();
```

---

## Programmatic Navigation

```typescript
import { navigate, prefetch } from '@flightdev/router';

// Navigate to a path
navigate('/docs');

// Replace history instead of push
navigate('/login', { replace: true });

// Navigate without scrolling to top
navigate('/next-page', { scroll: false });

// Pass state data
navigate('/dashboard', { state: { from: '/login' } });
```

---

## Route Matching

```typescript
import { matchRoute, parseParams, generatePath } from '@flightdev/router';

// Check if a path matches a pattern
const { matched, params } = matchRoute('/docs/routing', '/docs/:slug');
// matched: true, params: { slug: 'routing' }

// Parse params from a path
const params = parseParams('/blog/2024/my-post', '/blog/:year/:slug');
// { year: '2024', slug: 'my-post' }

// Generate a path from pattern and params
const path = generatePath('/docs/:slug', { slug: 'api-routes' });
// '/docs/api-routes'
```

---

## Link Component

### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `href` | `string` | required | Target URL path |
| `prefetch` | `boolean \| PrefetchStrategy` | `'none'` | Prefetch strategy |
| `replace` | `boolean` | `false` | Replace history entry |
| `scroll` | `boolean` | `true` | Scroll to top on navigate |
| `target` | `string` | - | Link target (_blank, etc) |
| `className` | `string` | - | CSS class |
| `aria-label` | `string` | - | Accessibility label |

### PrefetchPageLinks Component

For proactive prefetching based on user behavior:

```tsx
import { PrefetchPageLinks } from '@flightdev/router';

function SearchResults({ results }) {
    return (
        <>
            {results.map(result => (
                <div key={result.id}>
                    <PrefetchPageLinks page={result.url} />
                    <Link href={result.url}>{result.title}</Link>
                </div>
            ))}
        </>
    );
}
```

---

## Framework Integration

### Vue

```vue
<script setup>
import { useLinkProps } from '@flightdev/router';

const docsLink = useLinkProps('/docs', { prefetch: 'intent' });
</script>

<template>
    <a v-bind="docsLink">Documentation</a>
</template>
```

### Vanilla JavaScript

```typescript
import { createLink, prefetch } from '@flightdev/router';

const link = createLink({
    href: '/docs',
    children: 'Documentation',
    prefetch: 'intent',
});

document.body.appendChild(link);
```

---

## SSR Support

The router is SSR-safe. Pass the initial path from your server:

```tsx
// entry-server.tsx
export function render(url: string) {
    return renderToString(
        <RouterProvider initialPath={url}>
            <App />
        </RouterProvider>
    );
}
```

---

## Browser Support

| Feature | Chrome | Firefox | Safari | Edge |
|---------|--------|---------|--------|------|
| Prefetch | All | All | All | All |
| Viewport (IntersectionObserver) | 51+ | 55+ | 12.1+ | 15+ |
| Network Information API | 61+ | No | No | 79+ |
| requestIdleCallback | 47+ | 55+ | No | 79+ |
| fetchPriority | 101+ | No | No | 101+ |

Features gracefully degrade when APIs are unavailable.

---

## TypeScript

Full TypeScript support with exported types:

```typescript
import type {
    PrefetchStrategy,
    PrefetchOptions,
    SmartPrefetchOptions,
    InterceptedRouteState,
    InterceptedRouteContextValue,
} from '@flightdev/router';
```

---

## License

MIT