@fictjs/router 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,3 +1,1137 @@
1
- declare const Router: () => void;
1
+ import { Component, FictNode, JSX, StyleProp } from '@fictjs/runtime';
2
2
 
3
- export { Router };
3
+ /**
4
+ * @fileoverview Core type definitions for @fictjs/router
5
+ *
6
+ * This module defines the fundamental types used throughout the router.
7
+ * Designed to integrate seamlessly with Fict's reactive system.
8
+ */
9
+
10
+ /**
11
+ * Represents a location in the router.
12
+ * Similar to window.location but with reactive support.
13
+ */
14
+ interface Location {
15
+ /** The pathname portion of the URL (e.g., "/users/123") */
16
+ pathname: string;
17
+ /** The search/query portion of the URL (e.g., "?page=1") */
18
+ search: string;
19
+ /** The hash portion of the URL (e.g., "#section") */
20
+ hash: string;
21
+ /** State associated with this location */
22
+ state: unknown;
23
+ /** Unique key for this location entry */
24
+ key: string;
25
+ }
26
+ /**
27
+ * Target for navigation - can be a string path or a partial location object
28
+ */
29
+ type To = string | Partial<Location>;
30
+ /**
31
+ * Navigation intent type
32
+ */
33
+ type NavigationIntent = 'initial' | 'navigate' | 'native' | 'preload';
34
+ /**
35
+ * Route parameters extracted from the URL
36
+ */
37
+ type Params<Key extends string = string> = Readonly<Record<Key, string | undefined>>;
38
+ /**
39
+ * Search parameters from the query string
40
+ */
41
+ type SearchParams = URLSearchParams;
42
+ /**
43
+ * Match filter for validating route parameters
44
+ */
45
+ type MatchFilter<T = string> = RegExp | readonly T[] | ((value: string) => boolean);
46
+ /**
47
+ * Match filters for route parameters
48
+ */
49
+ type MatchFilters<P extends string = string> = Partial<Record<P, MatchFilter>>;
50
+ /**
51
+ * Props passed to route components
52
+ */
53
+ interface RouteComponentProps<P extends string = string> {
54
+ /** Route parameters */
55
+ params: Params<P>;
56
+ /** Current location */
57
+ location: Location;
58
+ /** Preloaded data (if preload function is defined) */
59
+ data?: unknown;
60
+ /** Children routes rendered via <Outlet /> */
61
+ children?: FictNode;
62
+ /** Allow additional properties for component extensibility */
63
+ [key: string]: unknown;
64
+ }
65
+ /**
66
+ * Preload function arguments
67
+ */
68
+ interface PreloadArgs<P extends string = string> {
69
+ /** Route parameters */
70
+ params: Params<P>;
71
+ /** Current location */
72
+ location: Location;
73
+ /** Navigation intent */
74
+ intent: NavigationIntent;
75
+ }
76
+ /**
77
+ * Preload function type
78
+ */
79
+ type PreloadFunction<T = unknown, P extends string = string> = (args: PreloadArgs<P>) => T | Promise<T>;
80
+ /**
81
+ * Route definition - user-facing configuration
82
+ */
83
+ interface RouteDefinition<P extends string = string> {
84
+ /** Path pattern (e.g., "/users/:id", "/items/:id?") */
85
+ path?: string;
86
+ /** Component to render for this route */
87
+ component?: Component<RouteComponentProps<P>>;
88
+ /** Element to render (alternative to component) */
89
+ element?: FictNode;
90
+ /** Preload function for data loading */
91
+ preload?: PreloadFunction<unknown, P>;
92
+ /** Nested child routes */
93
+ children?: RouteDefinition[];
94
+ /** Parameter validation filters */
95
+ matchFilters?: MatchFilters<P>;
96
+ /** Whether this is an index route */
97
+ index?: boolean;
98
+ /** Route key for caching/optimization */
99
+ key?: string;
100
+ /** Catch-all error boundary element */
101
+ errorElement?: FictNode;
102
+ /** Loading fallback element */
103
+ loadingElement?: FictNode;
104
+ }
105
+ /**
106
+ * Props for the Route component (JSX-based definition)
107
+ */
108
+ interface RouteProps<P extends string = string> extends Omit<RouteDefinition<P>, 'children'> {
109
+ /** JSX children (nested Route components) */
110
+ children?: FictNode;
111
+ }
112
+ /**
113
+ * Result of matching a route against a location
114
+ */
115
+ interface RouteMatch<P extends string = string> {
116
+ /** The matched route definition */
117
+ route: RouteDefinition<P>;
118
+ /** The matched portion of the pathname */
119
+ pathname: string;
120
+ /** Extracted parameters */
121
+ params: Params<P>;
122
+ /** The pattern that matched */
123
+ pattern: string;
124
+ }
125
+ /**
126
+ * Internal compiled route with matcher function
127
+ */
128
+ interface CompiledRoute {
129
+ /** Original route definition */
130
+ route: RouteDefinition;
131
+ /** Normalized path pattern */
132
+ pattern: string;
133
+ /** Matcher function */
134
+ matcher: (pathname: string) => RouteMatch | null;
135
+ /** Route score for ranking */
136
+ score: number;
137
+ /** Child compiled routes */
138
+ children?: CompiledRoute[];
139
+ /** Unique key for this route */
140
+ key: string;
141
+ }
142
+ /**
143
+ * Branch of routes (for nested route matching)
144
+ */
145
+ interface RouteBranch {
146
+ /** Routes in this branch from root to leaf */
147
+ routes: CompiledRoute[];
148
+ /** Combined score for the branch */
149
+ score: number;
150
+ /** Matcher for the entire branch */
151
+ matcher: (pathname: string) => RouteMatch[] | null;
152
+ }
153
+ /**
154
+ * Options for navigation
155
+ */
156
+ interface NavigateOptions {
157
+ /** Replace current history entry instead of pushing */
158
+ replace?: boolean | undefined;
159
+ /** State to pass with the navigation */
160
+ state?: unknown;
161
+ /** Scroll to top after navigation */
162
+ scroll?: boolean | undefined;
163
+ /** Resolve path relative to current route */
164
+ relative?: 'route' | 'path' | undefined;
165
+ }
166
+ /**
167
+ * Navigation function type
168
+ */
169
+ interface NavigateFunction {
170
+ (to: To, options?: NavigateOptions): void;
171
+ (delta: number): void;
172
+ }
173
+ /**
174
+ * Navigation state during transitions
175
+ */
176
+ interface Navigation {
177
+ /** Current navigation state */
178
+ state: 'idle' | 'loading' | 'submitting';
179
+ /** Target location (if loading) */
180
+ location?: Location;
181
+ /** Form data (if submitting) */
182
+ formData?: FormData;
183
+ /** Form action (if submitting) */
184
+ formAction?: string;
185
+ /** Form method (if submitting) */
186
+ formMethod?: string;
187
+ }
188
+ /**
189
+ * Router context value
190
+ */
191
+ interface RouterContextValue {
192
+ /** Current location (reactive) */
193
+ location: () => Location;
194
+ /** Route parameters (reactive) */
195
+ params: () => Params;
196
+ /** Current matches (reactive) */
197
+ matches: () => RouteMatch[];
198
+ /** Navigate function */
199
+ navigate: NavigateFunction;
200
+ /** Whether currently routing */
201
+ isRouting: () => boolean;
202
+ /** Pending navigation target (if routing) */
203
+ pendingLocation: () => Location | null;
204
+ /** Base path for the router */
205
+ base: string;
206
+ /** Resolve a path relative to the current route */
207
+ resolvePath: (to: To) => string;
208
+ }
209
+ /**
210
+ * Route context value (for nested routes)
211
+ */
212
+ interface RouteContextValue {
213
+ /** The current route match */
214
+ match: () => RouteMatch | undefined;
215
+ /** Preloaded data */
216
+ data: () => unknown;
217
+ /** Route error (if any) */
218
+ error?: () => unknown;
219
+ /** Outlet function to render child route */
220
+ outlet: () => FictNode;
221
+ /** Parent route context */
222
+ parent?: RouteContextValue;
223
+ /** Resolve path relative to this route */
224
+ resolvePath: (to: To) => string;
225
+ }
226
+ /**
227
+ * History action type
228
+ */
229
+ type HistoryAction = 'POP' | 'PUSH' | 'REPLACE';
230
+ /**
231
+ * History listener callback
232
+ */
233
+ type HistoryListener = (update: {
234
+ action: HistoryAction;
235
+ location: Location;
236
+ }) => void;
237
+ /**
238
+ * History interface (browser, hash, or memory)
239
+ */
240
+ interface History {
241
+ /** Current action */
242
+ readonly action: HistoryAction;
243
+ /** Current location */
244
+ readonly location: Location;
245
+ /** Push a new entry */
246
+ push(to: To, state?: unknown): void;
247
+ /** Replace the current entry */
248
+ replace(to: To, state?: unknown): void;
249
+ /** Go forward or backward */
250
+ go(delta: number): void;
251
+ /** Go back one entry */
252
+ back(): void;
253
+ /** Go forward one entry */
254
+ forward(): void;
255
+ /** Listen for location changes */
256
+ listen(listener: HistoryListener): () => void;
257
+ /** Create an href from a To value */
258
+ createHref(to: To): string;
259
+ /** Block navigation */
260
+ block(blocker: Blocker): () => void;
261
+ }
262
+ /**
263
+ * Blocker function for preventing navigation
264
+ */
265
+ type Blocker = (tx: {
266
+ action: HistoryAction;
267
+ location: Location;
268
+ retry: () => void;
269
+ }) => void;
270
+ /**
271
+ * Arguments passed to beforeLeave handlers
272
+ */
273
+ interface BeforeLeaveEventArgs {
274
+ /** Target location */
275
+ to: Location;
276
+ /** Current location */
277
+ from: Location;
278
+ /** Whether this was prevented */
279
+ defaultPrevented: boolean;
280
+ /** Prevent the navigation */
281
+ preventDefault: () => void;
282
+ /** Retry the navigation */
283
+ retry: (force?: boolean) => void;
284
+ }
285
+ /**
286
+ * BeforeLeave handler function
287
+ */
288
+ type BeforeLeaveHandler = (e: BeforeLeaveEventArgs) => void | Promise<void>;
289
+ /**
290
+ * Submission state
291
+ */
292
+ interface Submission<T = unknown> {
293
+ /** Unique submission key */
294
+ key: string;
295
+ /** Form data being submitted */
296
+ formData: FormData;
297
+ /** Submission state */
298
+ state: 'submitting' | 'loading' | 'idle';
299
+ /** Result data */
300
+ result?: T;
301
+ /** Error if submission failed */
302
+ error?: unknown;
303
+ /** Clear the submission */
304
+ clear: () => void;
305
+ /** Retry the submission */
306
+ retry: () => void;
307
+ }
308
+ /**
309
+ * Action function type
310
+ */
311
+ type ActionFunction<T = unknown> = (formData: FormData, args: {
312
+ params: Params;
313
+ request: Request;
314
+ }) => T | Promise<T>;
315
+ /**
316
+ * Action object returned by createAction
317
+ */
318
+ interface Action<T = unknown> {
319
+ /** Action URL */
320
+ url: string;
321
+ /** Submit the action */
322
+ submit: (formData: FormData) => Promise<T>;
323
+ /** Action name */
324
+ name?: string;
325
+ }
326
+ /**
327
+ * Query function type
328
+ */
329
+ type QueryFunction<T = unknown, Args extends unknown[] = unknown[]> = (...args: Args) => T | Promise<T>;
330
+ /**
331
+ * Query cache entry
332
+ */
333
+ interface QueryCacheEntry<T = unknown> {
334
+ /** Timestamp when cached */
335
+ timestamp: number;
336
+ /** Cached promise */
337
+ promise: Promise<T>;
338
+ /** Resolved result */
339
+ result?: T;
340
+ /** Intent when fetched */
341
+ intent: NavigationIntent;
342
+ }
343
+ /**
344
+ * Router configuration options
345
+ */
346
+ interface RouterOptions {
347
+ /** Base path for the router */
348
+ base?: string;
349
+ /** Initial location (for SSR) */
350
+ url?: string;
351
+ /** History implementation to use */
352
+ history?: History;
353
+ /** Data preloaded on server */
354
+ hydrationData?: {
355
+ loaderData?: Record<string, unknown>;
356
+ actionData?: Record<string, unknown>;
357
+ };
358
+ }
359
+ /**
360
+ * Memory router options
361
+ */
362
+ interface MemoryRouterOptions extends RouterOptions {
363
+ /** Initial entries in the history stack */
364
+ initialEntries?: string[];
365
+ /** Initial index in the history stack */
366
+ initialIndex?: number;
367
+ }
368
+ /**
369
+ * Hash router options
370
+ */
371
+ interface HashRouterOptions extends RouterOptions {
372
+ /** Hash type: "slash" for /#/path, "noslash" for /#path */
373
+ hashType?: 'slash' | 'noslash';
374
+ }
375
+
376
+ /**
377
+ * @fileoverview Router components for @fictjs/router
378
+ *
379
+ * This module provides the main Router, Routes, Route, and Outlet components.
380
+ * These integrate with Fict's reactive system for fine-grained updates.
381
+ */
382
+
383
+ interface BaseRouterProps {
384
+ children?: FictNode;
385
+ base?: string;
386
+ }
387
+ interface BrowserRouterProps extends BaseRouterProps, RouterOptions {
388
+ }
389
+ interface HashRouterProps extends BaseRouterProps, HashRouterOptions {
390
+ }
391
+ interface MemoryRouterProps extends BaseRouterProps, MemoryRouterOptions {
392
+ }
393
+ interface StaticRouterProps extends BaseRouterProps {
394
+ url: string;
395
+ }
396
+ /**
397
+ * Browser Router - uses the History API
398
+ */
399
+ declare function Router(props: BrowserRouterProps & {
400
+ children?: FictNode;
401
+ }): FictNode;
402
+ /**
403
+ * Hash Router - uses the URL hash
404
+ */
405
+ declare function HashRouter(props: HashRouterProps & {
406
+ children?: FictNode;
407
+ }): FictNode;
408
+ /**
409
+ * Memory Router - keeps history in memory (for testing/SSR)
410
+ */
411
+ declare function MemoryRouter(props: MemoryRouterProps & {
412
+ children?: FictNode;
413
+ }): FictNode;
414
+ /**
415
+ * Static Router - for server-side rendering
416
+ */
417
+ declare function StaticRouter(props: StaticRouterProps & {
418
+ children?: FictNode;
419
+ }): FictNode;
420
+ interface RoutesProps {
421
+ children?: FictNode;
422
+ }
423
+ /**
424
+ * Routes component - renders the matched route
425
+ */
426
+ declare function Routes(props: RoutesProps): FictNode;
427
+ interface RouteJSXProps {
428
+ path?: string | undefined;
429
+ component?: Component<any> | undefined;
430
+ element?: FictNode;
431
+ children?: FictNode;
432
+ index?: boolean | undefined;
433
+ key?: string | undefined;
434
+ preload?: ((args: {
435
+ params: Params;
436
+ location: Location;
437
+ intent: 'initial' | 'navigate' | 'native' | 'preload';
438
+ }) => unknown | Promise<unknown>) | undefined;
439
+ errorElement?: FictNode;
440
+ loadingElement?: FictNode;
441
+ }
442
+ /**
443
+ * Route component - defines a route
444
+ * This is a configuration component, it doesn't render anything directly.
445
+ */
446
+ declare function Route(_props: RouteJSXProps): FictNode;
447
+ /**
448
+ * Outlet component - renders the child route
449
+ */
450
+ declare function Outlet(): FictNode;
451
+ interface NavigateComponentProps {
452
+ to: To;
453
+ replace?: boolean;
454
+ state?: unknown;
455
+ }
456
+ /**
457
+ * Navigate component - declarative navigation
458
+ * Navigates immediately when rendered.
459
+ */
460
+ declare function Navigate(props: NavigateComponentProps): FictNode;
461
+ interface RedirectProps {
462
+ /** Target path to redirect to */
463
+ to: To;
464
+ /** Path pattern that triggers this redirect (optional, for declarative redirects) */
465
+ from?: string;
466
+ /** State to pass with the redirect */
467
+ state?: unknown;
468
+ /** Whether to replace or push to history (default: true) */
469
+ push?: boolean;
470
+ }
471
+ /**
472
+ * Redirect component - declarative redirect
473
+ *
474
+ * Unlike Navigate, Redirect is specifically for redirect scenarios:
475
+ * - Always replaces by default (unless push=true)
476
+ * - Can be used in route definitions with a `from` pattern
477
+ * - Semantically indicates a redirect rather than navigation
478
+ *
479
+ * @example
480
+ * ```tsx
481
+ * // Basic redirect (replaces current entry)
482
+ * <Redirect to="/login" />
483
+ *
484
+ * // Redirect with state
485
+ * <Redirect to="/login" state={{ from: location.pathname }} />
486
+ *
487
+ * // Push instead of replace
488
+ * <Redirect to="/new-page" push />
489
+ *
490
+ * // In route definitions (redirect old paths)
491
+ * <Route path="/old-path" element={<Redirect to="/new-path" />} />
492
+ * ```
493
+ */
494
+ declare function Redirect(props: RedirectProps): FictNode;
495
+ /**
496
+ * Create routes from a configuration array (alternative to JSX)
497
+ */
498
+ declare function createRoutes(routes: RouteDefinition[]): RouteDefinition[];
499
+ /**
500
+ * Create a router with programmatic routes
501
+ */
502
+ declare function createRouter(routes: RouteDefinition[], options?: RouterOptions): {
503
+ Router: Component<{
504
+ children?: FictNode;
505
+ }>;
506
+ };
507
+
508
+ /**
509
+ * @fileoverview Link components for @fictjs/router
510
+ *
511
+ * This module provides Link and NavLink components for declarative navigation.
512
+ * Integrates with Fict's reactive system for active state tracking.
513
+ */
514
+
515
+ type CSSProperties = StyleProp;
516
+ interface LinkProps extends Omit<JSX.IntrinsicElements['a'], 'href'> {
517
+ /** Navigation target */
518
+ to: To;
519
+ /** Replace history entry instead of pushing */
520
+ replace?: boolean;
521
+ /** State to pass with navigation */
522
+ state?: unknown;
523
+ /** Scroll to top after navigation */
524
+ scroll?: boolean;
525
+ /** Relative path resolution mode */
526
+ relative?: 'route' | 'path';
527
+ /** Force full page reload */
528
+ reloadDocument?: boolean;
529
+ /** Preload behavior */
530
+ prefetch?: 'none' | 'intent' | 'render';
531
+ /** Prevent navigation (render as text) */
532
+ disabled?: boolean;
533
+ /** Custom click handler (called before navigation) */
534
+ onClick?: (event: MouseEvent) => void;
535
+ children?: FictNode;
536
+ }
537
+ /**
538
+ * Link component for navigation
539
+ *
540
+ * @example
541
+ * ```tsx
542
+ * <Link to="/about">About</Link>
543
+ * <Link to="/users/123" replace>View User</Link>
544
+ * <Link to={{ pathname: "/search", search: "?q=test" }}>Search</Link>
545
+ * ```
546
+ */
547
+ declare function Link(props: LinkProps): FictNode;
548
+ interface NavLinkRenderProps {
549
+ /** Whether the link is active */
550
+ isActive: boolean;
551
+ /** Whether a navigation to this link is pending */
552
+ isPending: boolean;
553
+ /** Whether a view transition is in progress */
554
+ isTransitioning: boolean;
555
+ }
556
+ interface NavLinkProps extends Omit<LinkProps, 'className' | 'style' | 'children'> {
557
+ /** Class name - can be a function that receives render props */
558
+ className?: string | ((props: NavLinkRenderProps) => string | undefined);
559
+ /** Style - can be a function that receives render props */
560
+ style?: CSSProperties | ((props: NavLinkRenderProps) => CSSProperties | undefined);
561
+ /** Children - can be a function that receives render props */
562
+ children?: FictNode | ((props: NavLinkRenderProps) => FictNode);
563
+ /** Only match if path is exactly equal (not a prefix) */
564
+ end?: boolean;
565
+ /** Case-sensitive matching */
566
+ caseSensitive?: boolean;
567
+ /** Custom active class name */
568
+ activeClassName?: string;
569
+ /** Custom pending class name */
570
+ pendingClassName?: string;
571
+ /** Custom active style */
572
+ activeStyle?: CSSProperties;
573
+ /** Custom pending style */
574
+ pendingStyle?: CSSProperties;
575
+ /** aria-current value when active */
576
+ 'aria-current'?: 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false';
577
+ }
578
+ /**
579
+ * NavLink component for navigation with active state
580
+ *
581
+ * @example
582
+ * ```tsx
583
+ * <NavLink to="/about" activeClassName="active">About</NavLink>
584
+ *
585
+ * <NavLink to="/users" end>
586
+ * {({ isActive }) => (
587
+ * <span className={isActive ? 'active' : ''}>Users</span>
588
+ * )}
589
+ * </NavLink>
590
+ *
591
+ * <NavLink
592
+ * to="/dashboard"
593
+ * className={({ isActive }) => isActive ? 'nav-active' : 'nav-link'}
594
+ * >
595
+ * Dashboard
596
+ * </NavLink>
597
+ * ```
598
+ */
599
+ declare function NavLink(props: NavLinkProps): FictNode;
600
+ interface FormProps extends Omit<JSX.IntrinsicElements['form'], 'action' | 'method'> {
601
+ /** Form action URL */
602
+ action?: string;
603
+ /** HTTP method */
604
+ method?: 'get' | 'post' | 'put' | 'patch' | 'delete';
605
+ /** Replace history entry */
606
+ replace?: boolean;
607
+ /** Relative path resolution */
608
+ relative?: 'route' | 'path';
609
+ /** Prevent navigation */
610
+ preventScrollReset?: boolean;
611
+ /** Navigate on submit */
612
+ navigate?: boolean;
613
+ /** Fetch mode */
614
+ fetcherKey?: string;
615
+ children?: FictNode;
616
+ onSubmit?: (event: SubmitEvent) => void;
617
+ }
618
+ /**
619
+ * Form component for action submissions
620
+ *
621
+ * @example
622
+ * ```tsx
623
+ * <Form action="/api/submit" method="post">
624
+ * <input name="email" type="email" />
625
+ * <button type="submit">Submit</button>
626
+ * </Form>
627
+ * ```
628
+ */
629
+ declare function Form(props: FormProps): FictNode;
630
+
631
+ /**
632
+ * Use the router context
633
+ */
634
+ declare function useRouter(): RouterContextValue;
635
+ /**
636
+ * Use the route context
637
+ */
638
+ declare function useRoute(): RouteContextValue;
639
+ /**
640
+ * Get the navigate function
641
+ */
642
+ declare function useNavigate(): NavigateFunction;
643
+ /**
644
+ * Get the current location
645
+ */
646
+ declare function useLocation(): () => Location;
647
+ /**
648
+ * Get the current route parameters
649
+ */
650
+ declare function useParams<P extends string = string>(): () => Params<P>;
651
+ /**
652
+ * Get the current search parameters
653
+ */
654
+ declare function useSearchParams(): [
655
+ () => URLSearchParams,
656
+ (params: URLSearchParams | Record<string, string>, options?: {
657
+ replace?: boolean;
658
+ }) => void
659
+ ];
660
+ /**
661
+ * Get the current route matches
662
+ */
663
+ declare function useMatches(): () => RouteMatch[];
664
+ /**
665
+ * Check if currently routing (loading new route)
666
+ */
667
+ declare function useIsRouting(): () => boolean;
668
+ /**
669
+ * Get the pending navigation location (if any)
670
+ */
671
+ declare function usePendingLocation(): () => Location | null;
672
+ /**
673
+ * Get the preloaded data for the current route
674
+ */
675
+ declare function useRouteData<T = unknown>(): () => T | undefined;
676
+ /**
677
+ * Get route error (for use in errorElement components)
678
+ * This hook is used within an error boundary to access the caught error.
679
+ * It returns errors from both preload phase (via route context) and
680
+ * render phase (via ErrorBoundary context).
681
+ *
682
+ * @example
683
+ * ```tsx
684
+ * function RouteErrorPage() {
685
+ * const error = useRouteError()
686
+ * return (
687
+ * <div>
688
+ * <h1>Error</h1>
689
+ * <p>{error?.message || 'Unknown error'}</p>
690
+ * </div>
691
+ * )
692
+ * }
693
+ * ```
694
+ */
695
+ declare function useRouteError(): unknown;
696
+ /**
697
+ * Resolve a path relative to the current route
698
+ */
699
+ declare function useResolvedPath(to: To | (() => To)): () => string;
700
+ /**
701
+ * Check if a path matches the current location
702
+ */
703
+ declare function useMatch(path: string | (() => string)): () => RouteMatch | null;
704
+ /**
705
+ * Get the href for a given path (useful for SSR)
706
+ */
707
+ declare function useHref(to: To | (() => To)): () => string;
708
+ /**
709
+ * Check if a path is active (matches current location)
710
+ */
711
+ declare function useIsActive(to: To | (() => To), options?: {
712
+ end?: boolean | undefined;
713
+ }): () => boolean;
714
+ /**
715
+ * Register a beforeLeave handler for the current route
716
+ */
717
+ declare function useBeforeLeave(handler: BeforeLeaveHandler): void;
718
+
719
+ /**
720
+ * @fileoverview History implementations for @fictjs/router
721
+ *
722
+ * Provides browser history, hash history, and memory history implementations.
723
+ * These handle the low-level navigation state management.
724
+ */
725
+
726
+ /**
727
+ * Create a browser history instance that uses the History API.
728
+ * This is the standard history for most web applications.
729
+ *
730
+ * @throws Error if called in a non-browser environment (SSR)
731
+ */
732
+ declare function createBrowserHistory(): History;
733
+ /**
734
+ * Create a hash history instance that uses the URL hash.
735
+ * Useful for static file hosting or when you can't configure server-side routing.
736
+ *
737
+ * @throws Error if called in a non-browser environment (SSR)
738
+ */
739
+ declare function createHashHistory(options?: {
740
+ hashType?: 'slash' | 'noslash';
741
+ }): History;
742
+ /**
743
+ * Create a memory history instance that keeps history in memory.
744
+ * Useful for testing and server-side rendering.
745
+ */
746
+ declare function createMemoryHistory(options?: {
747
+ initialEntries?: string[];
748
+ initialIndex?: number;
749
+ }): History;
750
+ /**
751
+ * Create a static history for server-side rendering.
752
+ * This history doesn't support navigation and always returns the initial location.
753
+ */
754
+ declare function createStaticHistory(url: string): History;
755
+
756
+ /**
757
+ * @fileoverview Data loading utilities for @fictjs/router
758
+ *
759
+ * This module provides utilities for loading data in routes,
760
+ * including query caching, actions, and preloading.
761
+ */
762
+
763
+ /**
764
+ * Create a cached query function
765
+ *
766
+ * @example
767
+ * ```tsx
768
+ * const getUser = query(
769
+ * async (id: string) => {
770
+ * const response = await fetch(`/api/users/${id}`)
771
+ * return response.json()
772
+ * },
773
+ * 'getUser'
774
+ * )
775
+ *
776
+ * // In a component
777
+ * function UserProfile({ id }) {
778
+ * const user = getUser(id)
779
+ * return <div>{user()?.name}</div>
780
+ * }
781
+ * ```
782
+ */
783
+ declare function query<T, Args extends unknown[]>(fn: QueryFunction<T, Args>, name: string): (...args: Args) => () => T | undefined;
784
+ /**
785
+ * Invalidate cached queries by key pattern
786
+ */
787
+ declare function revalidate(keys?: string | string[] | RegExp): void;
788
+ /**
789
+ * Create an action for form submissions
790
+ *
791
+ * @example
792
+ * ```tsx
793
+ * const createUser = action(
794
+ * async (formData, { params }) => {
795
+ * const response = await fetch('/api/users', {
796
+ * method: 'POST',
797
+ * body: formData,
798
+ * })
799
+ * return response.json()
800
+ * },
801
+ * 'createUser'
802
+ * )
803
+ *
804
+ * // In a component
805
+ * <Form action={createUser}>
806
+ * <input name="name" />
807
+ * <button type="submit">Create</button>
808
+ * </Form>
809
+ * ```
810
+ */
811
+ declare function action<T>(fn: ActionFunction<T>, name?: string): Action<T>;
812
+ /**
813
+ * Get a registered action by URL
814
+ */
815
+ declare function getAction(url: string): ActionFunction<unknown> | undefined;
816
+ /**
817
+ * Use submission state for an action
818
+ */
819
+ declare function useSubmission<T>(actionOrUrl: Action<T> | string): () => Submission<T> | undefined;
820
+ /**
821
+ * Use all active submissions
822
+ */
823
+ declare function useSubmissions(): () => Submission<unknown>[];
824
+ /**
825
+ * Submit an action and track the submission
826
+ */
827
+ declare function submitAction<T>(action: Action<T>, formData: FormData, params?: Params): Promise<T>;
828
+ /**
829
+ * Preload a query for faster navigation
830
+ */
831
+ declare function preloadQuery<T, Args extends unknown[]>(queryFn: (...args: Args) => () => T | undefined, ...args: Args): void;
832
+ /**
833
+ * Create a preload function for a route
834
+ */
835
+ declare function createPreload<T>(fn: (args: {
836
+ params: Params;
837
+ intent: NavigationIntent;
838
+ }) => T | Promise<T>): (args: {
839
+ params: Params;
840
+ intent: NavigationIntent;
841
+ }) => Promise<T>;
842
+ /**
843
+ * Resource state
844
+ */
845
+ interface Resource<T> {
846
+ /** Get current data (undefined during loading or on error) */
847
+ (): T | undefined;
848
+ /** Whether the resource is currently loading */
849
+ loading: () => boolean;
850
+ /** Error if the fetch failed, undefined otherwise */
851
+ error: () => unknown;
852
+ /** Latest successfully loaded value (persists during reloads) */
853
+ latest: () => T | undefined;
854
+ /** Trigger a refetch, returns the result or undefined on error */
855
+ refetch: () => Promise<T | undefined>;
856
+ }
857
+ /**
858
+ * Create a resource for async data loading
859
+ * Integrates with Suspense for loading states
860
+ *
861
+ * @example
862
+ * ```tsx
863
+ * const userResource = createResource(
864
+ * () => userId,
865
+ * async (id) => fetch(`/api/users/${id}`).then(r => r.json())
866
+ * )
867
+ *
868
+ * function UserProfile() {
869
+ * const user = userResource()
870
+ * return <div>{user?.name}</div>
871
+ * }
872
+ * ```
873
+ */
874
+ declare function createResource<T, S = unknown>(source: () => S, fetcher: (source: S) => T | Promise<T>): Resource<T>;
875
+ /**
876
+ * Clean up router data utilities
877
+ */
878
+ declare function cleanupDataUtilities(): void;
879
+
880
+ /**
881
+ * @fileoverview Path matching and utility functions for @fictjs/router
882
+ *
883
+ * This module provides path parsing, matching, and scoring utilities.
884
+ * Based on patterns from Solid Router with optimizations for Fict.
885
+ */
886
+
887
+ /**
888
+ * Normalize a path by removing trailing slashes and ensuring leading slash
889
+ */
890
+ declare function normalizePath(path: string): string;
891
+ /**
892
+ * Join path segments together
893
+ */
894
+ declare function joinPaths(...paths: (string | undefined)[]): string;
895
+ /**
896
+ * Resolve a relative path against a base path
897
+ */
898
+ declare function resolvePath(base: string, to: To): string;
899
+ /**
900
+ * Create a Location object from a To value
901
+ */
902
+ declare function createLocation(to: To, state?: unknown, key?: string): Location;
903
+ /**
904
+ * Parse a URL string into its components
905
+ */
906
+ declare function parseURL(url: string): {
907
+ pathname: string;
908
+ search: string;
909
+ hash: string;
910
+ };
911
+ /**
912
+ * Create a URL string from a Location object
913
+ */
914
+ declare function createURL(location: Partial<Location>): string;
915
+ /**
916
+ * Calculate the score for a route pattern.
917
+ * Higher score = more specific route.
918
+ *
919
+ * Scoring:
920
+ * - Static segment: 3 points
921
+ * - Dynamic segment: 2 points
922
+ * - Optional segment: 1 point
923
+ * - Splat segment: 0.5 points
924
+ * - Index route bonus: 0.5 points
925
+ */
926
+ declare function scoreRoute(pattern: string, isIndex?: boolean): number;
927
+ /**
928
+ * Compile a route definition into a CompiledRoute
929
+ */
930
+ declare function compileRoute(route: RouteDefinition, parentPattern?: string): CompiledRoute;
931
+ /**
932
+ * Create branches from compiled routes for efficient matching.
933
+ * A branch represents a complete path from root to leaf.
934
+ */
935
+ declare function createBranches(routes: CompiledRoute[]): RouteBranch[];
936
+ /**
937
+ * Match a pathname against route branches
938
+ */
939
+ declare function matchRoutes(branches: RouteBranch[], pathname: string): RouteMatch[] | null;
940
+ /**
941
+ * Parse search params from a search string
942
+ */
943
+ declare function parseSearchParams(search: string): URLSearchParams;
944
+ /**
945
+ * Stringify search params to a search string
946
+ */
947
+ declare function stringifySearchParams(params: URLSearchParams | Record<string, string>): string;
948
+ /**
949
+ * Check if two locations are equal
950
+ */
951
+ declare function locationsAreEqual(a: Location, b: Location): boolean;
952
+ /**
953
+ * Strip the base path from a pathname
954
+ */
955
+ declare function stripBasePath(pathname: string, basePath: string): string;
956
+ /**
957
+ * Prepend the base path to a pathname
958
+ */
959
+ declare function prependBasePath(pathname: string, basePath: string): string;
960
+ /**
961
+ * Check if code is running on the server
962
+ */
963
+ declare function isServer(): boolean;
964
+ /**
965
+ * Check if code is running in the browser
966
+ */
967
+ declare function isBrowser(): boolean;
968
+
969
+ /**
970
+ * @fileoverview Scroll restoration utilities for @fictjs/router
971
+ *
972
+ * This module provides scroll position management including:
973
+ * - Saving scroll positions per location key
974
+ * - Restoring scroll on back/forward navigation
975
+ * - Scrolling to top on new navigation
976
+ * - Hash scrolling support (#section)
977
+ */
978
+
979
+ /**
980
+ * Save the current scroll position for a location
981
+ */
982
+ declare function saveScrollPosition(key: string): void;
983
+ /**
984
+ * Clear saved scroll position for a location
985
+ */
986
+ declare function clearScrollPosition(key: string): void;
987
+ /**
988
+ * Clear all saved scroll positions
989
+ */
990
+ declare function clearAllScrollPositions(): void;
991
+ /**
992
+ * Scroll to top of the page
993
+ */
994
+ declare function scrollToTop(behavior?: ScrollBehavior): void;
995
+ /**
996
+ * Scroll to an element by ID (hash navigation)
997
+ */
998
+ declare function scrollToHash(hash: string, behavior?: ScrollBehavior): boolean;
999
+ /**
1000
+ * Restore scroll position for a location
1001
+ * Returns true if position was restored
1002
+ */
1003
+ declare function restoreScrollPosition(key: string): boolean;
1004
+ interface ScrollRestorationOptions {
1005
+ /** Whether scroll restoration is enabled */
1006
+ enabled?: boolean;
1007
+ /** Whether to restore scroll on back/forward navigation */
1008
+ restoreOnPop?: boolean;
1009
+ /** Whether to scroll to top on push navigation */
1010
+ scrollToTopOnPush?: boolean;
1011
+ /** Default scroll behavior */
1012
+ behavior?: ScrollBehavior;
1013
+ }
1014
+ /**
1015
+ * Create a scroll restoration manager
1016
+ */
1017
+ declare function createScrollRestoration(options?: ScrollRestorationOptions): {
1018
+ handleNavigation: (from: Location | null, to: Location, action: "PUSH" | "REPLACE" | "POP") => void;
1019
+ saveScrollPosition: typeof saveScrollPosition;
1020
+ restoreScrollPosition: typeof restoreScrollPosition;
1021
+ scrollToTop: () => void;
1022
+ scrollToHash: (hash: string) => boolean;
1023
+ reset: () => void;
1024
+ config: {
1025
+ enabled: boolean;
1026
+ restoreOnPop: boolean;
1027
+ scrollToTopOnPush: boolean;
1028
+ behavior: ScrollBehavior;
1029
+ };
1030
+ };
1031
+ /**
1032
+ * Get or create the default scroll restoration instance
1033
+ */
1034
+ declare function getScrollRestoration(): ReturnType<typeof createScrollRestoration>;
1035
+ /**
1036
+ * Configure the default scroll restoration
1037
+ */
1038
+ declare function configureScrollRestoration(options: ScrollRestorationOptions): void;
1039
+
1040
+ /**
1041
+ * @fileoverview Lazy loading utilities for @fictjs/router
1042
+ *
1043
+ * This module provides code splitting support via lazy loading of route components.
1044
+ * Works with Fict's Suspense for loading states.
1045
+ */
1046
+
1047
+ /**
1048
+ * Create a lazy-loaded component
1049
+ *
1050
+ * @example
1051
+ * ```tsx
1052
+ * // Create a lazy component
1053
+ * const LazyUserProfile = lazy(() => import('./pages/UserProfile'))
1054
+ *
1055
+ * // Use in routes
1056
+ * <Route path="/users/:id" component={LazyUserProfile} />
1057
+ *
1058
+ * // Or with Suspense fallback
1059
+ * <Suspense fallback={<Loading />}>
1060
+ * <LazyUserProfile />
1061
+ * </Suspense>
1062
+ * ```
1063
+ */
1064
+ declare function lazy<T extends Component<any>>(loader: () => Promise<{
1065
+ default: T;
1066
+ } | T>): Component<any>;
1067
+ /**
1068
+ * Preload a lazy component
1069
+ * Useful for preloading on hover/focus
1070
+ */
1071
+ declare function preloadLazy(component: Component<any>): Promise<void>;
1072
+ /**
1073
+ * Check if a component is a lazy component
1074
+ */
1075
+ declare function isLazyComponent(component: unknown): boolean;
1076
+ /**
1077
+ * Create a lazy route definition
1078
+ *
1079
+ * @example
1080
+ * ```tsx
1081
+ * const routes = [
1082
+ * lazyRoute({
1083
+ * path: '/users/:id',
1084
+ * component: () => import('./pages/UserProfile'),
1085
+ * }),
1086
+ * lazyRoute({
1087
+ * path: '/settings',
1088
+ * component: () => import('./pages/Settings'),
1089
+ * loadingElement: <Loading />,
1090
+ * errorElement: <Error />,
1091
+ * }),
1092
+ * ]
1093
+ * ```
1094
+ */
1095
+ declare function lazyRoute<P extends string = string>(config: {
1096
+ path?: string;
1097
+ component: () => Promise<{
1098
+ default: Component<RouteComponentProps<P>>;
1099
+ } | Component<RouteComponentProps<P>>>;
1100
+ loadingElement?: FictNode;
1101
+ errorElement?: FictNode;
1102
+ preload?: RouteDefinition<P>['preload'];
1103
+ children?: RouteDefinition[];
1104
+ index?: boolean;
1105
+ key?: string;
1106
+ }): RouteDefinition<P>;
1107
+ /**
1108
+ * Create multiple lazy routes from a glob import pattern
1109
+ * Useful for file-system based routing
1110
+ *
1111
+ * @example
1112
+ * ```tsx
1113
+ * // In a Vite project
1114
+ * const pages = import.meta.glob('./pages/*.tsx')
1115
+ *
1116
+ * const routes = createLazyRoutes(pages, {
1117
+ * // Map file path to route path
1118
+ * pathTransform: (filePath) => {
1119
+ * // ./pages/UserProfile.tsx -> /user-profile
1120
+ * return filePath
1121
+ * .replace('./pages/', '/')
1122
+ * .replace('.tsx', '')
1123
+ * .toLowerCase()
1124
+ * .replace(/([A-Z])/g, '-$1')
1125
+ * },
1126
+ * })
1127
+ * ```
1128
+ */
1129
+ declare function createLazyRoutes(modules: Record<string, () => Promise<{
1130
+ default: Component<any>;
1131
+ }>>, options?: {
1132
+ pathTransform?: (filePath: string) => string;
1133
+ loadingElement?: FictNode;
1134
+ errorElement?: FictNode;
1135
+ }): RouteDefinition[];
1136
+
1137
+ export { type Action, type ActionFunction, type BeforeLeaveEventArgs, type BeforeLeaveHandler, type Blocker, type CompiledRoute, Form, type FormProps, HashRouter, type HashRouterOptions, type History, type HistoryAction, type HistoryListener, Link, type LinkProps, type Location, type MatchFilter, type MatchFilters, MemoryRouter, type MemoryRouterOptions, NavLink, type NavLinkProps, type NavLinkRenderProps, Navigate, type NavigateFunction, type NavigateOptions, type Navigation, type NavigationIntent, Outlet, type Params, type PreloadArgs, type PreloadFunction, type QueryCacheEntry, type QueryFunction, Redirect, type Resource, Route, type RouteBranch, type RouteComponentProps, type RouteContextValue, type RouteDefinition, type RouteMatch, type RouteProps, Router, type RouterContextValue, type RouterOptions, Routes, type ScrollRestorationOptions, type SearchParams, StaticRouter, type Submission, type To, action, cleanupDataUtilities, clearAllScrollPositions, clearScrollPosition, compileRoute, configureScrollRestoration, createBranches, createBrowserHistory, createHashHistory, createLazyRoutes, createLocation, createMemoryHistory, createPreload, createResource, createRouter, createRoutes, createScrollRestoration, createStaticHistory, createURL, getAction, getScrollRestoration, isBrowser, isLazyComponent, isServer, joinPaths, lazy, lazyRoute, locationsAreEqual, matchRoutes, normalizePath, parseSearchParams, parseURL, preloadLazy, preloadQuery, prependBasePath, query, resolvePath, restoreScrollPosition, revalidate, saveScrollPosition, scoreRoute, scrollToHash, scrollToTop, stringifySearchParams, stripBasePath, submitAction, useBeforeLeave, useHref, useIsActive, useIsRouting, useLocation, useMatch, useMatches, useNavigate, useParams, usePendingLocation, useResolvedPath, useRoute, useRouteData, useRouteError, useRouter, useSearchParams, useSubmission, useSubmissions };