@flight-framework/router 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,137 +1,488 @@
1
- # @flight-framework/router
2
-
3
- Client-side routing primitives for Flight Framework.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @flight-framework/router
9
- ```
10
-
11
- ## Usage
12
-
13
- ### With React
14
-
15
- ```tsx
16
- import { RouterProvider, Link, useRouter } from '@flight-framework/router';
17
-
18
- // Wrap your app
19
- function App() {
20
- return (
21
- <RouterProvider initialPath={url}>
22
- <Navigation />
23
- <Content />
24
- </RouterProvider>
25
- );
26
- }
27
-
28
- // Use Link for navigation
29
- function Navigation() {
30
- return (
31
- <nav>
32
- <Link href="/">Home</Link>
33
- <Link href="/docs" prefetch>Docs</Link>
34
- <Link href="/about">About</Link>
35
- </nav>
36
- );
37
- }
38
-
39
- // Use hooks to access router state
40
- function Content() {
41
- const { path, navigate } = useRouter();
42
-
43
- return (
44
- <main>
45
- <p>Current path: {path}</p>
46
- <button onClick={() => navigate('/dashboard')}>
47
- Go to Dashboard
48
- </button>
49
- </main>
50
- );
51
- }
52
- ```
53
-
54
- ### Hooks
55
-
56
- ```tsx
57
- // Get current path and navigation functions
58
- const { path, searchParams, navigate, back, forward } = useRouter();
59
-
60
- // Get route parameters (from dynamic routes like [slug])
61
- const { slug } = useParams<{ slug: string }>();
62
-
63
- // Get and set search params
64
- const [searchParams, setSearchParams] = useSearchParams();
65
-
66
- // Get current pathname
67
- const pathname = usePathname();
68
- ```
69
-
70
- ### Programmatic Navigation
71
-
72
- ```ts
73
- import { navigate, prefetch } from '@flight-framework/router';
74
-
75
- // Navigate to a path
76
- navigate('/docs');
77
-
78
- // Replace history instead of push
79
- navigate('/login', { replace: true });
80
-
81
- // Navigate without scrolling to top
82
- navigate('/next-page', { scroll: false });
83
-
84
- // Pass state data
85
- navigate('/dashboard', { state: { from: '/login' } });
86
-
87
- // Prefetch a route
88
- prefetch('/heavy-page');
89
- ```
90
-
91
- ### Route Matching
92
-
93
- ```ts
94
- import { matchRoute, parseParams, generatePath } from '@flight-framework/router';
95
-
96
- // Check if a path matches a pattern
97
- const { matched, params } = matchRoute('/docs/routing', '/docs/:slug');
98
- // matched: true, params: { slug: 'routing' }
99
-
100
- // Parse params from a path
101
- const params = parseParams('/blog/2024/my-post', '/blog/:year/:slug');
102
- // { year: '2024', slug: 'my-post' }
103
-
104
- // Generate a path from pattern and params
105
- const path = generatePath('/docs/:slug', { slug: 'api-routes' });
106
- // '/docs/api-routes'
107
- ```
108
-
109
- ### Link Props
110
-
111
- | Prop | Type | Default | Description |
112
- |------|------|---------|-------------|
113
- | `href` | `string` | required | Target URL path |
114
- | `prefetch` | `boolean` | `false` | Prefetch target on hover |
115
- | `replace` | `boolean` | `false` | Replace history entry |
116
- | `scroll` | `boolean` | `true` | Scroll to top on navigate |
117
- | `target` | `string` | - | Link target (_blank, etc) |
118
- | `className` | `string` | - | CSS class |
119
-
120
- ## SSR Support
121
-
122
- The router is SSR-safe. Pass the initial path from your server:
123
-
124
- ```tsx
125
- // entry-server.tsx
126
- export function render(url: string) {
127
- return renderToString(
128
- <RouterProvider initialPath={url}>
129
- <App />
130
- </RouterProvider>
131
- );
132
- }
133
- ```
134
-
135
- ## License
136
-
137
- MIT
1
+ # @flight-framework/router
2
+
3
+ Universal client-side routing primitives for Flight Framework. Zero external dependencies. Works with any UI framework.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Features](#features)
8
+ - [Installation](#installation)
9
+ - [Quick Start](#quick-start)
10
+ - [Prefetch Strategies](#prefetch-strategies)
11
+ - [Smart Prefetching](#smart-prefetching)
12
+ - [Intercepting Routes](#intercepting-routes)
13
+ - [Programmatic Prefetching](#programmatic-prefetching)
14
+ - [Prefetch Queue](#prefetch-queue)
15
+ - [React Hooks](#react-hooks)
16
+ - [Programmatic Navigation](#programmatic-navigation)
17
+ - [Route Matching](#route-matching)
18
+ - [Link Component](#link-component)
19
+ - [Framework Integration](#framework-integration)
20
+ - [SSR Support](#ssr-support)
21
+ - [Browser Support](#browser-support)
22
+ - [License](#license)
23
+
24
+ ---
25
+
26
+ ## Features
27
+
28
+ - Multiple prefetch strategies (none, intent, render, viewport, idle)
29
+ - Network-aware smart prefetching (respects Save-Data and connection speed)
30
+ - Intercepting routes with modal support
31
+ - Prefetch queue with concurrency control
32
+ - SSR-safe implementation
33
+ - Framework-agnostic with React adapters
34
+ - TypeScript-first design
35
+ - IntersectionObserver for viewport prefetching
36
+ - Zero external dependencies
37
+
38
+ ---
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ npm install @flight-framework/router
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Quick Start
49
+
50
+ ### With React
51
+
52
+ ```tsx
53
+ import { RouterProvider, Link, useRouter } from '@flight-framework/router';
54
+
55
+ function App() {
56
+ return (
57
+ <RouterProvider initialPath={url}>
58
+ <Navigation />
59
+ <Content />
60
+ </RouterProvider>
61
+ );
62
+ }
63
+
64
+ function Navigation() {
65
+ return (
66
+ <nav>
67
+ <Link href="/">Home</Link>
68
+ <Link href="/docs" prefetch="intent">Docs</Link>
69
+ <Link href="/about">About</Link>
70
+ </nav>
71
+ );
72
+ }
73
+
74
+ function Content() {
75
+ const { path, navigate } = useRouter();
76
+
77
+ return (
78
+ <main>
79
+ <p>Current path: {path}</p>
80
+ <button onClick={() => navigate('/dashboard')}>
81
+ Go to Dashboard
82
+ </button>
83
+ </main>
84
+ );
85
+ }
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Prefetch Strategies
91
+
92
+ Flight Router supports multiple prefetch strategies to optimize navigation performance:
93
+
94
+ | Strategy | Behavior | Best For |
95
+ |----------|----------|----------|
96
+ | `'none'` | No prefetching (default) | Low-priority links |
97
+ | `'intent'` | Prefetch on hover/focus | Most navigation links |
98
+ | `'render'` | Prefetch immediately | Critical paths (checkout) |
99
+ | `'viewport'` | Prefetch when visible | Mobile, infinite scroll |
100
+ | `'idle'` | Prefetch when browser is idle | Background preloading |
101
+
102
+ ### Usage Examples
103
+
104
+ ```tsx
105
+ // No prefetching (default)
106
+ <Link href="/docs">Docs</Link>
107
+ <Link href="/docs" prefetch="none">Docs</Link>
108
+
109
+ // Prefetch on hover/focus (recommended for most cases)
110
+ <Link href="/docs" prefetch="intent">Docs</Link>
111
+ <Link href="/docs" prefetch>Docs</Link> // boolean true = "intent"
112
+
113
+ // Prefetch immediately when link renders
114
+ <Link href="/checkout" prefetch="render">Checkout</Link>
115
+
116
+ // Prefetch when link enters viewport (good for mobile)
117
+ <Link href="/products" prefetch="viewport">Products</Link>
118
+
119
+ // Prefetch when browser is idle
120
+ <Link href="/settings" prefetch="idle">Settings</Link>
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Smart Prefetching
126
+
127
+ Network-aware prefetching that respects user preferences and connection quality.
128
+
129
+ ### Features
130
+
131
+ - Respects `Save-Data` header (users on limited data plans)
132
+ - Detects connection type (2G, 3G, 4G)
133
+ - Configurable minimum network requirements
134
+ - Automatic throttling on slow connections
135
+
136
+ ### API
137
+
138
+ ```typescript
139
+ import {
140
+ smartPrefetch,
141
+ shouldSkipPrefetch,
142
+ canPrefetchOnNetwork,
143
+ } from '@flight-framework/router';
144
+
145
+ // Respects network conditions automatically
146
+ smartPrefetch('/dashboard');
147
+
148
+ // Check if prefetching should be skipped
149
+ if (shouldSkipPrefetch()) {
150
+ console.log('Skipping due to network conditions');
151
+ }
152
+
153
+ // Custom network requirements
154
+ const canPrefetch = canPrefetchOnNetwork({
155
+ respectSaveData: true, // Skip if Save-Data enabled
156
+ respectSlowNetwork: true, // Skip on 2G/slow-2G
157
+ minEffectiveType: '3g', // Minimum 3G required
158
+ });
159
+ ```
160
+
161
+ ### Configuration
162
+
163
+ ```typescript
164
+ smartPrefetch('/page', {
165
+ respectSaveData: true, // Default: true
166
+ respectSlowNetwork: true, // Default: true
167
+ minEffectiveType: '3g', // Default: '3g'
168
+ priority: 'high', // Optional priority override
169
+ });
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Intercepting Routes
175
+
176
+ Render routes in modals while preserving URL state. Perfect for photo galleries, user profiles, and detail views.
177
+
178
+ ### React Integration
179
+
180
+ ```tsx
181
+ import {
182
+ InterceptedRouteProvider,
183
+ useInterceptedRoute,
184
+ } from '@flight-framework/router';
185
+
186
+ // Wrap your layout
187
+ function RootLayout({ children }) {
188
+ return (
189
+ <InterceptedRouteProvider>
190
+ {children}
191
+ <ModalRenderer />
192
+ </InterceptedRouteProvider>
193
+ );
194
+ }
195
+
196
+ // Render intercepted content in a modal
197
+ function ModalRenderer() {
198
+ const intercepted = useInterceptedRoute();
199
+
200
+ if (!intercepted) return null;
201
+
202
+ return (
203
+ <Dialog open onClose={intercepted.dismiss}>
204
+ <intercepted.Component />
205
+ <button onClick={intercepted.navigateToPage}>
206
+ View Full Page
207
+ </button>
208
+ </Dialog>
209
+ );
210
+ }
211
+ ```
212
+
213
+ ### Intercepted Route State
214
+
215
+ | Property | Type | Description |
216
+ |----------|------|-------------|
217
+ | `Component` | `() => unknown` | The component to render |
218
+ | `pathname` | `string` | The intercepted URL path |
219
+ | `params` | `Record<string, string>` | Route parameters |
220
+ | `dismiss()` | `() => void` | Go back (close modal) |
221
+ | `navigateToPage()` | `() => void` | Navigate to actual page |
222
+
223
+ ### Additional Hooks
224
+
225
+ ```typescript
226
+ import {
227
+ useInterceptedRoute,
228
+ useSetInterceptedRoute,
229
+ useIsIntercepting,
230
+ } from '@flight-framework/router';
231
+
232
+ // Check if currently intercepting
233
+ const isIntercepting = useIsIntercepting();
234
+
235
+ // Programmatically set intercepted state (for router integration)
236
+ const setIntercepted = useSetInterceptedRoute();
237
+ ```
238
+
239
+ ---
240
+
241
+ ## Programmatic Prefetching
242
+
243
+ ```typescript
244
+ import {
245
+ prefetch,
246
+ prefetchAll,
247
+ prefetchWhenIdle,
248
+ isPrefetched,
249
+ clearPrefetchCache,
250
+ } from '@flight-framework/router';
251
+
252
+ // Basic prefetch
253
+ prefetch('/docs');
254
+
255
+ // High priority prefetch
256
+ prefetch('/checkout', { priority: 'high' });
257
+
258
+ // Prefetch with data loaders
259
+ prefetch('/products', { includeData: true });
260
+
261
+ // Prefetch multiple pages
262
+ prefetchAll(['/page1', '/page2', '/page3']);
263
+
264
+ // Prefetch when browser is idle
265
+ prefetchWhenIdle('/dashboard');
266
+
267
+ // Check if already prefetched
268
+ if (!isPrefetched('/docs')) {
269
+ prefetch('/docs');
270
+ }
271
+
272
+ // Clear prefetch cache (useful for testing)
273
+ clearPrefetchCache();
274
+ ```
275
+
276
+ ---
277
+
278
+ ## Prefetch Queue
279
+
280
+ Control concurrent prefetch requests to avoid overwhelming the network:
281
+
282
+ ```typescript
283
+ import { PrefetchQueue } from '@flight-framework/router';
284
+
285
+ // Create queue with max 3 concurrent prefetches
286
+ const queue = new PrefetchQueue(3);
287
+
288
+ // Add URLs to queue
289
+ queue.add('/page1');
290
+ queue.add('/page2', { priority: 'high' });
291
+ queue.addAll(['/page3', '/page4', '/page5']);
292
+
293
+ // Control queue
294
+ queue.pause(); // Stop processing
295
+ queue.resume(); // Continue processing
296
+ queue.clear(); // Remove pending items
297
+
298
+ // Check state
299
+ console.log(queue.pending); // Items waiting
300
+ console.log(queue.activeCount); // Currently prefetching
301
+ ```
302
+
303
+ ---
304
+
305
+ ## React Hooks
306
+
307
+ ```tsx
308
+ import {
309
+ useRouter,
310
+ useParams,
311
+ useSearchParams,
312
+ usePathname,
313
+ } from '@flight-framework/router';
314
+
315
+ // Get current path and navigation functions
316
+ const { path, searchParams, navigate, back, forward } = useRouter();
317
+
318
+ // Get route parameters (from dynamic routes like [slug])
319
+ const { slug } = useParams<{ slug: string }>();
320
+
321
+ // Get and set search params
322
+ const [searchParams, setSearchParams] = useSearchParams();
323
+
324
+ // Get current pathname
325
+ const pathname = usePathname();
326
+ ```
327
+
328
+ ---
329
+
330
+ ## Programmatic Navigation
331
+
332
+ ```typescript
333
+ import { navigate, prefetch } from '@flight-framework/router';
334
+
335
+ // Navigate to a path
336
+ navigate('/docs');
337
+
338
+ // Replace history instead of push
339
+ navigate('/login', { replace: true });
340
+
341
+ // Navigate without scrolling to top
342
+ navigate('/next-page', { scroll: false });
343
+
344
+ // Pass state data
345
+ navigate('/dashboard', { state: { from: '/login' } });
346
+ ```
347
+
348
+ ---
349
+
350
+ ## Route Matching
351
+
352
+ ```typescript
353
+ import { matchRoute, parseParams, generatePath } from '@flight-framework/router';
354
+
355
+ // Check if a path matches a pattern
356
+ const { matched, params } = matchRoute('/docs/routing', '/docs/:slug');
357
+ // matched: true, params: { slug: 'routing' }
358
+
359
+ // Parse params from a path
360
+ const params = parseParams('/blog/2024/my-post', '/blog/:year/:slug');
361
+ // { year: '2024', slug: 'my-post' }
362
+
363
+ // Generate a path from pattern and params
364
+ const path = generatePath('/docs/:slug', { slug: 'api-routes' });
365
+ // '/docs/api-routes'
366
+ ```
367
+
368
+ ---
369
+
370
+ ## Link Component
371
+
372
+ ### Props
373
+
374
+ | Prop | Type | Default | Description |
375
+ |------|------|---------|-------------|
376
+ | `href` | `string` | required | Target URL path |
377
+ | `prefetch` | `boolean \| PrefetchStrategy` | `'none'` | Prefetch strategy |
378
+ | `replace` | `boolean` | `false` | Replace history entry |
379
+ | `scroll` | `boolean` | `true` | Scroll to top on navigate |
380
+ | `target` | `string` | - | Link target (_blank, etc) |
381
+ | `className` | `string` | - | CSS class |
382
+ | `aria-label` | `string` | - | Accessibility label |
383
+
384
+ ### PrefetchPageLinks Component
385
+
386
+ For proactive prefetching based on user behavior:
387
+
388
+ ```tsx
389
+ import { PrefetchPageLinks } from '@flight-framework/router';
390
+
391
+ function SearchResults({ results }) {
392
+ return (
393
+ <>
394
+ {results.map(result => (
395
+ <div key={result.id}>
396
+ <PrefetchPageLinks page={result.url} />
397
+ <Link href={result.url}>{result.title}</Link>
398
+ </div>
399
+ ))}
400
+ </>
401
+ );
402
+ }
403
+ ```
404
+
405
+ ---
406
+
407
+ ## Framework Integration
408
+
409
+ ### Vue
410
+
411
+ ```vue
412
+ <script setup>
413
+ import { useLinkProps } from '@flight-framework/router';
414
+
415
+ const docsLink = useLinkProps('/docs', { prefetch: 'intent' });
416
+ </script>
417
+
418
+ <template>
419
+ <a v-bind="docsLink">Documentation</a>
420
+ </template>
421
+ ```
422
+
423
+ ### Vanilla JavaScript
424
+
425
+ ```typescript
426
+ import { createLink, prefetch } from '@flight-framework/router';
427
+
428
+ const link = createLink({
429
+ href: '/docs',
430
+ children: 'Documentation',
431
+ prefetch: 'intent',
432
+ });
433
+
434
+ document.body.appendChild(link);
435
+ ```
436
+
437
+ ---
438
+
439
+ ## SSR Support
440
+
441
+ The router is SSR-safe. Pass the initial path from your server:
442
+
443
+ ```tsx
444
+ // entry-server.tsx
445
+ export function render(url: string) {
446
+ return renderToString(
447
+ <RouterProvider initialPath={url}>
448
+ <App />
449
+ </RouterProvider>
450
+ );
451
+ }
452
+ ```
453
+
454
+ ---
455
+
456
+ ## Browser Support
457
+
458
+ | Feature | Chrome | Firefox | Safari | Edge |
459
+ |---------|--------|---------|--------|------|
460
+ | Prefetch | All | All | All | All |
461
+ | Viewport (IntersectionObserver) | 51+ | 55+ | 12.1+ | 15+ |
462
+ | Network Information API | 61+ | No | No | 79+ |
463
+ | requestIdleCallback | 47+ | 55+ | No | 79+ |
464
+ | fetchPriority | 101+ | No | No | 101+ |
465
+
466
+ Features gracefully degrade when APIs are unavailable.
467
+
468
+ ---
469
+
470
+ ## TypeScript
471
+
472
+ Full TypeScript support with exported types:
473
+
474
+ ```typescript
475
+ import type {
476
+ PrefetchStrategy,
477
+ PrefetchOptions,
478
+ SmartPrefetchOptions,
479
+ InterceptedRouteState,
480
+ InterceptedRouteContextValue,
481
+ } from '@flight-framework/router';
482
+ ```
483
+
484
+ ---
485
+
486
+ ## License
487
+
488
+ MIT