1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | var Action = ((Action2) => {
|
14 | Action2["Pop"] = "POP";
|
15 | Action2["Push"] = "PUSH";
|
16 | Action2["Replace"] = "REPLACE";
|
17 | return Action2;
|
18 | })(Action || {});
|
19 | var PopStateEventType = "popstate";
|
20 | function createMemoryHistory(options = {}) {
|
21 | let { initialEntries = ["/"], initialIndex, v5Compat = false } = options;
|
22 | let entries;
|
23 | entries = initialEntries.map(
|
24 | (entry, index2) => createMemoryLocation(
|
25 | entry,
|
26 | typeof entry === "string" ? null : entry.state,
|
27 | index2 === 0 ? "default" : void 0
|
28 | )
|
29 | );
|
30 | let index = clampIndex(
|
31 | initialIndex == null ? entries.length - 1 : initialIndex
|
32 | );
|
33 | let action = "POP" ;
|
34 | let listener = null;
|
35 | function clampIndex(n) {
|
36 | return Math.min(Math.max(n, 0), entries.length - 1);
|
37 | }
|
38 | function getCurrentLocation() {
|
39 | return entries[index];
|
40 | }
|
41 | function createMemoryLocation(to, state = null, key) {
|
42 | let location = createLocation(
|
43 | entries ? getCurrentLocation().pathname : "/",
|
44 | to,
|
45 | state,
|
46 | key
|
47 | );
|
48 | warning(
|
49 | location.pathname.charAt(0) === "/",
|
50 | `relative pathnames are not supported in memory history: ${JSON.stringify(
|
51 | to
|
52 | )}`
|
53 | );
|
54 | return location;
|
55 | }
|
56 | function createHref2(to) {
|
57 | return typeof to === "string" ? to : createPath(to);
|
58 | }
|
59 | let history = {
|
60 | get index() {
|
61 | return index;
|
62 | },
|
63 | get action() {
|
64 | return action;
|
65 | },
|
66 | get location() {
|
67 | return getCurrentLocation();
|
68 | },
|
69 | createHref: createHref2,
|
70 | createURL(to) {
|
71 | return new URL(createHref2(to), "http://localhost");
|
72 | },
|
73 | encodeLocation(to) {
|
74 | let path = typeof to === "string" ? parsePath(to) : to;
|
75 | return {
|
76 | pathname: path.pathname || "",
|
77 | search: path.search || "",
|
78 | hash: path.hash || ""
|
79 | };
|
80 | },
|
81 | push(to, state) {
|
82 | action = "PUSH" ;
|
83 | let nextLocation = createMemoryLocation(to, state);
|
84 | index += 1;
|
85 | entries.splice(index, entries.length, nextLocation);
|
86 | if (v5Compat && listener) {
|
87 | listener({ action, location: nextLocation, delta: 1 });
|
88 | }
|
89 | },
|
90 | replace(to, state) {
|
91 | action = "REPLACE" ;
|
92 | let nextLocation = createMemoryLocation(to, state);
|
93 | entries[index] = nextLocation;
|
94 | if (v5Compat && listener) {
|
95 | listener({ action, location: nextLocation, delta: 0 });
|
96 | }
|
97 | },
|
98 | go(delta) {
|
99 | action = "POP" ;
|
100 | let nextIndex = clampIndex(index + delta);
|
101 | let nextLocation = entries[nextIndex];
|
102 | index = nextIndex;
|
103 | if (listener) {
|
104 | listener({ action, location: nextLocation, delta });
|
105 | }
|
106 | },
|
107 | listen(fn) {
|
108 | listener = fn;
|
109 | return () => {
|
110 | listener = null;
|
111 | };
|
112 | }
|
113 | };
|
114 | return history;
|
115 | }
|
116 | function createBrowserHistory(options = {}) {
|
117 | function createBrowserLocation(window2, globalHistory) {
|
118 | let { pathname, search, hash } = window2.location;
|
119 | return createLocation(
|
120 | "",
|
121 | { pathname, search, hash },
|
122 |
|
123 | globalHistory.state && globalHistory.state.usr || null,
|
124 | globalHistory.state && globalHistory.state.key || "default"
|
125 | );
|
126 | }
|
127 | function createBrowserHref(window2, to) {
|
128 | return typeof to === "string" ? to : createPath(to);
|
129 | }
|
130 | return getUrlBasedHistory(
|
131 | createBrowserLocation,
|
132 | createBrowserHref,
|
133 | null,
|
134 | options
|
135 | );
|
136 | }
|
137 | function createHashHistory(options = {}) {
|
138 | function createHashLocation(window2, globalHistory) {
|
139 | let {
|
140 | pathname = "/",
|
141 | search = "",
|
142 | hash = ""
|
143 | } = parsePath(window2.location.hash.substring(1));
|
144 | if (!pathname.startsWith("/") && !pathname.startsWith(".")) {
|
145 | pathname = "/" + pathname;
|
146 | }
|
147 | return createLocation(
|
148 | "",
|
149 | { pathname, search, hash },
|
150 |
|
151 | globalHistory.state && globalHistory.state.usr || null,
|
152 | globalHistory.state && globalHistory.state.key || "default"
|
153 | );
|
154 | }
|
155 | function createHashHref(window2, to) {
|
156 | let base = window2.document.querySelector("base");
|
157 | let href = "";
|
158 | if (base && base.getAttribute("href")) {
|
159 | let url = window2.location.href;
|
160 | let hashIndex = url.indexOf("#");
|
161 | href = hashIndex === -1 ? url : url.slice(0, hashIndex);
|
162 | }
|
163 | return href + "#" + (typeof to === "string" ? to : createPath(to));
|
164 | }
|
165 | function validateHashLocation(location, to) {
|
166 | warning(
|
167 | location.pathname.charAt(0) === "/",
|
168 | `relative pathnames are not supported in hash history.push(${JSON.stringify(
|
169 | to
|
170 | )})`
|
171 | );
|
172 | }
|
173 | return getUrlBasedHistory(
|
174 | createHashLocation,
|
175 | createHashHref,
|
176 | validateHashLocation,
|
177 | options
|
178 | );
|
179 | }
|
180 | function invariant(value, message) {
|
181 | if (value === false || value === null || typeof value === "undefined") {
|
182 | throw new Error(message);
|
183 | }
|
184 | }
|
185 | function warning(cond, message) {
|
186 | if (!cond) {
|
187 | if (typeof console !== "undefined") console.warn(message);
|
188 | try {
|
189 | throw new Error(message);
|
190 | } catch (e) {
|
191 | }
|
192 | }
|
193 | }
|
194 | function createKey() {
|
195 | return Math.random().toString(36).substring(2, 10);
|
196 | }
|
197 | function getHistoryState(location, index) {
|
198 | return {
|
199 | usr: location.state,
|
200 | key: location.key,
|
201 | idx: index
|
202 | };
|
203 | }
|
204 | function createLocation(current, to, state = null, key) {
|
205 | let location = {
|
206 | pathname: typeof current === "string" ? current : current.pathname,
|
207 | search: "",
|
208 | hash: "",
|
209 | ...typeof to === "string" ? parsePath(to) : to,
|
210 | state,
|
211 |
|
212 |
|
213 |
|
214 |
|
215 | key: to && to.key || key || createKey()
|
216 | };
|
217 | return location;
|
218 | }
|
219 | function createPath({
|
220 | pathname = "/",
|
221 | search = "",
|
222 | hash = ""
|
223 | }) {
|
224 | if (search && search !== "?")
|
225 | pathname += search.charAt(0) === "?" ? search : "?" + search;
|
226 | if (hash && hash !== "#")
|
227 | pathname += hash.charAt(0) === "#" ? hash : "#" + hash;
|
228 | return pathname;
|
229 | }
|
230 | function parsePath(path) {
|
231 | let parsedPath = {};
|
232 | if (path) {
|
233 | let hashIndex = path.indexOf("#");
|
234 | if (hashIndex >= 0) {
|
235 | parsedPath.hash = path.substring(hashIndex);
|
236 | path = path.substring(0, hashIndex);
|
237 | }
|
238 | let searchIndex = path.indexOf("?");
|
239 | if (searchIndex >= 0) {
|
240 | parsedPath.search = path.substring(searchIndex);
|
241 | path = path.substring(0, searchIndex);
|
242 | }
|
243 | if (path) {
|
244 | parsedPath.pathname = path;
|
245 | }
|
246 | }
|
247 | return parsedPath;
|
248 | }
|
249 | function getUrlBasedHistory(getLocation, createHref2, validateLocation, options = {}) {
|
250 | let { window: window2 = document.defaultView, v5Compat = false } = options;
|
251 | let globalHistory = window2.history;
|
252 | let action = "POP" ;
|
253 | let listener = null;
|
254 | let index = getIndex();
|
255 | if (index == null) {
|
256 | index = 0;
|
257 | globalHistory.replaceState({ ...globalHistory.state, idx: index }, "");
|
258 | }
|
259 | function getIndex() {
|
260 | let state = globalHistory.state || { idx: null };
|
261 | return state.idx;
|
262 | }
|
263 | function handlePop() {
|
264 | action = "POP" ;
|
265 | let nextIndex = getIndex();
|
266 | let delta = nextIndex == null ? null : nextIndex - index;
|
267 | index = nextIndex;
|
268 | if (listener) {
|
269 | listener({ action, location: history.location, delta });
|
270 | }
|
271 | }
|
272 | function push(to, state) {
|
273 | action = "PUSH" ;
|
274 | let location = createLocation(history.location, to, state);
|
275 | if (validateLocation) validateLocation(location, to);
|
276 | index = getIndex() + 1;
|
277 | let historyState = getHistoryState(location, index);
|
278 | let url = history.createHref(location);
|
279 | try {
|
280 | globalHistory.pushState(historyState, "", url);
|
281 | } catch (error) {
|
282 | if (error instanceof DOMException && error.name === "DataCloneError") {
|
283 | throw error;
|
284 | }
|
285 | window2.location.assign(url);
|
286 | }
|
287 | if (v5Compat && listener) {
|
288 | listener({ action, location: history.location, delta: 1 });
|
289 | }
|
290 | }
|
291 | function replace2(to, state) {
|
292 | action = "REPLACE" ;
|
293 | let location = createLocation(history.location, to, state);
|
294 | if (validateLocation) validateLocation(location, to);
|
295 | index = getIndex();
|
296 | let historyState = getHistoryState(location, index);
|
297 | let url = history.createHref(location);
|
298 | globalHistory.replaceState(historyState, "", url);
|
299 | if (v5Compat && listener) {
|
300 | listener({ action, location: history.location, delta: 0 });
|
301 | }
|
302 | }
|
303 | function createURL(to) {
|
304 | let base = window2.location.origin !== "null" ? window2.location.origin : window2.location.href;
|
305 | let href = typeof to === "string" ? to : createPath(to);
|
306 | href = href.replace(/ $/, "%20");
|
307 | invariant(
|
308 | base,
|
309 | `No window.location.(origin|href) available to create URL for href: ${href}`
|
310 | );
|
311 | return new URL(href, base);
|
312 | }
|
313 | let history = {
|
314 | get action() {
|
315 | return action;
|
316 | },
|
317 | get location() {
|
318 | return getLocation(window2, globalHistory);
|
319 | },
|
320 | listen(fn) {
|
321 | if (listener) {
|
322 | throw new Error("A history only accepts one active listener");
|
323 | }
|
324 | window2.addEventListener(PopStateEventType, handlePop);
|
325 | listener = fn;
|
326 | return () => {
|
327 | window2.removeEventListener(PopStateEventType, handlePop);
|
328 | listener = null;
|
329 | };
|
330 | },
|
331 | createHref(to) {
|
332 | return createHref2(window2, to);
|
333 | },
|
334 | createURL,
|
335 | encodeLocation(to) {
|
336 | let url = createURL(to);
|
337 | return {
|
338 | pathname: url.pathname,
|
339 | search: url.search,
|
340 | hash: url.hash
|
341 | };
|
342 | },
|
343 | push,
|
344 | replace: replace2,
|
345 | go(n) {
|
346 | return globalHistory.go(n);
|
347 | }
|
348 | };
|
349 | return history;
|
350 | }
|
351 |
|
352 |
|
353 | var immutableRouteKeys = new Set([
|
354 | "lazy",
|
355 | "caseSensitive",
|
356 | "path",
|
357 | "id",
|
358 | "index",
|
359 | "children"
|
360 | ]);
|
361 | function isIndexRoute(route) {
|
362 | return route.index === true;
|
363 | }
|
364 | function convertRoutesToDataRoutes(routes, mapRouteProperties2, parentPath = [], manifest = {}) {
|
365 | return routes.map((route, index) => {
|
366 | let treePath = [...parentPath, String(index)];
|
367 | let id = typeof route.id === "string" ? route.id : treePath.join("-");
|
368 | invariant(
|
369 | route.index !== true || !route.children,
|
370 | `Cannot specify children on an index route`
|
371 | );
|
372 | invariant(
|
373 | !manifest[id],
|
374 | `Found a route id collision on id "${id}". Route id's must be globally unique within Data Router usages`
|
375 | );
|
376 | if (isIndexRoute(route)) {
|
377 | let indexRoute = {
|
378 | ...route,
|
379 | ...mapRouteProperties2(route),
|
380 | id
|
381 | };
|
382 | manifest[id] = indexRoute;
|
383 | return indexRoute;
|
384 | } else {
|
385 | let pathOrLayoutRoute = {
|
386 | ...route,
|
387 | ...mapRouteProperties2(route),
|
388 | id,
|
389 | children: void 0
|
390 | };
|
391 | manifest[id] = pathOrLayoutRoute;
|
392 | if (route.children) {
|
393 | pathOrLayoutRoute.children = convertRoutesToDataRoutes(
|
394 | route.children,
|
395 | mapRouteProperties2,
|
396 | treePath,
|
397 | manifest
|
398 | );
|
399 | }
|
400 | return pathOrLayoutRoute;
|
401 | }
|
402 | });
|
403 | }
|
404 | function matchRoutes(routes, locationArg, basename = "/") {
|
405 | return matchRoutesImpl(routes, locationArg, basename, false);
|
406 | }
|
407 | function matchRoutesImpl(routes, locationArg, basename, allowPartial) {
|
408 | let location = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
|
409 | let pathname = stripBasename(location.pathname || "/", basename);
|
410 | if (pathname == null) {
|
411 | return null;
|
412 | }
|
413 | let branches = flattenRoutes(routes);
|
414 | rankRouteBranches(branches);
|
415 | let matches = null;
|
416 | for (let i = 0; matches == null && i < branches.length; ++i) {
|
417 | let decoded = decodePath(pathname);
|
418 | matches = matchRouteBranch(
|
419 | branches[i],
|
420 | decoded,
|
421 | allowPartial
|
422 | );
|
423 | }
|
424 | return matches;
|
425 | }
|
426 | function convertRouteMatchToUiMatch(match, loaderData) {
|
427 | let { route, pathname, params } = match;
|
428 | return {
|
429 | id: route.id,
|
430 | pathname,
|
431 | params,
|
432 | data: loaderData[route.id],
|
433 | handle: route.handle
|
434 | };
|
435 | }
|
436 | function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "") {
|
437 | let flattenRoute = (route, index, relativePath) => {
|
438 | let meta = {
|
439 | relativePath: relativePath === void 0 ? route.path || "" : relativePath,
|
440 | caseSensitive: route.caseSensitive === true,
|
441 | childrenIndex: index,
|
442 | route
|
443 | };
|
444 | if (meta.relativePath.startsWith("/")) {
|
445 | invariant(
|
446 | meta.relativePath.startsWith(parentPath),
|
447 | `Absolute route path "${meta.relativePath}" nested under path "${parentPath}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`
|
448 | );
|
449 | meta.relativePath = meta.relativePath.slice(parentPath.length);
|
450 | }
|
451 | let path = joinPaths([parentPath, meta.relativePath]);
|
452 | let routesMeta = parentsMeta.concat(meta);
|
453 | if (route.children && route.children.length > 0) {
|
454 | invariant(
|
455 |
|
456 |
|
457 | route.index !== true,
|
458 | `Index routes must not have child routes. Please remove all child routes from route path "${path}".`
|
459 | );
|
460 | flattenRoutes(route.children, branches, routesMeta, path);
|
461 | }
|
462 | if (route.path == null && !route.index) {
|
463 | return;
|
464 | }
|
465 | branches.push({
|
466 | path,
|
467 | score: computeScore(path, route.index),
|
468 | routesMeta
|
469 | });
|
470 | };
|
471 | routes.forEach((route, index) => {
|
472 | if (route.path === "" || !route.path?.includes("?")) {
|
473 | flattenRoute(route, index);
|
474 | } else {
|
475 | for (let exploded of explodeOptionalSegments(route.path)) {
|
476 | flattenRoute(route, index, exploded);
|
477 | }
|
478 | }
|
479 | });
|
480 | return branches;
|
481 | }
|
482 | function explodeOptionalSegments(path) {
|
483 | let segments = path.split("/");
|
484 | if (segments.length === 0) return [];
|
485 | let [first, ...rest] = segments;
|
486 | let isOptional = first.endsWith("?");
|
487 | let required = first.replace(/\?$/, "");
|
488 | if (rest.length === 0) {
|
489 | return isOptional ? [required, ""] : [required];
|
490 | }
|
491 | let restExploded = explodeOptionalSegments(rest.join("/"));
|
492 | let result = [];
|
493 | result.push(
|
494 | ...restExploded.map(
|
495 | (subpath) => subpath === "" ? required : [required, subpath].join("/")
|
496 | )
|
497 | );
|
498 | if (isOptional) {
|
499 | result.push(...restExploded);
|
500 | }
|
501 | return result.map(
|
502 | (exploded) => path.startsWith("/") && exploded === "" ? "/" : exploded
|
503 | );
|
504 | }
|
505 | function rankRouteBranches(branches) {
|
506 | branches.sort(
|
507 | (a, b) => a.score !== b.score ? b.score - a.score : compareIndexes(
|
508 | a.routesMeta.map((meta) => meta.childrenIndex),
|
509 | b.routesMeta.map((meta) => meta.childrenIndex)
|
510 | )
|
511 | );
|
512 | }
|
513 | var paramRe = /^:[\w-]+$/;
|
514 | var dynamicSegmentValue = 3;
|
515 | var indexRouteValue = 2;
|
516 | var emptySegmentValue = 1;
|
517 | var staticSegmentValue = 10;
|
518 | var splatPenalty = -2;
|
519 | var isSplat = (s) => s === "*";
|
520 | function computeScore(path, index) {
|
521 | let segments = path.split("/");
|
522 | let initialScore = segments.length;
|
523 | if (segments.some(isSplat)) {
|
524 | initialScore += splatPenalty;
|
525 | }
|
526 | if (index) {
|
527 | initialScore += indexRouteValue;
|
528 | }
|
529 | return segments.filter((s) => !isSplat(s)).reduce(
|
530 | (score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue),
|
531 | initialScore
|
532 | );
|
533 | }
|
534 | function compareIndexes(a, b) {
|
535 | let siblings = a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]);
|
536 | return siblings ? (
|
537 |
|
538 |
|
539 |
|
540 |
|
541 | a[a.length - 1] - b[b.length - 1]
|
542 | ) : (
|
543 |
|
544 |
|
545 | 0
|
546 | );
|
547 | }
|
548 | function matchRouteBranch(branch, pathname, allowPartial = false) {
|
549 | let { routesMeta } = branch;
|
550 | let matchedParams = {};
|
551 | let matchedPathname = "/";
|
552 | let matches = [];
|
553 | for (let i = 0; i < routesMeta.length; ++i) {
|
554 | let meta = routesMeta[i];
|
555 | let end = i === routesMeta.length - 1;
|
556 | let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
|
557 | let match = matchPath(
|
558 | { path: meta.relativePath, caseSensitive: meta.caseSensitive, end },
|
559 | remainingPathname
|
560 | );
|
561 | let route = meta.route;
|
562 | if (!match && end && allowPartial && !routesMeta[routesMeta.length - 1].route.index) {
|
563 | match = matchPath(
|
564 | {
|
565 | path: meta.relativePath,
|
566 | caseSensitive: meta.caseSensitive,
|
567 | end: false
|
568 | },
|
569 | remainingPathname
|
570 | );
|
571 | }
|
572 | if (!match) {
|
573 | return null;
|
574 | }
|
575 | Object.assign(matchedParams, match.params);
|
576 | matches.push({
|
577 |
|
578 | params: matchedParams,
|
579 | pathname: joinPaths([matchedPathname, match.pathname]),
|
580 | pathnameBase: normalizePathname(
|
581 | joinPaths([matchedPathname, match.pathnameBase])
|
582 | ),
|
583 | route
|
584 | });
|
585 | if (match.pathnameBase !== "/") {
|
586 | matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
|
587 | }
|
588 | }
|
589 | return matches;
|
590 | }
|
591 | function generatePath(originalPath, params = {}) {
|
592 | let path = originalPath;
|
593 | if (path.endsWith("*") && path !== "*" && !path.endsWith("/*")) {
|
594 | warning(
|
595 | false,
|
596 | `Route path "${path}" will be treated as if it were "${path.replace(/\*$/, "/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${path.replace(/\*$/, "/*")}".`
|
597 | );
|
598 | path = path.replace(/\*$/, "/*");
|
599 | }
|
600 | const prefix = path.startsWith("/") ? "/" : "";
|
601 | const stringify = (p) => p == null ? "" : typeof p === "string" ? p : String(p);
|
602 | const segments = path.split(/\/+/).map((segment, index, array) => {
|
603 | const isLastSegment = index === array.length - 1;
|
604 | if (isLastSegment && segment === "*") {
|
605 | const star = "*";
|
606 | return stringify(params[star]);
|
607 | }
|
608 | const keyMatch = segment.match(/^:([\w-]+)(\??)$/);
|
609 | if (keyMatch) {
|
610 | const [, key, optional] = keyMatch;
|
611 | let param = params[key];
|
612 | invariant(optional === "?" || param != null, `Missing ":${key}" param`);
|
613 | return stringify(param);
|
614 | }
|
615 | return segment.replace(/\?$/g, "");
|
616 | }).filter((segment) => !!segment);
|
617 | return prefix + segments.join("/");
|
618 | }
|
619 | function matchPath(pattern, pathname) {
|
620 | if (typeof pattern === "string") {
|
621 | pattern = { path: pattern, caseSensitive: false, end: true };
|
622 | }
|
623 | let [matcher, compiledParams] = compilePath(
|
624 | pattern.path,
|
625 | pattern.caseSensitive,
|
626 | pattern.end
|
627 | );
|
628 | let match = pathname.match(matcher);
|
629 | if (!match) return null;
|
630 | let matchedPathname = match[0];
|
631 | let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
|
632 | let captureGroups = match.slice(1);
|
633 | let params = compiledParams.reduce(
|
634 | (memo2, { paramName, isOptional }, index) => {
|
635 | if (paramName === "*") {
|
636 | let splatValue = captureGroups[index] || "";
|
637 | pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
|
638 | }
|
639 | const value = captureGroups[index];
|
640 | if (isOptional && !value) {
|
641 | memo2[paramName] = void 0;
|
642 | } else {
|
643 | memo2[paramName] = (value || "").replace(/%2F/g, "/");
|
644 | }
|
645 | return memo2;
|
646 | },
|
647 | {}
|
648 | );
|
649 | return {
|
650 | params,
|
651 | pathname: matchedPathname,
|
652 | pathnameBase,
|
653 | pattern
|
654 | };
|
655 | }
|
656 | function compilePath(path, caseSensitive = false, end = true) {
|
657 | warning(
|
658 | path === "*" || !path.endsWith("*") || path.endsWith("/*"),
|
659 | `Route path "${path}" will be treated as if it were "${path.replace(/\*$/, "/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${path.replace(/\*$/, "/*")}".`
|
660 | );
|
661 | let params = [];
|
662 | let regexpSource = "^" + path.replace(/\/*\*?$/, "").replace(/^\/*/, "/").replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(
|
663 | /\/:([\w-]+)(\?)?/g,
|
664 | (_, paramName, isOptional) => {
|
665 | params.push({ paramName, isOptional: isOptional != null });
|
666 | return isOptional ? "/?([^\\/]+)?" : "/([^\\/]+)";
|
667 | }
|
668 | );
|
669 | if (path.endsWith("*")) {
|
670 | params.push({ paramName: "*" });
|
671 | regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
|
672 | } else if (end) {
|
673 | regexpSource += "\\/*$";
|
674 | } else if (path !== "" && path !== "/") {
|
675 | regexpSource += "(?:(?=\\/|$))";
|
676 | } else {
|
677 | }
|
678 | let matcher = new RegExp(regexpSource, caseSensitive ? void 0 : "i");
|
679 | return [matcher, params];
|
680 | }
|
681 | function decodePath(value) {
|
682 | try {
|
683 | return value.split("/").map((v) => decodeURIComponent(v).replace(/\//g, "%2F")).join("/");
|
684 | } catch (error) {
|
685 | warning(
|
686 | false,
|
687 | `The URL path "${value}" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent encoding (${error}).`
|
688 | );
|
689 | return value;
|
690 | }
|
691 | }
|
692 | function stripBasename(pathname, basename) {
|
693 | if (basename === "/") return pathname;
|
694 | if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
|
695 | return null;
|
696 | }
|
697 | let startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
|
698 | let nextChar = pathname.charAt(startIndex);
|
699 | if (nextChar && nextChar !== "/") {
|
700 | return null;
|
701 | }
|
702 | return pathname.slice(startIndex) || "/";
|
703 | }
|
704 | function resolvePath(to, fromPathname = "/") {
|
705 | let {
|
706 | pathname: toPathname,
|
707 | search = "",
|
708 | hash = ""
|
709 | } = typeof to === "string" ? parsePath(to) : to;
|
710 | let pathname = toPathname ? toPathname.startsWith("/") ? toPathname : resolvePathname(toPathname, fromPathname) : fromPathname;
|
711 | return {
|
712 | pathname,
|
713 | search: normalizeSearch(search),
|
714 | hash: normalizeHash(hash)
|
715 | };
|
716 | }
|
717 | function resolvePathname(relativePath, fromPathname) {
|
718 | let segments = fromPathname.replace(/\/+$/, "").split("/");
|
719 | let relativeSegments = relativePath.split("/");
|
720 | relativeSegments.forEach((segment) => {
|
721 | if (segment === "..") {
|
722 | if (segments.length > 1) segments.pop();
|
723 | } else if (segment !== ".") {
|
724 | segments.push(segment);
|
725 | }
|
726 | });
|
727 | return segments.length > 1 ? segments.join("/") : "/";
|
728 | }
|
729 | function getInvalidPathError(char, field, dest, path) {
|
730 | return `Cannot include a '${char}' character in a manually specified \`to.${field}\` field [${JSON.stringify(
|
731 | path
|
732 | )}]. Please separate it out to the \`to.${dest}\` field. Alternatively you may provide the full path as a string in <Link to="..."> and the router will parse it for you.`;
|
733 | }
|
734 | function getPathContributingMatches(matches) {
|
735 | return matches.filter(
|
736 | (match, index) => index === 0 || match.route.path && match.route.path.length > 0
|
737 | );
|
738 | }
|
739 | function getResolveToMatches(matches) {
|
740 | let pathMatches = getPathContributingMatches(matches);
|
741 | return pathMatches.map(
|
742 | (match, idx) => idx === pathMatches.length - 1 ? match.pathname : match.pathnameBase
|
743 | );
|
744 | }
|
745 | function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = false) {
|
746 | let to;
|
747 | if (typeof toArg === "string") {
|
748 | to = parsePath(toArg);
|
749 | } else {
|
750 | to = { ...toArg };
|
751 | invariant(
|
752 | !to.pathname || !to.pathname.includes("?"),
|
753 | getInvalidPathError("?", "pathname", "search", to)
|
754 | );
|
755 | invariant(
|
756 | !to.pathname || !to.pathname.includes("#"),
|
757 | getInvalidPathError("#", "pathname", "hash", to)
|
758 | );
|
759 | invariant(
|
760 | !to.search || !to.search.includes("#"),
|
761 | getInvalidPathError("#", "search", "hash", to)
|
762 | );
|
763 | }
|
764 | let isEmptyPath = toArg === "" || to.pathname === "";
|
765 | let toPathname = isEmptyPath ? "/" : to.pathname;
|
766 | let from;
|
767 | if (toPathname == null) {
|
768 | from = locationPathname;
|
769 | } else {
|
770 | let routePathnameIndex = routePathnames.length - 1;
|
771 | if (!isPathRelative && toPathname.startsWith("..")) {
|
772 | let toSegments = toPathname.split("/");
|
773 | while (toSegments[0] === "..") {
|
774 | toSegments.shift();
|
775 | routePathnameIndex -= 1;
|
776 | }
|
777 | to.pathname = toSegments.join("/");
|
778 | }
|
779 | from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
|
780 | }
|
781 | let path = resolvePath(to, from);
|
782 | let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
|
783 | let hasCurrentTrailingSlash = (isEmptyPath || toPathname === ".") && locationPathname.endsWith("/");
|
784 | if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) {
|
785 | path.pathname += "/";
|
786 | }
|
787 | return path;
|
788 | }
|
789 | var joinPaths = (paths) => paths.join("/").replace(/\/\/+/g, "/");
|
790 | var normalizePathname = (pathname) => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
|
791 | var normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
|
792 | var normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
|
793 | var DataWithResponseInit = class {
|
794 | constructor(data2, init) {
|
795 | this.type = "DataWithResponseInit";
|
796 | this.data = data2;
|
797 | this.init = init || null;
|
798 | }
|
799 | };
|
800 | function data(data2, init) {
|
801 | return new DataWithResponseInit(
|
802 | data2,
|
803 | typeof init === "number" ? { status: init } : init
|
804 | );
|
805 | }
|
806 | var redirect = (url, init = 302) => {
|
807 | let responseInit = init;
|
808 | if (typeof responseInit === "number") {
|
809 | responseInit = { status: responseInit };
|
810 | } else if (typeof responseInit.status === "undefined") {
|
811 | responseInit.status = 302;
|
812 | }
|
813 | let headers = new Headers(responseInit.headers);
|
814 | headers.set("Location", url);
|
815 | return new Response(null, {
|
816 | ...responseInit,
|
817 | headers
|
818 | });
|
819 | };
|
820 | var redirectDocument = (url, init) => {
|
821 | let response = redirect(url, init);
|
822 | response.headers.set("X-Remix-Reload-Document", "true");
|
823 | return response;
|
824 | };
|
825 | var replace = (url, init) => {
|
826 | let response = redirect(url, init);
|
827 | response.headers.set("X-Remix-Replace", "true");
|
828 | return response;
|
829 | };
|
830 | var ErrorResponseImpl = class {
|
831 | constructor(status, statusText, data2, internal = false) {
|
832 | this.status = status;
|
833 | this.statusText = statusText || "";
|
834 | this.internal = internal;
|
835 | if (data2 instanceof Error) {
|
836 | this.data = data2.toString();
|
837 | this.error = data2;
|
838 | } else {
|
839 | this.data = data2;
|
840 | }
|
841 | }
|
842 | };
|
843 | function isRouteErrorResponse(error) {
|
844 | return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
|
845 | }
|
846 |
|
847 |
|
848 | var validMutationMethodsArr = [
|
849 | "POST",
|
850 | "PUT",
|
851 | "PATCH",
|
852 | "DELETE"
|
853 | ];
|
854 | var validMutationMethods = new Set(
|
855 | validMutationMethodsArr
|
856 | );
|
857 | var validRequestMethodsArr = [
|
858 | "GET",
|
859 | ...validMutationMethodsArr
|
860 | ];
|
861 | var validRequestMethods = new Set(validRequestMethodsArr);
|
862 | var redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
|
863 | var redirectPreserveMethodStatusCodes = new Set([307, 308]);
|
864 | var IDLE_NAVIGATION = {
|
865 | state: "idle",
|
866 | location: void 0,
|
867 | formMethod: void 0,
|
868 | formAction: void 0,
|
869 | formEncType: void 0,
|
870 | formData: void 0,
|
871 | json: void 0,
|
872 | text: void 0
|
873 | };
|
874 | var IDLE_FETCHER = {
|
875 | state: "idle",
|
876 | data: void 0,
|
877 | formMethod: void 0,
|
878 | formAction: void 0,
|
879 | formEncType: void 0,
|
880 | formData: void 0,
|
881 | json: void 0,
|
882 | text: void 0
|
883 | };
|
884 | var IDLE_BLOCKER = {
|
885 | state: "unblocked",
|
886 | proceed: void 0,
|
887 | reset: void 0,
|
888 | location: void 0
|
889 | };
|
890 | var ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
891 | var defaultMapRouteProperties = (route) => ({
|
892 | hasErrorBoundary: Boolean(route.hasErrorBoundary)
|
893 | });
|
894 | var TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
|
895 | var ResetLoaderDataSymbol = Symbol("ResetLoaderData");
|
896 | function createRouter(init) {
|
897 | const routerWindow = init.window ? init.window : typeof window !== "undefined" ? window : void 0;
|
898 | const isBrowser2 = typeof routerWindow !== "undefined" && typeof routerWindow.document !== "undefined" && typeof routerWindow.document.createElement !== "undefined";
|
899 | invariant(
|
900 | init.routes.length > 0,
|
901 | "You must provide a non-empty routes array to createRouter"
|
902 | );
|
903 | let mapRouteProperties2 = init.mapRouteProperties || defaultMapRouteProperties;
|
904 | let manifest = {};
|
905 | let dataRoutes = convertRoutesToDataRoutes(
|
906 | init.routes,
|
907 | mapRouteProperties2,
|
908 | void 0,
|
909 | manifest
|
910 | );
|
911 | let inFlightDataRoutes;
|
912 | let basename = init.basename || "/";
|
913 | let dataStrategyImpl = init.dataStrategy || defaultDataStrategy;
|
914 | let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
|
915 | let future = {
|
916 | ...init.future
|
917 | };
|
918 | let unlistenHistory = null;
|
919 | let subscribers = new Set();
|
920 | let savedScrollPositions2 = null;
|
921 | let getScrollRestorationKey2 = null;
|
922 | let getScrollPosition = null;
|
923 | let initialScrollRestored = init.hydrationData != null;
|
924 | let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
|
925 | let initialErrors = null;
|
926 | if (initialMatches == null && !patchRoutesOnNavigationImpl) {
|
927 | let error = getInternalRouterError(404, {
|
928 | pathname: init.history.location.pathname
|
929 | });
|
930 | let { matches, route } = getShortCircuitMatches(dataRoutes);
|
931 | initialMatches = matches;
|
932 | initialErrors = { [route.id]: error };
|
933 | }
|
934 | if (initialMatches && !init.hydrationData) {
|
935 | let fogOfWar = checkFogOfWar(
|
936 | initialMatches,
|
937 | dataRoutes,
|
938 | init.history.location.pathname
|
939 | );
|
940 | if (fogOfWar.active) {
|
941 | initialMatches = null;
|
942 | }
|
943 | }
|
944 | let initialized;
|
945 | if (!initialMatches) {
|
946 | initialized = false;
|
947 | initialMatches = [];
|
948 | let fogOfWar = checkFogOfWar(
|
949 | null,
|
950 | dataRoutes,
|
951 | init.history.location.pathname
|
952 | );
|
953 | if (fogOfWar.active && fogOfWar.matches) {
|
954 | initialMatches = fogOfWar.matches;
|
955 | }
|
956 | } else if (initialMatches.some((m) => m.route.lazy)) {
|
957 | initialized = false;
|
958 | } else if (!initialMatches.some((m) => m.route.loader)) {
|
959 | initialized = true;
|
960 | } else {
|
961 | let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
|
962 | let errors = init.hydrationData ? init.hydrationData.errors : null;
|
963 | if (errors) {
|
964 | let idx = initialMatches.findIndex(
|
965 | (m) => errors[m.route.id] !== void 0
|
966 | );
|
967 | initialized = initialMatches.slice(0, idx + 1).every((m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors));
|
968 | } else {
|
969 | initialized = initialMatches.every(
|
970 | (m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors)
|
971 | );
|
972 | }
|
973 | }
|
974 | let router;
|
975 | let state = {
|
976 | historyAction: init.history.action,
|
977 | location: init.history.location,
|
978 | matches: initialMatches,
|
979 | initialized,
|
980 | navigation: IDLE_NAVIGATION,
|
981 |
|
982 | restoreScrollPosition: init.hydrationData != null ? false : null,
|
983 | preventScrollReset: false,
|
984 | revalidation: "idle",
|
985 | loaderData: init.hydrationData && init.hydrationData.loaderData || {},
|
986 | actionData: init.hydrationData && init.hydrationData.actionData || null,
|
987 | errors: init.hydrationData && init.hydrationData.errors || initialErrors,
|
988 | fetchers: new Map(),
|
989 | blockers: new Map()
|
990 | };
|
991 | let pendingAction = "POP" ;
|
992 | let pendingPreventScrollReset = false;
|
993 | let pendingNavigationController;
|
994 | let pendingViewTransitionEnabled = false;
|
995 | let appliedViewTransitions = new Map();
|
996 | let removePageHideEventListener = null;
|
997 | let isUninterruptedRevalidation = false;
|
998 | let isRevalidationRequired = false;
|
999 | let cancelledFetcherLoads = new Set();
|
1000 | let fetchControllers = new Map();
|
1001 | let incrementingLoadId = 0;
|
1002 | let pendingNavigationLoadId = -1;
|
1003 | let fetchReloadIds = new Map();
|
1004 | let fetchRedirectIds = new Set();
|
1005 | let fetchLoadMatches = new Map();
|
1006 | let activeFetchers = new Map();
|
1007 | let fetchersQueuedForDeletion = new Set();
|
1008 | let blockerFunctions = new Map();
|
1009 | let unblockBlockerHistoryUpdate = void 0;
|
1010 | let pendingRevalidationDfd = null;
|
1011 | function initialize() {
|
1012 | unlistenHistory = init.history.listen(
|
1013 | ({ action: historyAction, location, delta }) => {
|
1014 | if (unblockBlockerHistoryUpdate) {
|
1015 | unblockBlockerHistoryUpdate();
|
1016 | unblockBlockerHistoryUpdate = void 0;
|
1017 | return;
|
1018 | }
|
1019 | warning(
|
1020 | blockerFunctions.size === 0 || delta != null,
|
1021 | "You are trying to use a blocker on a POP navigation to a location that was not created by @remix-run/router. This will fail silently in production. This can happen if you are navigating outside the router via `window.history.pushState`/`window.location.hash` instead of using router navigation APIs. This can also happen if you are using createHashRouter and the user manually changes the URL."
|
1022 | );
|
1023 | let blockerKey = shouldBlockNavigation({
|
1024 | currentLocation: state.location,
|
1025 | nextLocation: location,
|
1026 | historyAction
|
1027 | });
|
1028 | if (blockerKey && delta != null) {
|
1029 | let nextHistoryUpdatePromise = new Promise((resolve) => {
|
1030 | unblockBlockerHistoryUpdate = resolve;
|
1031 | });
|
1032 | init.history.go(delta * -1);
|
1033 | updateBlocker(blockerKey, {
|
1034 | state: "blocked",
|
1035 | location,
|
1036 | proceed() {
|
1037 | updateBlocker(blockerKey, {
|
1038 | state: "proceeding",
|
1039 | proceed: void 0,
|
1040 | reset: void 0,
|
1041 | location
|
1042 | });
|
1043 | nextHistoryUpdatePromise.then(() => init.history.go(delta));
|
1044 | },
|
1045 | reset() {
|
1046 | let blockers = new Map(state.blockers);
|
1047 | blockers.set(blockerKey, IDLE_BLOCKER);
|
1048 | updateState({ blockers });
|
1049 | }
|
1050 | });
|
1051 | return;
|
1052 | }
|
1053 | return startNavigation(historyAction, location);
|
1054 | }
|
1055 | );
|
1056 | if (isBrowser2) {
|
1057 | restoreAppliedTransitions(routerWindow, appliedViewTransitions);
|
1058 | let _saveAppliedTransitions = () => persistAppliedTransitions(routerWindow, appliedViewTransitions);
|
1059 | routerWindow.addEventListener("pagehide", _saveAppliedTransitions);
|
1060 | removePageHideEventListener = () => routerWindow.removeEventListener("pagehide", _saveAppliedTransitions);
|
1061 | }
|
1062 | if (!state.initialized) {
|
1063 | startNavigation("POP" , state.location, {
|
1064 | initialHydration: true
|
1065 | });
|
1066 | }
|
1067 | return router;
|
1068 | }
|
1069 | function dispose() {
|
1070 | if (unlistenHistory) {
|
1071 | unlistenHistory();
|
1072 | }
|
1073 | if (removePageHideEventListener) {
|
1074 | removePageHideEventListener();
|
1075 | }
|
1076 | subscribers.clear();
|
1077 | pendingNavigationController && pendingNavigationController.abort();
|
1078 | state.fetchers.forEach((_, key) => deleteFetcher(key));
|
1079 | state.blockers.forEach((_, key) => deleteBlocker(key));
|
1080 | }
|
1081 | function subscribe(fn) {
|
1082 | subscribers.add(fn);
|
1083 | return () => subscribers.delete(fn);
|
1084 | }
|
1085 | function updateState(newState, opts = {}) {
|
1086 | state = {
|
1087 | ...state,
|
1088 | ...newState
|
1089 | };
|
1090 | let unmountedFetchers = [];
|
1091 | let mountedFetchers = [];
|
1092 | state.fetchers.forEach((fetcher, key) => {
|
1093 | if (fetcher.state === "idle") {
|
1094 | if (fetchersQueuedForDeletion.has(key)) {
|
1095 | unmountedFetchers.push(key);
|
1096 | } else {
|
1097 | mountedFetchers.push(key);
|
1098 | }
|
1099 | }
|
1100 | });
|
1101 | [...subscribers].forEach(
|
1102 | (subscriber) => subscriber(state, {
|
1103 | deletedFetchers: unmountedFetchers,
|
1104 | viewTransitionOpts: opts.viewTransitionOpts,
|
1105 | flushSync: opts.flushSync === true
|
1106 | })
|
1107 | );
|
1108 | unmountedFetchers.forEach((key) => deleteFetcher(key));
|
1109 | mountedFetchers.forEach((key) => state.fetchers.delete(key));
|
1110 | }
|
1111 | function completeNavigation(location, newState, { flushSync } = {}) {
|
1112 | let isActionReload = state.actionData != null && state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && state.navigation.state === "loading" && location.state?._isRedirect !== true;
|
1113 | let actionData;
|
1114 | if (newState.actionData) {
|
1115 | if (Object.keys(newState.actionData).length > 0) {
|
1116 | actionData = newState.actionData;
|
1117 | } else {
|
1118 | actionData = null;
|
1119 | }
|
1120 | } else if (isActionReload) {
|
1121 | actionData = state.actionData;
|
1122 | } else {
|
1123 | actionData = null;
|
1124 | }
|
1125 | let loaderData = newState.loaderData ? mergeLoaderData(
|
1126 | state.loaderData,
|
1127 | newState.loaderData,
|
1128 | newState.matches || [],
|
1129 | newState.errors
|
1130 | ) : state.loaderData;
|
1131 | let blockers = state.blockers;
|
1132 | if (blockers.size > 0) {
|
1133 | blockers = new Map(blockers);
|
1134 | blockers.forEach((_, k) => blockers.set(k, IDLE_BLOCKER));
|
1135 | }
|
1136 | let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && location.state?._isRedirect !== true;
|
1137 | if (inFlightDataRoutes) {
|
1138 | dataRoutes = inFlightDataRoutes;
|
1139 | inFlightDataRoutes = void 0;
|
1140 | }
|
1141 | if (isUninterruptedRevalidation) {
|
1142 | } else if (pendingAction === "POP" ) {
|
1143 | } else if (pendingAction === "PUSH" ) {
|
1144 | init.history.push(location, location.state);
|
1145 | } else if (pendingAction === "REPLACE" ) {
|
1146 | init.history.replace(location, location.state);
|
1147 | }
|
1148 | let viewTransitionOpts;
|
1149 | if (pendingAction === "POP" ) {
|
1150 | let priorPaths = appliedViewTransitions.get(state.location.pathname);
|
1151 | if (priorPaths && priorPaths.has(location.pathname)) {
|
1152 | viewTransitionOpts = {
|
1153 | currentLocation: state.location,
|
1154 | nextLocation: location
|
1155 | };
|
1156 | } else if (appliedViewTransitions.has(location.pathname)) {
|
1157 | viewTransitionOpts = {
|
1158 | currentLocation: location,
|
1159 | nextLocation: state.location
|
1160 | };
|
1161 | }
|
1162 | } else if (pendingViewTransitionEnabled) {
|
1163 | let toPaths = appliedViewTransitions.get(state.location.pathname);
|
1164 | if (toPaths) {
|
1165 | toPaths.add(location.pathname);
|
1166 | } else {
|
1167 | toPaths = new Set([location.pathname]);
|
1168 | appliedViewTransitions.set(state.location.pathname, toPaths);
|
1169 | }
|
1170 | viewTransitionOpts = {
|
1171 | currentLocation: state.location,
|
1172 | nextLocation: location
|
1173 | };
|
1174 | }
|
1175 | updateState(
|
1176 | {
|
1177 | ...newState,
|
1178 |
|
1179 | actionData,
|
1180 | loaderData,
|
1181 | historyAction: pendingAction,
|
1182 | location,
|
1183 | initialized: true,
|
1184 | navigation: IDLE_NAVIGATION,
|
1185 | revalidation: "idle",
|
1186 | restoreScrollPosition: getSavedScrollPosition(
|
1187 | location,
|
1188 | newState.matches || state.matches
|
1189 | ),
|
1190 | preventScrollReset,
|
1191 | blockers
|
1192 | },
|
1193 | {
|
1194 | viewTransitionOpts,
|
1195 | flushSync: flushSync === true
|
1196 | }
|
1197 | );
|
1198 | pendingAction = "POP" ;
|
1199 | pendingPreventScrollReset = false;
|
1200 | pendingViewTransitionEnabled = false;
|
1201 | isUninterruptedRevalidation = false;
|
1202 | isRevalidationRequired = false;
|
1203 | pendingRevalidationDfd?.resolve();
|
1204 | pendingRevalidationDfd = null;
|
1205 | }
|
1206 | async function navigate(to, opts) {
|
1207 | if (typeof to === "number") {
|
1208 | init.history.go(to);
|
1209 | return;
|
1210 | }
|
1211 | let normalizedPath = normalizeTo(
|
1212 | state.location,
|
1213 | state.matches,
|
1214 | basename,
|
1215 | to,
|
1216 | opts?.fromRouteId,
|
1217 | opts?.relative
|
1218 | );
|
1219 | let { path, submission, error } = normalizeNavigateOptions(
|
1220 | false,
|
1221 | normalizedPath,
|
1222 | opts
|
1223 | );
|
1224 | let currentLocation = state.location;
|
1225 | let nextLocation = createLocation(state.location, path, opts && opts.state);
|
1226 | nextLocation = {
|
1227 | ...nextLocation,
|
1228 | ...init.history.encodeLocation(nextLocation)
|
1229 | };
|
1230 | let userReplace = opts && opts.replace != null ? opts.replace : void 0;
|
1231 | let historyAction = "PUSH" ;
|
1232 | if (userReplace === true) {
|
1233 | historyAction = "REPLACE" ;
|
1234 | } else if (userReplace === false) {
|
1235 | } else if (submission != null && isMutationMethod(submission.formMethod) && submission.formAction === state.location.pathname + state.location.search) {
|
1236 | historyAction = "REPLACE" ;
|
1237 | }
|
1238 | let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : void 0;
|
1239 | let flushSync = (opts && opts.flushSync) === true;
|
1240 | let blockerKey = shouldBlockNavigation({
|
1241 | currentLocation,
|
1242 | nextLocation,
|
1243 | historyAction
|
1244 | });
|
1245 | if (blockerKey) {
|
1246 | updateBlocker(blockerKey, {
|
1247 | state: "blocked",
|
1248 | location: nextLocation,
|
1249 | proceed() {
|
1250 | updateBlocker(blockerKey, {
|
1251 | state: "proceeding",
|
1252 | proceed: void 0,
|
1253 | reset: void 0,
|
1254 | location: nextLocation
|
1255 | });
|
1256 | navigate(to, opts);
|
1257 | },
|
1258 | reset() {
|
1259 | let blockers = new Map(state.blockers);
|
1260 | blockers.set(blockerKey, IDLE_BLOCKER);
|
1261 | updateState({ blockers });
|
1262 | }
|
1263 | });
|
1264 | return;
|
1265 | }
|
1266 | await startNavigation(historyAction, nextLocation, {
|
1267 | submission,
|
1268 |
|
1269 |
|
1270 | pendingError: error,
|
1271 | preventScrollReset,
|
1272 | replace: opts && opts.replace,
|
1273 | enableViewTransition: opts && opts.viewTransition,
|
1274 | flushSync
|
1275 | });
|
1276 | }
|
1277 | function revalidate() {
|
1278 | if (!pendingRevalidationDfd) {
|
1279 | pendingRevalidationDfd = createDeferred();
|
1280 | }
|
1281 | interruptActiveLoads();
|
1282 | updateState({ revalidation: "loading" });
|
1283 | let promise = pendingRevalidationDfd.promise;
|
1284 | if (state.navigation.state === "submitting") {
|
1285 | return promise;
|
1286 | }
|
1287 | if (state.navigation.state === "idle") {
|
1288 | startNavigation(state.historyAction, state.location, {
|
1289 | startUninterruptedRevalidation: true
|
1290 | });
|
1291 | return promise;
|
1292 | }
|
1293 | startNavigation(
|
1294 | pendingAction || state.historyAction,
|
1295 | state.navigation.location,
|
1296 | {
|
1297 | overrideNavigation: state.navigation,
|
1298 |
|
1299 | enableViewTransition: pendingViewTransitionEnabled === true
|
1300 | }
|
1301 | );
|
1302 | return promise;
|
1303 | }
|
1304 | async function startNavigation(historyAction, location, opts) {
|
1305 | pendingNavigationController && pendingNavigationController.abort();
|
1306 | pendingNavigationController = null;
|
1307 | pendingAction = historyAction;
|
1308 | isUninterruptedRevalidation = (opts && opts.startUninterruptedRevalidation) === true;
|
1309 | saveScrollPosition(state.location, state.matches);
|
1310 | pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
1311 | pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
|
1312 | let routesToUse = inFlightDataRoutes || dataRoutes;
|
1313 | let loadingNavigation = opts && opts.overrideNavigation;
|
1314 | let matches = matchRoutes(routesToUse, location, basename);
|
1315 | let flushSync = (opts && opts.flushSync) === true;
|
1316 | let fogOfWar = checkFogOfWar(matches, routesToUse, location.pathname);
|
1317 | if (fogOfWar.active && fogOfWar.matches) {
|
1318 | matches = fogOfWar.matches;
|
1319 | }
|
1320 | if (!matches) {
|
1321 | let { error, notFoundMatches, route } = handleNavigational404(
|
1322 | location.pathname
|
1323 | );
|
1324 | completeNavigation(
|
1325 | location,
|
1326 | {
|
1327 | matches: notFoundMatches,
|
1328 | loaderData: {},
|
1329 | errors: {
|
1330 | [route.id]: error
|
1331 | }
|
1332 | },
|
1333 | { flushSync }
|
1334 | );
|
1335 | return;
|
1336 | }
|
1337 | if (state.initialized && !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
|
1338 | completeNavigation(location, { matches }, { flushSync });
|
1339 | return;
|
1340 | }
|
1341 | pendingNavigationController = new AbortController();
|
1342 | let request = createClientSideRequest(
|
1343 | init.history,
|
1344 | location,
|
1345 | pendingNavigationController.signal,
|
1346 | opts && opts.submission
|
1347 | );
|
1348 | let pendingActionResult;
|
1349 | if (opts && opts.pendingError) {
|
1350 | pendingActionResult = [
|
1351 | findNearestBoundary(matches).route.id,
|
1352 | { type: "error" , error: opts.pendingError }
|
1353 | ];
|
1354 | } else if (opts && opts.submission && isMutationMethod(opts.submission.formMethod)) {
|
1355 | let actionResult = await handleAction(
|
1356 | request,
|
1357 | location,
|
1358 | opts.submission,
|
1359 | matches,
|
1360 | fogOfWar.active,
|
1361 | { replace: opts.replace, flushSync }
|
1362 | );
|
1363 | if (actionResult.shortCircuited) {
|
1364 | return;
|
1365 | }
|
1366 | if (actionResult.pendingActionResult) {
|
1367 | let [routeId, result] = actionResult.pendingActionResult;
|
1368 | if (isErrorResult(result) && isRouteErrorResponse(result.error) && result.error.status === 404) {
|
1369 | pendingNavigationController = null;
|
1370 | completeNavigation(location, {
|
1371 | matches: actionResult.matches,
|
1372 | loaderData: {},
|
1373 | errors: {
|
1374 | [routeId]: result.error
|
1375 | }
|
1376 | });
|
1377 | return;
|
1378 | }
|
1379 | }
|
1380 | matches = actionResult.matches || matches;
|
1381 | pendingActionResult = actionResult.pendingActionResult;
|
1382 | loadingNavigation = getLoadingNavigation(location, opts.submission);
|
1383 | flushSync = false;
|
1384 | fogOfWar.active = false;
|
1385 | request = createClientSideRequest(
|
1386 | init.history,
|
1387 | request.url,
|
1388 | request.signal
|
1389 | );
|
1390 | }
|
1391 | let {
|
1392 | shortCircuited,
|
1393 | matches: updatedMatches,
|
1394 | loaderData,
|
1395 | errors
|
1396 | } = await handleLoaders(
|
1397 | request,
|
1398 | location,
|
1399 | matches,
|
1400 | fogOfWar.active,
|
1401 | loadingNavigation,
|
1402 | opts && opts.submission,
|
1403 | opts && opts.fetcherSubmission,
|
1404 | opts && opts.replace,
|
1405 | opts && opts.initialHydration === true,
|
1406 | flushSync,
|
1407 | pendingActionResult
|
1408 | );
|
1409 | if (shortCircuited) {
|
1410 | return;
|
1411 | }
|
1412 | pendingNavigationController = null;
|
1413 | completeNavigation(location, {
|
1414 | matches: updatedMatches || matches,
|
1415 | ...getActionDataForCommit(pendingActionResult),
|
1416 | loaderData,
|
1417 | errors
|
1418 | });
|
1419 | }
|
1420 | async function handleAction(request, location, submission, matches, isFogOfWar, opts = {}) {
|
1421 | interruptActiveLoads();
|
1422 | let navigation = getSubmittingNavigation(location, submission);
|
1423 | updateState({ navigation }, { flushSync: opts.flushSync === true });
|
1424 | if (isFogOfWar) {
|
1425 | let discoverResult = await discoverRoutes(
|
1426 | matches,
|
1427 | location.pathname,
|
1428 | request.signal
|
1429 | );
|
1430 | if (discoverResult.type === "aborted") {
|
1431 | return { shortCircuited: true };
|
1432 | } else if (discoverResult.type === "error") {
|
1433 | let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
|
1434 | return {
|
1435 | matches: discoverResult.partialMatches,
|
1436 | pendingActionResult: [
|
1437 | boundaryId,
|
1438 | {
|
1439 | type: "error" ,
|
1440 | error: discoverResult.error
|
1441 | }
|
1442 | ]
|
1443 | };
|
1444 | } else if (!discoverResult.matches) {
|
1445 | let { notFoundMatches, error, route } = handleNavigational404(
|
1446 | location.pathname
|
1447 | );
|
1448 | return {
|
1449 | matches: notFoundMatches,
|
1450 | pendingActionResult: [
|
1451 | route.id,
|
1452 | {
|
1453 | type: "error" ,
|
1454 | error
|
1455 | }
|
1456 | ]
|
1457 | };
|
1458 | } else {
|
1459 | matches = discoverResult.matches;
|
1460 | }
|
1461 | }
|
1462 | let result;
|
1463 | let actionMatch = getTargetMatch(matches, location);
|
1464 | if (!actionMatch.route.action && !actionMatch.route.lazy) {
|
1465 | result = {
|
1466 | type: "error" ,
|
1467 | error: getInternalRouterError(405, {
|
1468 | method: request.method,
|
1469 | pathname: location.pathname,
|
1470< |