@funstack/router 0.0.10 → 1.1.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/bin/skill-installer.mjs +2 -3
- package/dist/bin/skill-installer.mjs.map +1 -1
- package/dist/{route-p_gr5yPI.mjs → bindRoute-CQ2-ruTp.mjs} +11 -3
- package/dist/bindRoute-CQ2-ruTp.mjs.map +1 -0
- package/dist/{route-DRcgs0Pt.d.mts → bindRoute-DulMzi5X.d.mts} +169 -12
- package/dist/bindRoute-DulMzi5X.d.mts.map +1 -0
- package/dist/docs/ApiHooksPage.tsx +9 -22
- package/dist/docs/ApiTypesPage.tsx +17 -0
- package/dist/docs/ApiUtilitiesPage.tsx +62 -3
- package/dist/docs/ExamplesPage.tsx +3 -5
- package/dist/docs/FaqPage.tsx +84 -0
- package/dist/docs/GettingStartedPage.tsx +6 -3
- package/dist/docs/LearnActionsPage.tsx +228 -0
- package/dist/docs/LearnLoadersPage.tsx +320 -0
- package/dist/docs/LearnNavigationApiPage.tsx +1 -1
- package/dist/docs/LearnRouteDefinitionsPage.tsx +285 -0
- package/dist/docs/LearnRscPage.tsx +6 -0
- package/dist/docs/LearnSsgPage.tsx +3 -5
- package/dist/docs/index.md +4 -0
- package/dist/index.d.mts +36 -11
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +108 -71
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +2 -2
- package/dist/server.mjs +2 -3
- package/package.json +6 -5
- package/skills/funstack-router-knowledge/SKILL.md +1 -1
- package/dist/route-DRcgs0Pt.d.mts.map +0 -1
- package/dist/route-p_gr5yPI.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore, useTransition } from "react";
|
|
2
|
+
import { n as route, r as routeState, t as bindRoute } from "./bindRoute-CQ2-ruTp.mjs";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useEffectEvent, useId, useMemo, useRef, useState, useSyncExternalStore, useTransition } from "react";
|
|
5
4
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
-
|
|
7
5
|
//#region src/context/RouterContext.ts
|
|
8
6
|
const RouterContext = createContext(null);
|
|
9
|
-
|
|
10
7
|
//#endregion
|
|
11
8
|
//#region src/context/BlockerContext.ts
|
|
12
9
|
/**
|
|
@@ -29,7 +26,6 @@ function createBlockerRegistry() {
|
|
|
29
26
|
};
|
|
30
27
|
}
|
|
31
28
|
const BlockerContext = createContext(null);
|
|
32
|
-
|
|
33
29
|
//#endregion
|
|
34
30
|
//#region src/types.ts
|
|
35
31
|
/**
|
|
@@ -42,7 +38,6 @@ const BlockerContext = createContext(null);
|
|
|
42
38
|
function internalRoutes(routes) {
|
|
43
39
|
return routes;
|
|
44
40
|
}
|
|
45
|
-
|
|
46
41
|
//#endregion
|
|
47
42
|
//#region src/core/matchRoutes.ts
|
|
48
43
|
const SKIPPED = Symbol("skipped");
|
|
@@ -167,10 +162,42 @@ function matchPath(pattern, pathname, exact) {
|
|
|
167
162
|
consumedPathname
|
|
168
163
|
};
|
|
169
164
|
}
|
|
170
|
-
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/bypassInterception.ts
|
|
167
|
+
const bypassInterceptionSymbol = Symbol("bypassInterception");
|
|
168
|
+
/**
|
|
169
|
+
* Check if the given info is a bypass interception marker.
|
|
170
|
+
*/
|
|
171
|
+
function isBypassInterception(info) {
|
|
172
|
+
return info === bypassInterceptionSymbol;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Perform a full page reload, bypassing the router's interception.
|
|
176
|
+
*/
|
|
177
|
+
function hardReload() {
|
|
178
|
+
navigation.reload({ info: bypassInterceptionSymbol });
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Navigate to the given URL with a full page navigation,
|
|
182
|
+
* bypassing the router's interception.
|
|
183
|
+
*/
|
|
184
|
+
function hardNavigate(url) {
|
|
185
|
+
navigation.navigate(url, { info: bypassInterceptionSymbol });
|
|
186
|
+
}
|
|
171
187
|
//#endregion
|
|
172
188
|
//#region src/core/loaderCache.ts
|
|
173
189
|
/**
|
|
190
|
+
* Wrapper for synchronous errors thrown by loaders.
|
|
191
|
+
* Cached instead of the raw error so the Router's useMemo doesn't throw.
|
|
192
|
+
* RouteRenderer checks for this class and re-throws the original error
|
|
193
|
+
* during rendering, where Error Boundaries can catch it.
|
|
194
|
+
*/
|
|
195
|
+
var LoaderError = class {
|
|
196
|
+
constructor(error) {
|
|
197
|
+
this.error = error;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
174
201
|
* Cache for loader results.
|
|
175
202
|
* Key format: `${entryId}:${matchIndex}`
|
|
176
203
|
*/
|
|
@@ -182,7 +209,11 @@ const loaderCache = /* @__PURE__ */ new Map();
|
|
|
182
209
|
function getOrCreateLoaderResult(entryId, matchIndex, route, args) {
|
|
183
210
|
if (!route.loader) return;
|
|
184
211
|
const cacheKey = `${entryId}:${matchIndex}`;
|
|
185
|
-
if (!loaderCache.has(cacheKey))
|
|
212
|
+
if (!loaderCache.has(cacheKey)) try {
|
|
213
|
+
loaderCache.set(cacheKey, route.loader(args));
|
|
214
|
+
} catch (error) {
|
|
215
|
+
loaderCache.set(cacheKey, new LoaderError(error));
|
|
216
|
+
}
|
|
186
217
|
return loaderCache.get(cacheKey);
|
|
187
218
|
}
|
|
188
219
|
/**
|
|
@@ -227,7 +258,6 @@ function clearLoaderCacheForEntry(entryId) {
|
|
|
227
258
|
const prefix = `${entryId}:`;
|
|
228
259
|
for (const key of loaderCache.keys()) if (key.startsWith(prefix)) loaderCache.delete(key);
|
|
229
260
|
}
|
|
230
|
-
|
|
231
261
|
//#endregion
|
|
232
262
|
//#region src/core/NavigationAPIAdapter.ts
|
|
233
263
|
/**
|
|
@@ -244,6 +274,7 @@ var NavigationAPIAdapter = class {
|
|
|
244
274
|
#cachedSnapshot = null;
|
|
245
275
|
#cachedEntryId = null;
|
|
246
276
|
#currentNavigationInfo = void 0;
|
|
277
|
+
#reloadCounts = /* @__PURE__ */ new Map();
|
|
247
278
|
getSnapshot() {
|
|
248
279
|
const entry = navigation.currentEntry;
|
|
249
280
|
if (!entry?.url) return null;
|
|
@@ -251,7 +282,9 @@ var NavigationAPIAdapter = class {
|
|
|
251
282
|
this.#cachedEntryId = entry.id;
|
|
252
283
|
this.#cachedSnapshot = {
|
|
253
284
|
url: new URL(entry.url),
|
|
254
|
-
key: entry.id,
|
|
285
|
+
key: this.#effectiveKey(entry.id),
|
|
286
|
+
entryId: entry.id,
|
|
287
|
+
entryKey: entry.key,
|
|
255
288
|
state: entry.getState(),
|
|
256
289
|
info: this.#currentNavigationInfo
|
|
257
290
|
};
|
|
@@ -284,9 +317,19 @@ var NavigationAPIAdapter = class {
|
|
|
284
317
|
entry.addEventListener("dispose", () => {
|
|
285
318
|
clearLoaderCacheForEntry(entryId);
|
|
286
319
|
this.#subscribedEntryIds.delete(entryId);
|
|
320
|
+
this.#reloadCounts.delete(entryId);
|
|
287
321
|
}, { signal });
|
|
288
322
|
}
|
|
289
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Compute the effective cache key for a given entry.
|
|
326
|
+
* Includes a reload suffix when the entry has been reloaded,
|
|
327
|
+
* so loaders get a fresh cache key and re-execute.
|
|
328
|
+
*/
|
|
329
|
+
#effectiveKey(entryId) {
|
|
330
|
+
const count = this.#reloadCounts.get(entryId) ?? 0;
|
|
331
|
+
return count > 0 ? `${entryId}:r${count}` : entryId;
|
|
332
|
+
}
|
|
290
333
|
navigate(to, options) {
|
|
291
334
|
navigation.navigate(to, {
|
|
292
335
|
history: options?.replace ? "replace" : "push",
|
|
@@ -301,8 +344,16 @@ var NavigationAPIAdapter = class {
|
|
|
301
344
|
info: options?.info
|
|
302
345
|
}).finished;
|
|
303
346
|
}
|
|
304
|
-
setupInterception(
|
|
347
|
+
setupInterception(getRoutes, onNavigate, checkBlockers) {
|
|
305
348
|
const handleNavigate = (event) => {
|
|
349
|
+
if (isBypassInterception(event.info)) {
|
|
350
|
+
onNavigate?.(event, {
|
|
351
|
+
matches: [],
|
|
352
|
+
intercepting: false,
|
|
353
|
+
formData: event.formData
|
|
354
|
+
});
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
306
357
|
this.#currentNavigationInfo = event.info;
|
|
307
358
|
this.#cachedSnapshot = null;
|
|
308
359
|
if (checkBlockers?.()) {
|
|
@@ -318,7 +369,7 @@ var NavigationAPIAdapter = class {
|
|
|
318
369
|
return;
|
|
319
370
|
}
|
|
320
371
|
const url = new URL(event.destination.url);
|
|
321
|
-
const matched = matchRoutes(
|
|
372
|
+
const matched = matchRoutes(getRoutes(), url.pathname);
|
|
322
373
|
const isFormSubmission = event.formData !== null;
|
|
323
374
|
if (isFormSubmission && matched !== null) {
|
|
324
375
|
if (!matched.some((m) => m.route.action)) {
|
|
@@ -340,6 +391,13 @@ var NavigationAPIAdapter = class {
|
|
|
340
391
|
if (event.defaultPrevented) return;
|
|
341
392
|
}
|
|
342
393
|
if (!willIntercept) return;
|
|
394
|
+
if (event.navigationType === "reload") {
|
|
395
|
+
const entryId = navigation.currentEntry.id;
|
|
396
|
+
const oldCount = this.#reloadCounts.get(entryId) ?? 0;
|
|
397
|
+
if (oldCount >= 2) clearLoaderCacheForEntry(`${entryId}:r${oldCount - 1}`);
|
|
398
|
+
this.#reloadCounts.set(entryId, oldCount + 1);
|
|
399
|
+
this.#cachedSnapshot = null;
|
|
400
|
+
}
|
|
343
401
|
if (idleController) {
|
|
344
402
|
idleController.abort();
|
|
345
403
|
idleController = null;
|
|
@@ -347,6 +405,7 @@ var NavigationAPIAdapter = class {
|
|
|
347
405
|
event.intercept({ handler: async () => {
|
|
348
406
|
const currentEntry = navigation.currentEntry;
|
|
349
407
|
if (!currentEntry) throw new Error("Navigation currentEntry is null during navigation interception");
|
|
408
|
+
const effectiveKey = this.#effectiveKey(currentEntry.id);
|
|
350
409
|
let actionResult = void 0;
|
|
351
410
|
if (isFormSubmission) {
|
|
352
411
|
const actionRoute = findActionRoute(matched);
|
|
@@ -360,8 +419,7 @@ var NavigationAPIAdapter = class {
|
|
|
360
419
|
}
|
|
361
420
|
clearLoaderCacheForEntry(currentEntry.id);
|
|
362
421
|
}
|
|
363
|
-
const
|
|
364
|
-
const results = executeLoaders(matched, currentEntry.id, request, event.signal, actionResult);
|
|
422
|
+
const results = executeLoaders(matched, effectiveKey, createLoaderRequest(url), event.signal, actionResult);
|
|
365
423
|
await Promise.all(results.map((r) => r.data));
|
|
366
424
|
} });
|
|
367
425
|
};
|
|
@@ -387,7 +445,6 @@ var NavigationAPIAdapter = class {
|
|
|
387
445
|
function findActionRoute(matched) {
|
|
388
446
|
for (let i = matched.length - 1; i >= 0; i--) if (matched[i].route.action) return matched[i];
|
|
389
447
|
}
|
|
390
|
-
|
|
391
448
|
//#endregion
|
|
392
449
|
//#region src/core/StaticAdapter.ts
|
|
393
450
|
/**
|
|
@@ -403,6 +460,8 @@ var StaticAdapter = class {
|
|
|
403
460
|
if (!this.#cachedSnapshot) this.#cachedSnapshot = {
|
|
404
461
|
url: new URL(window.location.href),
|
|
405
462
|
key: "__static__",
|
|
463
|
+
entryId: null,
|
|
464
|
+
entryKey: null,
|
|
406
465
|
state: void 0,
|
|
407
466
|
info: void 0
|
|
408
467
|
};
|
|
@@ -417,14 +476,13 @@ var StaticAdapter = class {
|
|
|
417
476
|
async navigateAsync(to, options) {
|
|
418
477
|
this.navigate(to, options);
|
|
419
478
|
}
|
|
420
|
-
setupInterception(
|
|
479
|
+
setupInterception(_getRoutes, _onNavigate, _checkBlockers) {}
|
|
421
480
|
getIdleAbortSignal() {
|
|
422
481
|
this.#idleController ??= new AbortController();
|
|
423
482
|
return this.#idleController.signal;
|
|
424
483
|
}
|
|
425
484
|
updateCurrentEntryState(_state) {}
|
|
426
485
|
};
|
|
427
|
-
|
|
428
486
|
//#endregion
|
|
429
487
|
//#region src/core/NullAdapter.ts
|
|
430
488
|
/**
|
|
@@ -445,14 +503,13 @@ var NullAdapter = class {
|
|
|
445
503
|
async navigateAsync(to, options) {
|
|
446
504
|
this.navigate(to, options);
|
|
447
505
|
}
|
|
448
|
-
setupInterception(
|
|
506
|
+
setupInterception(_getRoutes, _onNavigate, _checkBlockers) {}
|
|
449
507
|
getIdleAbortSignal() {
|
|
450
508
|
this.#idleController ??= new AbortController();
|
|
451
509
|
return this.#idleController.signal;
|
|
452
510
|
}
|
|
453
511
|
updateCurrentEntryState(_state) {}
|
|
454
512
|
};
|
|
455
|
-
|
|
456
513
|
//#endregion
|
|
457
514
|
//#region src/core/createAdapter.ts
|
|
458
515
|
/**
|
|
@@ -473,7 +530,6 @@ function createAdapter(fallback) {
|
|
|
473
530
|
if (fallback === "static") return new StaticAdapter();
|
|
474
531
|
return new NullAdapter();
|
|
475
532
|
}
|
|
476
|
-
|
|
477
533
|
//#endregion
|
|
478
534
|
//#region src/Router/ServerLocationSnapshot.ts
|
|
479
535
|
/**
|
|
@@ -489,7 +545,6 @@ function isServerSnapshot(value) {
|
|
|
489
545
|
return value instanceof ServerLocationSnapshot;
|
|
490
546
|
}
|
|
491
547
|
const noopSubscribe = () => () => {};
|
|
492
|
-
|
|
493
548
|
//#endregion
|
|
494
549
|
//#region src/context/RouteContext.ts
|
|
495
550
|
const RouteContext = createContext(null);
|
|
@@ -505,7 +560,6 @@ function findRouteContextById(context, id) {
|
|
|
505
560
|
}
|
|
506
561
|
return null;
|
|
507
562
|
}
|
|
508
|
-
|
|
509
563
|
//#endregion
|
|
510
564
|
//#region src/Router/useRouteStateCallbacks.ts
|
|
511
565
|
function useRouteStateCallbacks(index, internalState, url, navigateAsync, updateCurrentEntryState) {
|
|
@@ -567,7 +621,6 @@ function useRouteStateCallbacks(index, internalState, url, navigateAsync, update
|
|
|
567
621
|
resetStateSync
|
|
568
622
|
};
|
|
569
623
|
}
|
|
570
|
-
|
|
571
624
|
//#endregion
|
|
572
625
|
//#region src/Router/RouteRenderer.tsx
|
|
573
626
|
/**
|
|
@@ -575,12 +628,11 @@ function useRouteStateCallbacks(index, internalState, url, navigateAsync, update
|
|
|
575
628
|
*/
|
|
576
629
|
function RouteRenderer({ matchedRoutes, index }) {
|
|
577
630
|
const parentRouteContext = useContext(RouteContext);
|
|
578
|
-
const match = matchedRoutes[index];
|
|
579
|
-
if (!match) return null;
|
|
580
|
-
const { route, params, pathname, data } = match;
|
|
581
631
|
const routerContext = useContext(RouterContext);
|
|
582
632
|
if (!routerContext) throw new Error("RouteRenderer must be used within RouterContext");
|
|
583
633
|
const { locationState, locationInfo, url, isPending, navigateAsync, updateCurrentEntryState } = routerContext;
|
|
634
|
+
const match = matchedRoutes[index];
|
|
635
|
+
const { route, params, pathname, data } = match ?? {};
|
|
584
636
|
const internalState = locationState;
|
|
585
637
|
const routeState = internalState?.__routeStates?.[index];
|
|
586
638
|
const { setState, setStateSync, resetState, resetStateSync } = useRouteStateCallbacks(index, internalState, url, navigateAsync, updateCurrentEntryState);
|
|
@@ -588,11 +640,11 @@ function RouteRenderer({ matchedRoutes, index }) {
|
|
|
588
640
|
matchedRoutes,
|
|
589
641
|
index: index + 1
|
|
590
642
|
}) : null, [matchedRoutes, index]);
|
|
591
|
-
const routeId = route
|
|
643
|
+
const routeId = route?.id;
|
|
592
644
|
const routeContextValue = useMemo(() => ({
|
|
593
645
|
id: routeId,
|
|
594
|
-
params,
|
|
595
|
-
matchedPath: pathname,
|
|
646
|
+
params: params ?? {},
|
|
647
|
+
matchedPath: pathname ?? "",
|
|
596
648
|
state: routeState,
|
|
597
649
|
data,
|
|
598
650
|
outlet,
|
|
@@ -606,6 +658,7 @@ function RouteRenderer({ matchedRoutes, index }) {
|
|
|
606
658
|
outlet,
|
|
607
659
|
parentRouteContext
|
|
608
660
|
]);
|
|
661
|
+
if (!match) return null;
|
|
609
662
|
const renderComponent = () => {
|
|
610
663
|
const componentOrElement = route.component;
|
|
611
664
|
if (componentOrElement == null) return outlet;
|
|
@@ -619,6 +672,7 @@ function RouteRenderer({ matchedRoutes, index }) {
|
|
|
619
672
|
resetStateSync
|
|
620
673
|
};
|
|
621
674
|
const info = locationInfo;
|
|
675
|
+
if (data instanceof LoaderError) throw data.error;
|
|
622
676
|
if (route.loader) return /* @__PURE__ */ jsx(Component, {
|
|
623
677
|
data,
|
|
624
678
|
params,
|
|
@@ -638,7 +692,6 @@ function RouteRenderer({ matchedRoutes, index }) {
|
|
|
638
692
|
children: renderComponent()
|
|
639
693
|
});
|
|
640
694
|
}
|
|
641
|
-
|
|
642
695
|
//#endregion
|
|
643
696
|
//#region src/Router/index.tsx
|
|
644
697
|
function Router({ routes: inputRoutes, onNavigate, fallback = "none", ssr }) {
|
|
@@ -662,17 +715,11 @@ function Router({ routes: inputRoutes, onNavigate, fallback = "none", ssr }) {
|
|
|
662
715
|
else setLocationEntry(adapter.getSnapshot());
|
|
663
716
|
});
|
|
664
717
|
}, [adapter, startTransition]);
|
|
718
|
+
const getRoutes = useEffectEvent(() => routes);
|
|
719
|
+
const handleNavigate = useEffectEvent((...args) => onNavigate?.(...args));
|
|
665
720
|
useEffect(() => {
|
|
666
|
-
return adapter.setupInterception(
|
|
667
|
-
}, [
|
|
668
|
-
adapter,
|
|
669
|
-
routes,
|
|
670
|
-
onNavigate,
|
|
671
|
-
blockerRegistry
|
|
672
|
-
]);
|
|
673
|
-
const navigate = useCallback((to, options) => {
|
|
674
|
-
adapter.navigate(to, options);
|
|
675
|
-
}, [adapter]);
|
|
721
|
+
return adapter.setupInterception(getRoutes, handleNavigate, blockerRegistry.checkAll);
|
|
722
|
+
}, [adapter, blockerRegistry]);
|
|
676
723
|
const navigateAsync = useCallback((to, options) => {
|
|
677
724
|
return adapter.navigateAsync(to, options);
|
|
678
725
|
}, [adapter]);
|
|
@@ -724,20 +771,24 @@ function Router({ routes: inputRoutes, onNavigate, fallback = "none", ssr }) {
|
|
|
724
771
|
]);
|
|
725
772
|
const locationState = locationEntry?.state;
|
|
726
773
|
const locationInfo = locationEntry?.info;
|
|
774
|
+
const entryId = locationEntry?.entryId ?? (isServerSnapshot(locationEntryInternal) ? locationEntryInternal.actualLocationEntry?.entryId : null) ?? null;
|
|
775
|
+
const entryKey = locationEntry?.entryKey ?? (isServerSnapshot(locationEntryInternal) ? locationEntryInternal.actualLocationEntry?.entryKey : null) ?? null;
|
|
727
776
|
const routerContextValue = useMemo(() => ({
|
|
728
777
|
locationState,
|
|
729
778
|
locationInfo,
|
|
730
779
|
url: urlObject,
|
|
780
|
+
entryId,
|
|
781
|
+
entryKey,
|
|
731
782
|
isPending,
|
|
732
|
-
navigate,
|
|
733
783
|
navigateAsync,
|
|
734
784
|
updateCurrentEntryState
|
|
735
785
|
}), [
|
|
736
786
|
locationState,
|
|
737
787
|
locationInfo,
|
|
738
788
|
urlObject,
|
|
789
|
+
entryId,
|
|
790
|
+
entryKey,
|
|
739
791
|
isPending,
|
|
740
|
-
navigate,
|
|
741
792
|
navigateAsync,
|
|
742
793
|
updateCurrentEntryState
|
|
743
794
|
]);
|
|
@@ -759,7 +810,6 @@ function Router({ routes: inputRoutes, onNavigate, fallback = "none", ssr }) {
|
|
|
759
810
|
blockerRegistry
|
|
760
811
|
]);
|
|
761
812
|
}
|
|
762
|
-
|
|
763
813
|
//#endregion
|
|
764
814
|
//#region src/Outlet.tsx
|
|
765
815
|
/**
|
|
@@ -771,18 +821,6 @@ function Outlet() {
|
|
|
771
821
|
if (!routeContext) return null;
|
|
772
822
|
return routeContext.outlet;
|
|
773
823
|
}
|
|
774
|
-
|
|
775
|
-
//#endregion
|
|
776
|
-
//#region src/hooks/useNavigate.ts
|
|
777
|
-
/**
|
|
778
|
-
* Returns a function for programmatic navigation.
|
|
779
|
-
*/
|
|
780
|
-
function useNavigate() {
|
|
781
|
-
const context = useContext(RouterContext);
|
|
782
|
-
if (!context) throw new Error("useNavigate must be used within a Router");
|
|
783
|
-
return context.navigate;
|
|
784
|
-
}
|
|
785
|
-
|
|
786
824
|
//#endregion
|
|
787
825
|
//#region src/hooks/useLocation.ts
|
|
788
826
|
/**
|
|
@@ -791,17 +829,22 @@ function useNavigate() {
|
|
|
791
829
|
function useLocation() {
|
|
792
830
|
const context = useContext(RouterContext);
|
|
793
831
|
if (!context) throw new Error("useLocation must be used within a Router");
|
|
794
|
-
const { url } = context;
|
|
832
|
+
const { url, entryId, entryKey } = context;
|
|
795
833
|
if (url === null) throw new Error("useLocation: URL is not available during SSR.");
|
|
796
834
|
return useMemo(() => {
|
|
797
835
|
return {
|
|
798
836
|
pathname: url.pathname,
|
|
799
837
|
search: url.search,
|
|
800
|
-
hash: url.hash
|
|
838
|
+
hash: url.hash,
|
|
839
|
+
entryId,
|
|
840
|
+
entryKey
|
|
801
841
|
};
|
|
802
|
-
}, [
|
|
842
|
+
}, [
|
|
843
|
+
url,
|
|
844
|
+
entryId,
|
|
845
|
+
entryKey
|
|
846
|
+
]);
|
|
803
847
|
}
|
|
804
|
-
|
|
805
848
|
//#endregion
|
|
806
849
|
//#region src/hooks/useSearchParams.ts
|
|
807
850
|
/**
|
|
@@ -812,7 +855,7 @@ function useSearchParams() {
|
|
|
812
855
|
if (!context) throw new Error("useSearchParams must be used within a Router");
|
|
813
856
|
if (context.url === null) throw new Error("useSearchParams: URL is not available during SSR.");
|
|
814
857
|
const currentUrl = context.url;
|
|
815
|
-
const {
|
|
858
|
+
const { navigateAsync } = context;
|
|
816
859
|
return [currentUrl.searchParams, useCallback((params) => {
|
|
817
860
|
const url = new URL(currentUrl);
|
|
818
861
|
let newParams;
|
|
@@ -822,10 +865,9 @@ function useSearchParams() {
|
|
|
822
865
|
} else if (params instanceof URLSearchParams) newParams = params;
|
|
823
866
|
else newParams = new URLSearchParams(params);
|
|
824
867
|
url.search = newParams.toString();
|
|
825
|
-
|
|
826
|
-
}, [currentUrl,
|
|
868
|
+
navigateAsync(url.pathname + url.search + url.hash, { replace: true });
|
|
869
|
+
}, [currentUrl, navigateAsync])];
|
|
827
870
|
}
|
|
828
|
-
|
|
829
871
|
//#endregion
|
|
830
872
|
//#region src/hooks/useBlocker.ts
|
|
831
873
|
/**
|
|
@@ -869,7 +911,6 @@ function useBlocker(options) {
|
|
|
869
911
|
registry
|
|
870
912
|
]);
|
|
871
913
|
}
|
|
872
|
-
|
|
873
914
|
//#endregion
|
|
874
915
|
//#region src/hooks/useRouteContext.ts
|
|
875
916
|
/**
|
|
@@ -891,7 +932,6 @@ function useRouteContext(hookName, routeId) {
|
|
|
891
932
|
if (!matchedContext) throw new Error(`${hookName}: Route ID "${routeId}" not found in current route hierarchy. Current route is "${context.id ?? "(no id)"}"`);
|
|
892
933
|
return matchedContext;
|
|
893
934
|
}
|
|
894
|
-
|
|
895
935
|
//#endregion
|
|
896
936
|
//#region src/hooks/useRouteParams.ts
|
|
897
937
|
/**
|
|
@@ -918,7 +958,6 @@ function useRouteParams(route) {
|
|
|
918
958
|
const routeId = route.id;
|
|
919
959
|
return useRouteContext("useRouteParams", routeId).params;
|
|
920
960
|
}
|
|
921
|
-
|
|
922
961
|
//#endregion
|
|
923
962
|
//#region src/hooks/useRouteState.ts
|
|
924
963
|
/**
|
|
@@ -946,7 +985,6 @@ function useRouteState(route) {
|
|
|
946
985
|
const routeId = route.id;
|
|
947
986
|
return useRouteContext("useRouteState", routeId).state;
|
|
948
987
|
}
|
|
949
|
-
|
|
950
988
|
//#endregion
|
|
951
989
|
//#region src/hooks/useRouteData.ts
|
|
952
990
|
/**
|
|
@@ -977,7 +1015,6 @@ function useRouteData(route) {
|
|
|
977
1015
|
const routeId = route.id;
|
|
978
1016
|
return useRouteContext("useRouteData", routeId).data;
|
|
979
1017
|
}
|
|
980
|
-
|
|
981
1018
|
//#endregion
|
|
982
1019
|
//#region src/hooks/useIsPending.ts
|
|
983
1020
|
/**
|
|
@@ -988,7 +1025,7 @@ function useIsPending() {
|
|
|
988
1025
|
if (!context) throw new Error("useIsPending must be used within a Router");
|
|
989
1026
|
return context.isPending;
|
|
990
1027
|
}
|
|
991
|
-
|
|
992
1028
|
//#endregion
|
|
993
|
-
export { Outlet, Router, route, routeState, useBlocker, useIsPending, useLocation,
|
|
1029
|
+
export { Outlet, Router, bindRoute, hardNavigate, hardReload, route, routeState, useBlocker, useIsPending, useLocation, useRouteData, useRouteParams, useRouteState, useSearchParams };
|
|
1030
|
+
|
|
994
1031
|
//# sourceMappingURL=index.mjs.map
|