@tanstack/router-core 0.0.1-beta.36 → 0.0.1-beta.39

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.
@@ -12,64 +12,8 @@ import { createMemoryHistory, createBrowserHistory } from 'history';
12
12
  export { createBrowserHistory, createHashHistory, createMemoryHistory } from 'history';
13
13
  import invariant from 'tiny-invariant';
14
14
  export { default as invariant } from 'tiny-invariant';
15
+ import { createStore, batch } from '@solidjs/reactivity';
15
16
 
16
- /**
17
- * This function returns `a` if `b` is deeply equal.
18
- * If not, it will replace any deeply equal children of `b` with those of `a`.
19
- * This can be used for structural sharing between JSON values for example.
20
- */
21
- function replaceEqualDeep(prev, next) {
22
- if (prev === next) {
23
- return prev;
24
- }
25
- const array = Array.isArray(prev) && Array.isArray(next);
26
- if (array || isPlainObject(prev) && isPlainObject(next)) {
27
- const aSize = array ? prev.length : Object.keys(prev).length;
28
- const bItems = array ? next : Object.keys(next);
29
- const bSize = bItems.length;
30
- const copy = array ? [] : {};
31
- let equalItems = 0;
32
- for (let i = 0; i < bSize; i++) {
33
- const key = array ? i : bItems[i];
34
- copy[key] = replaceEqualDeep(prev[key], next[key]);
35
- if (copy[key] === prev[key]) {
36
- equalItems++;
37
- }
38
- }
39
- return aSize === bSize && equalItems === aSize ? prev : copy;
40
- }
41
- return next;
42
- }
43
-
44
- // Copied from: https://github.com/jonschlinkert/is-plain-object
45
- function isPlainObject(o) {
46
- if (!hasObjectPrototype(o)) {
47
- return false;
48
- }
49
-
50
- // If has modified constructor
51
- const ctor = o.constructor;
52
- if (typeof ctor === 'undefined') {
53
- return true;
54
- }
55
-
56
- // If has modified prototype
57
- const prot = ctor.prototype;
58
- if (!hasObjectPrototype(prot)) {
59
- return false;
60
- }
61
-
62
- // If constructor does not have an Object-specific method
63
- if (!prot.hasOwnProperty('isPrototypeOf')) {
64
- return false;
65
- }
66
-
67
- // Most likely a plain Object
68
- return true;
69
- }
70
- function hasObjectPrototype(o) {
71
- return Object.prototype.toString.call(o) === '[object Object]';
72
- }
73
17
  function last(arr) {
74
18
  return arr[arr.length - 1];
75
19
  }
@@ -78,7 +22,7 @@ function warning(cond, message) {
78
22
  if (typeof console !== 'undefined') console.warn(message);
79
23
  try {
80
24
  throw new Error(message);
81
- } catch (_unused) {}
25
+ } catch {}
82
26
  }
83
27
  return true;
84
28
  }
@@ -115,8 +59,8 @@ function trimPath(path) {
115
59
  return trimPathRight(trimPathLeft(path));
116
60
  }
117
61
  function resolvePath(basepath, base, to) {
118
- base = base.replace(new RegExp("^" + basepath), '/');
119
- to = to.replace(new RegExp("^" + basepath), '/');
62
+ base = base.replace(new RegExp(`^${basepath}`), '/');
63
+ to = to.replace(new RegExp(`^${basepath}`), '/');
120
64
  let baseSegments = parsePathname(base);
121
65
  const toSegments = parsePathname(to);
122
66
  toSegments.forEach((toSegment, index) => {
@@ -197,8 +141,7 @@ function interpolatePath(path, params, leaveWildcard) {
197
141
  return '';
198
142
  }
199
143
  if (segment.type === 'param') {
200
- var _segment$value$substr;
201
- return (_segment$value$substr = params[segment.value.substring(1)]) != null ? _segment$value$substr : '';
144
+ return params[segment.value.substring(1)] ?? '';
202
145
  }
203
146
  return segment.value;
204
147
  }));
@@ -210,16 +153,15 @@ function matchPathname(basepath, currentPathname, matchLocation) {
210
153
  if (matchLocation.to && !pathParams) {
211
154
  return;
212
155
  }
213
- return pathParams != null ? pathParams : {};
156
+ return pathParams ?? {};
214
157
  }
215
158
  function matchByPath(basepath, from, matchLocation) {
216
- var _matchLocation$to;
217
159
  if (!from.startsWith(basepath)) {
218
160
  return undefined;
219
161
  }
220
162
  from = basepath != '/' ? from.substring(basepath.length) : from;
221
163
  const baseSegments = parsePathname(from);
222
- const to = "" + ((_matchLocation$to = matchLocation.to) != null ? _matchLocation$to : '*');
164
+ const to = `${matchLocation.to ?? '*'}`;
223
165
  const routeSegments = parsePathname(to);
224
166
  const params = {};
225
167
  let isMatch = (() => {
@@ -320,134 +262,136 @@ function decode(str) {
320
262
  return out;
321
263
  }
322
264
 
323
- function _extends() {
324
- _extends = Object.assign ? Object.assign.bind() : function (target) {
325
- for (var i = 1; i < arguments.length; i++) {
326
- var source = arguments[i];
327
- for (var key in source) {
328
- if (Object.prototype.hasOwnProperty.call(source, key)) {
329
- target[key] = source[key];
330
- }
331
- }
332
- }
333
- return target;
334
- };
335
- return _extends.apply(this, arguments);
336
- }
337
-
338
- function createRoute(routeConfig, options, parent, router) {
265
+ function createRoute(routeConfig, options, originalIndex, parent, router) {
339
266
  const {
340
267
  id,
341
268
  routeId,
342
269
  path: routePath,
343
270
  fullPath
344
271
  } = routeConfig;
345
- const action = router.state.actions[id] || (() => {
346
- router.state.actions[id] = {
347
- submissions: [],
348
- submit: async (submission, actionOpts) => {
349
- var _actionOpts$invalidat;
350
- if (!route) {
351
- return;
352
- }
353
- const invalidate = (_actionOpts$invalidat = actionOpts == null ? void 0 : actionOpts.invalidate) != null ? _actionOpts$invalidat : true;
354
- if (!(actionOpts != null && actionOpts.multi)) {
355
- action.submissions = action.submissions.filter(d => d.isMulti);
356
- }
357
- const actionState = {
358
- submittedAt: Date.now(),
359
- status: 'pending',
360
- submission,
361
- isMulti: !!(actionOpts != null && actionOpts.multi)
362
- };
363
- action.current = actionState;
364
- action.latest = actionState;
365
- action.submissions.push(actionState);
366
- router.notify();
367
- try {
368
- const res = await (route.options.action == null ? void 0 : route.options.action(submission));
369
- actionState.data = res;
370
- if (invalidate) {
371
- router.invalidateRoute({
372
- to: '.',
373
- fromCurrent: true
374
- });
375
- await router.reload();
376
- }
377
- actionState.status = 'success';
378
- return res;
379
- } catch (err) {
380
- console.error(err);
381
- actionState.error = err;
382
- actionState.status = 'error';
383
- } finally {
384
- router.notify();
385
- }
386
- }
387
- };
388
- return router.state.actions[id];
389
- })();
390
- const loader = router.state.loaders[id] || (() => {
391
- router.state.loaders[id] = {
392
- pending: [],
393
- fetch: async loaderContext => {
394
- if (!route) {
395
- return;
396
- }
397
- const loaderState = {
398
- loadedAt: Date.now(),
399
- loaderContext
400
- };
401
- loader.current = loaderState;
402
- loader.latest = loaderState;
403
- loader.pending.push(loaderState);
404
-
405
- // router.state = {
406
- // ...router.state,
407
- // currentAction: loaderState,
408
- // latestAction: loaderState,
409
- // }
410
-
411
- router.notify();
412
- try {
413
- return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
414
- } finally {
415
- loader.pending = loader.pending.filter(d => d !== loaderState);
416
- // router.removeActionQueue.push({ loader, loaderState })
417
- router.notify();
418
- }
419
- }
420
- };
421
- return router.state.loaders[id];
422
- })();
423
272
  let route = {
424
273
  routeInfo: undefined,
425
274
  routeId: id,
426
275
  routeRouteId: routeId,
276
+ originalIndex,
427
277
  routePath,
428
278
  fullPath,
429
279
  options,
430
280
  router,
431
281
  childRoutes: undefined,
432
282
  parentRoute: parent,
433
- action,
434
- loader: loader,
435
- buildLink: options => {
436
- return router.buildLink(_extends({}, options, {
437
- from: fullPath
438
- }));
439
- },
440
- navigate: options => {
441
- return router.navigate(_extends({}, options, {
442
- from: fullPath
443
- }));
283
+ get action() {
284
+ let action = router.store.actions[id] || (() => {
285
+ router.setStore(s => {
286
+ s.actions[id] = {
287
+ submissions: [],
288
+ submit: async (submission, actionOpts) => {
289
+ if (!route) {
290
+ return;
291
+ }
292
+ const invalidate = (actionOpts == null ? void 0 : actionOpts.invalidate) ?? true;
293
+ const [actionStore, setActionStore] = createStore({
294
+ submittedAt: Date.now(),
295
+ status: 'pending',
296
+ submission,
297
+ isMulti: !!(actionOpts != null && actionOpts.multi)
298
+ });
299
+ router.setStore(s => {
300
+ if (!(actionOpts != null && actionOpts.multi)) {
301
+ s.actions[id].submissions = action.submissions.filter(d => d.isMulti);
302
+ }
303
+ s.actions[id].current = actionStore;
304
+ s.actions[id].latest = actionStore;
305
+ s.actions[id].submissions.push(actionStore);
306
+ });
307
+ try {
308
+ const res = await (route.options.action == null ? void 0 : route.options.action(submission));
309
+ setActionStore(s => {
310
+ s.data = res;
311
+ });
312
+ if (invalidate) {
313
+ router.invalidateRoute({
314
+ to: '.',
315
+ fromCurrent: true
316
+ });
317
+ await router.reload();
318
+ }
319
+ setActionStore(s => {
320
+ s.status = 'success';
321
+ });
322
+ return res;
323
+ } catch (err) {
324
+ console.error(err);
325
+ setActionStore(s => {
326
+ s.error = err;
327
+ s.status = 'error';
328
+ });
329
+ }
330
+ }
331
+ };
332
+ });
333
+ return router.store.actions[id];
334
+ })();
335
+ return action;
444
336
  },
445
- matchRoute: (matchLocation, opts) => {
446
- return router.matchRoute(_extends({}, matchLocation, {
447
- from: fullPath
448
- }), opts);
337
+ get loader() {
338
+ let loader = router.store.loaders[id] || (() => {
339
+ router.setStore(s => {
340
+ s.loaders[id] = {
341
+ pending: [],
342
+ fetch: async loaderContext => {
343
+ if (!route) {
344
+ return;
345
+ }
346
+ const loaderState = {
347
+ loadedAt: Date.now(),
348
+ loaderContext
349
+ };
350
+ router.setStore(s => {
351
+ s.loaders[id].current = loaderState;
352
+ s.loaders[id].latest = loaderState;
353
+ s.loaders[id].pending.push(loaderState);
354
+ });
355
+ try {
356
+ return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
357
+ } finally {
358
+ router.setStore(s => {
359
+ s.loaders[id].pending = s.loaders[id].pending.filter(d => d !== loaderState);
360
+ });
361
+ }
362
+ }
363
+ };
364
+ });
365
+ return router.store.loaders[id];
366
+ })();
367
+ return loader;
449
368
  }
369
+
370
+ // buildLink: (options) => {
371
+ // return router.buildLink({
372
+ // ...options,
373
+ // from: fullPath,
374
+ // } as any) as any
375
+ // },
376
+
377
+ // navigate: (options) => {
378
+ // return router.navigate({
379
+ // ...options,
380
+ // from: fullPath,
381
+ // } as any) as any
382
+ // },
383
+
384
+ // matchRoute: (matchLocation, opts) => {
385
+ // return router.matchRoute(
386
+ // {
387
+ // ...matchLocation,
388
+ // from: fullPath,
389
+ // } as any,
390
+ // opts,
391
+ // ) as any
392
+ // },
450
393
  };
394
+
451
395
  router.options.createRoute == null ? void 0 : router.options.createRoute({
452
396
  router,
453
397
  route
@@ -456,7 +400,7 @@ function createRoute(routeConfig, options, parent, router) {
456
400
  }
457
401
 
458
402
  const rootRouteId = '__root__';
459
- const createRouteConfig = function createRouteConfig(options, children, isRoot, parentId, parentPath) {
403
+ const createRouteConfig = function (options, children, isRoot, parentId, parentPath) {
460
404
  if (options === void 0) {
461
405
  options = {};
462
406
  }
@@ -496,53 +440,194 @@ const createRouteConfig = function createRouteConfig(options, children, isRoot,
496
440
  addChildren: children => createRouteConfig(options, children, false, parentId, parentPath),
497
441
  createRoute: childOptions => createRouteConfig(childOptions, undefined, false, id, fullPath),
498
442
  generate: () => {
499
- invariant(false, "routeConfig.generate() is used by TanStack Router's file-based routing code generation and should not actually be called during runtime. ");
443
+ invariant(false, `routeConfig.generate() is used by TanStack Router's file-based routing code generation and should not actually be called during runtime. `);
500
444
  }
501
445
  };
502
446
  };
503
447
 
448
+ /**
449
+ * This function returns `a` if `b` is deeply equal.
450
+ * If not, it will replace any deeply equal children of `b` with those of `a`.
451
+ * This can be used for structural sharing between JSON values for example.
452
+ */
453
+ function sharedClone(prev, next, touchAll) {
454
+ const things = new Map();
455
+ function recurse(prev, next) {
456
+ if (prev === next) {
457
+ return prev;
458
+ }
459
+ if (things.has(next)) {
460
+ return things.get(next);
461
+ }
462
+ const prevIsArray = Array.isArray(prev);
463
+ const nextIsArray = Array.isArray(next);
464
+ const prevIsObj = isPlainObject(prev);
465
+ const nextIsObj = isPlainObject(next);
466
+ const isArray = prevIsArray && nextIsArray;
467
+ const isObj = prevIsObj && nextIsObj;
468
+ const isSameStructure = isArray || isObj;
469
+
470
+ // Both are arrays or objects
471
+ if (isSameStructure) {
472
+ const aSize = isArray ? prev.length : Object.keys(prev).length;
473
+ const bItems = isArray ? next : Object.keys(next);
474
+ const bSize = bItems.length;
475
+ const copy = isArray ? [] : {};
476
+ let equalItems = 0;
477
+ for (let i = 0; i < bSize; i++) {
478
+ const key = isArray ? i : bItems[i];
479
+ if (copy[key] === prev[key]) {
480
+ equalItems++;
481
+ }
482
+ }
483
+ if (aSize === bSize && equalItems === aSize) {
484
+ things.set(next, prev);
485
+ return prev;
486
+ }
487
+ things.set(next, copy);
488
+ for (let i = 0; i < bSize; i++) {
489
+ const key = isArray ? i : bItems[i];
490
+ if (typeof bItems[i] === 'function') {
491
+ copy[key] = prev[key];
492
+ } else {
493
+ copy[key] = recurse(prev[key], next[key]);
494
+ }
495
+ if (copy[key] === prev[key]) {
496
+ equalItems++;
497
+ }
498
+ }
499
+ return copy;
500
+ }
501
+ if (nextIsArray) {
502
+ const copy = [];
503
+ things.set(next, copy);
504
+ for (let i = 0; i < next.length; i++) {
505
+ copy[i] = recurse(undefined, next[i]);
506
+ }
507
+ return copy;
508
+ }
509
+ if (nextIsObj) {
510
+ const copy = {};
511
+ things.set(next, copy);
512
+ const nextKeys = Object.keys(next);
513
+ for (let i = 0; i < nextKeys.length; i++) {
514
+ const key = nextKeys[i];
515
+ copy[key] = recurse(undefined, next[key]);
516
+ }
517
+ return copy;
518
+ }
519
+ return next;
520
+ }
521
+ return recurse(prev, next);
522
+ }
523
+
524
+ // Copied from: https://github.com/jonschlinkert/is-plain-object
525
+ function isPlainObject(o) {
526
+ if (!hasObjectPrototype(o)) {
527
+ return false;
528
+ }
529
+
530
+ // If has modified constructor
531
+ const ctor = o.constructor;
532
+ if (typeof ctor === 'undefined') {
533
+ return true;
534
+ }
535
+
536
+ // If has modified prototype
537
+ const prot = ctor.prototype;
538
+ if (!hasObjectPrototype(prot)) {
539
+ return false;
540
+ }
541
+
542
+ // If constructor does not have an Object-specific method
543
+ if (!prot.hasOwnProperty('isPrototypeOf')) {
544
+ return false;
545
+ }
546
+
547
+ // Most likely a plain Object
548
+ return true;
549
+ }
550
+ function hasObjectPrototype(o) {
551
+ return Object.prototype.toString.call(o) === '[object Object]';
552
+ }
553
+
504
554
  const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
505
555
  function createRouteMatch(router, route, opts) {
506
- const routeMatch = _extends({}, route, opts, {
507
- router,
556
+ let componentsPromise;
557
+ let dataPromise;
558
+ let latestId = '';
559
+ let resolve = () => {};
560
+ function setLoaderData(loaderData) {
561
+ batch(() => {
562
+ setStore(s => {
563
+ s.routeLoaderData = sharedClone(s.routeLoaderData, loaderData);
564
+ });
565
+ updateLoaderData();
566
+ });
567
+ }
568
+ function updateLoaderData() {
569
+ setStore(s => {
570
+ var _store$parentMatch;
571
+ s.loaderData = sharedClone(s.loaderData, {
572
+ ...((_store$parentMatch = store.parentMatch) == null ? void 0 : _store$parentMatch.store.loaderData),
573
+ ...s.routeLoaderData
574
+ });
575
+ });
576
+ }
577
+ const [store, setStore] = createStore({
508
578
  routeSearch: {},
509
579
  search: {},
510
- childMatches: [],
511
580
  status: 'idle',
512
581
  routeLoaderData: {},
513
582
  loaderData: {},
514
583
  isFetching: false,
515
- isInvalid: false,
584
+ invalid: false,
516
585
  invalidAt: Infinity,
517
- // pendingActions: [],
518
- getIsInvalid: () => {
586
+ get isInvalid() {
519
587
  const now = Date.now();
520
- return routeMatch.isInvalid || routeMatch.invalidAt < now;
521
- },
588
+ return this.invalid || this.invalidAt < now;
589
+ }
590
+ });
591
+ const routeMatch = {
592
+ ...route,
593
+ ...opts,
594
+ store,
595
+ // setStore,
596
+ router,
597
+ childMatches: [],
522
598
  __: {
523
- abortController: new AbortController(),
524
- latestId: '',
525
- resolve: () => {},
526
- notify: () => {
527
- routeMatch.__.resolve();
528
- routeMatch.router.notify();
599
+ setParentMatch: parentMatch => {
600
+ batch(() => {
601
+ setStore(s => {
602
+ s.parentMatch = parentMatch;
603
+ });
604
+ updateLoaderData();
605
+ });
529
606
  },
607
+ abortController: new AbortController(),
530
608
  validate: () => {
531
- var _routeMatch$parentMat, _routeMatch$parentMat2;
609
+ var _store$parentMatch2;
532
610
  // Validate the search params and stabilize them
533
- const parentSearch = (_routeMatch$parentMat = (_routeMatch$parentMat2 = routeMatch.parentMatch) == null ? void 0 : _routeMatch$parentMat2.search) != null ? _routeMatch$parentMat : router.state.currentLocation.search;
611
+ const parentSearch = ((_store$parentMatch2 = store.parentMatch) == null ? void 0 : _store$parentMatch2.store.search) ?? router.store.currentLocation.search;
534
612
  try {
535
- var _validator;
536
- const prevSearch = routeMatch.routeSearch;
613
+ const prevSearch = store.routeSearch;
537
614
  const validator = typeof routeMatch.options.validateSearch === 'object' ? routeMatch.options.validateSearch.parse : routeMatch.options.validateSearch;
538
- let nextSearch = replaceEqualDeep(prevSearch, (_validator = validator == null ? void 0 : validator(parentSearch)) != null ? _validator : {});
615
+ let nextSearch = sharedClone(prevSearch, (validator == null ? void 0 : validator(parentSearch)) ?? {});
616
+ batch(() => {
617
+ // Invalidate route matches when search param stability changes
618
+ if (prevSearch !== nextSearch) {
619
+ setStore(s => s.invalid = true);
620
+ }
539
621
 
540
- // Invalidate route matches when search param stability changes
541
- if (prevSearch !== nextSearch) {
542
- routeMatch.isInvalid = true;
543
- }
544
- routeMatch.routeSearch = nextSearch;
545
- routeMatch.search = replaceEqualDeep(parentSearch, _extends({}, parentSearch, nextSearch));
622
+ // TODO: Alright, do we need batch() here?
623
+ setStore(s => {
624
+ s.routeSearch = nextSearch;
625
+ s.search = sharedClone(parentSearch, {
626
+ ...parentSearch,
627
+ ...nextSearch
628
+ });
629
+ });
630
+ });
546
631
  componentTypes.map(async type => {
547
632
  const component = routeMatch.options[type];
548
633
  if (typeof routeMatch.__[type] !== 'function') {
@@ -555,8 +640,11 @@ function createRouteMatch(router, route, opts) {
555
640
  cause: err
556
641
  });
557
642
  error.code = 'INVALID_SEARCH_PARAMS';
558
- routeMatch.status = 'error';
559
- routeMatch.error = error;
643
+ setStore(s => {
644
+ s.status = 'error';
645
+ s.error = error;
646
+ });
647
+
560
648
  // Do not proceed with loading the route
561
649
  return;
562
650
  }
@@ -567,7 +655,7 @@ function createRouteMatch(router, route, opts) {
567
655
  (_routeMatch$__$abortC = routeMatch.__.abortController) == null ? void 0 : _routeMatch$__$abortC.abort();
568
656
  },
569
657
  invalidate: () => {
570
- routeMatch.isInvalid = true;
658
+ setStore(s => s.invalid = true);
571
659
  },
572
660
  hasLoaders: () => {
573
661
  return !!(route.options.loader || componentTypes.some(d => {
@@ -582,17 +670,17 @@ function createRouteMatch(router, route, opts) {
582
670
  // If this is a preload, add it to the preload cache
583
671
  if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
584
672
  // If the match is currently active, don't preload it
585
- if (router.state.currentMatches.find(d => d.matchId === routeMatch.matchId)) {
673
+ if (router.store.currentMatches.find(d => d.matchId === routeMatch.matchId)) {
586
674
  return;
587
675
  }
588
- router.matchCache[routeMatch.matchId] = {
676
+ router.store.matchCache[routeMatch.matchId] = {
589
677
  gc: now + loaderOpts.gcMaxAge,
590
678
  match: routeMatch
591
679
  };
592
680
  }
593
681
 
594
682
  // If the match is invalid, errored or idle, trigger it to load
595
- if (routeMatch.status === 'success' && routeMatch.getIsInvalid() || routeMatch.status === 'error' || routeMatch.status === 'idle') {
683
+ if (store.status === 'success' && store.isInvalid || store.status === 'error' || store.status === 'idle') {
596
684
  const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
597
685
  await routeMatch.fetch({
598
686
  maxAge
@@ -601,29 +689,30 @@ function createRouteMatch(router, route, opts) {
601
689
  },
602
690
  fetch: async opts => {
603
691
  const loadId = '' + Date.now() + Math.random();
604
- routeMatch.__.latestId = loadId;
692
+ latestId = loadId;
605
693
  const checkLatest = async () => {
606
- if (loadId !== routeMatch.__.latestId) {
694
+ if (loadId !== latestId) {
607
695
  // warning(true, 'Data loader is out of date!')
608
696
  return new Promise(() => {});
609
697
  }
610
698
  };
699
+ batch(() => {
700
+ // If the match was in an error state, set it
701
+ // to a loading state again. Otherwise, keep it
702
+ // as loading or resolved
703
+ if (store.status === 'idle') {
704
+ setStore(s => s.status = 'loading');
705
+ }
611
706
 
612
- // If the match was in an error state, set it
613
- // to a loading state again. Otherwise, keep it
614
- // as loading or resolved
615
- if (routeMatch.status === 'idle') {
616
- routeMatch.status = 'loading';
617
- }
618
-
619
- // We started loading the route, so it's no longer invalid
620
- routeMatch.isInvalid = false;
621
- routeMatch.__.loadPromise = new Promise(async resolve => {
707
+ // We started loading the route, so it's no longer invalid
708
+ setStore(s => s.invalid = false);
709
+ });
710
+ routeMatch.__.loadPromise = new Promise(async r => {
622
711
  // We are now fetching, even if it's in the background of a
623
712
  // resolved state
624
- routeMatch.isFetching = true;
625
- routeMatch.__.resolve = resolve;
626
- routeMatch.__.componentsPromise = (async () => {
713
+ setStore(s => s.isFetching = true);
714
+ resolve = r;
715
+ componentsPromise = (async () => {
627
716
  // then run all component and data loaders in parallel
628
717
  // For each component type, potentially load it asynchronously
629
718
 
@@ -635,49 +724,52 @@ function createRouteMatch(router, route, opts) {
635
724
  }
636
725
  }));
637
726
  })();
638
- routeMatch.__.dataPromise = Promise.resolve().then(async () => {
727
+ dataPromise = Promise.resolve().then(async () => {
639
728
  try {
640
- var _ref, _ref2, _opts$maxAge;
641
729
  if (routeMatch.options.loader) {
642
730
  const data = await router.loadMatchData(routeMatch);
643
731
  await checkLatest();
644
- routeMatch.routeLoaderData = replaceEqualDeep(routeMatch.routeLoaderData, data);
732
+ setLoaderData(data);
645
733
  }
646
- routeMatch.error = undefined;
647
- routeMatch.status = 'success';
648
- routeMatch.updatedAt = Date.now();
649
- routeMatch.invalidAt = routeMatch.updatedAt + ((_ref = (_ref2 = (_opts$maxAge = opts == null ? void 0 : opts.maxAge) != null ? _opts$maxAge : routeMatch.options.loaderMaxAge) != null ? _ref2 : router.options.defaultLoaderMaxAge) != null ? _ref : 0);
650
- return routeMatch.routeLoaderData;
734
+ setStore(s => {
735
+ s.error = undefined;
736
+ s.status = 'success';
737
+ s.updatedAt = Date.now();
738
+ s.invalidAt = s.updatedAt + ((opts == null ? void 0 : opts.maxAge) ?? routeMatch.options.loaderMaxAge ?? router.options.defaultLoaderMaxAge ?? 0);
739
+ });
740
+ return store.routeLoaderData;
651
741
  } catch (err) {
652
742
  await checkLatest();
653
743
  if (process.env.NODE_ENV !== 'production') {
654
744
  console.error(err);
655
745
  }
656
- routeMatch.error = err;
657
- routeMatch.status = 'error';
658
- routeMatch.updatedAt = Date.now();
746
+ setStore(s => {
747
+ s.error = err;
748
+ s.status = 'error';
749
+ s.updatedAt = Date.now();
750
+ });
659
751
  throw err;
660
752
  }
661
753
  });
662
754
  const after = async () => {
663
755
  await checkLatest();
664
- routeMatch.isFetching = false;
756
+ setStore(s => s.isFetching = false);
665
757
  delete routeMatch.__.loadPromise;
666
- routeMatch.__.notify();
758
+ resolve();
667
759
  };
668
760
  try {
669
- await Promise.all([routeMatch.__.componentsPromise, routeMatch.__.dataPromise.catch(() => {})]);
761
+ await Promise.all([componentsPromise, dataPromise.catch(() => {})]);
670
762
  after();
671
- } catch (_unused) {
763
+ } catch {
672
764
  after();
673
765
  }
674
766
  });
675
767
  await routeMatch.__.loadPromise;
676
768
  await checkLatest();
677
769
  }
678
- });
770
+ };
679
771
  if (!routeMatch.hasLoaders()) {
680
- routeMatch.status = 'success';
772
+ setStore(s => s.status = 'success');
681
773
  }
682
774
  return routeMatch;
683
775
  }
@@ -707,7 +799,9 @@ function parseSearchWith(parser) {
707
799
  }
708
800
  function stringifySearchWith(stringify) {
709
801
  return search => {
710
- search = _extends({}, search);
802
+ search = {
803
+ ...search
804
+ };
711
805
  if (search) {
712
806
  Object.keys(search).forEach(key => {
713
807
  const val = search[key];
@@ -723,7 +817,7 @@ function stringifySearchWith(stringify) {
723
817
  });
724
818
  }
725
819
  const searchStr = encode(search).toString();
726
- return searchStr ? "?" + searchStr : '';
820
+ return searchStr ? `?${searchStr}` : '';
727
821
  };
728
822
  }
729
823
 
@@ -742,177 +836,277 @@ function getInitialRouterState() {
742
836
  actions: {},
743
837
  loaders: {},
744
838
  lastUpdated: Date.now(),
745
- isFetching: false,
746
- isPreloading: false
839
+ matchCache: {},
840
+ get isFetching() {
841
+ return this.status === 'loading' || this.currentMatches.some(d => d.store.isFetching);
842
+ },
843
+ get isPreloading() {
844
+ return Object.values(this.matchCache).some(d => d.match.store.isFetching && !this.currentMatches.find(dd => dd.matchId === d.match.matchId));
845
+ }
747
846
  };
748
847
  }
749
848
  function createRouter(userOptions) {
750
- var _userOptions$stringif, _userOptions$parseSea;
751
- const history = (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory();
752
- const originalOptions = _extends({
849
+ const originalOptions = {
753
850
  defaultLoaderGcMaxAge: 5 * 60 * 1000,
754
851
  defaultLoaderMaxAge: 0,
755
852
  defaultPreloadMaxAge: 2000,
756
853
  defaultPreloadDelay: 50,
757
- context: undefined
758
- }, userOptions, {
759
- stringifySearch: (_userOptions$stringif = userOptions == null ? void 0 : userOptions.stringifySearch) != null ? _userOptions$stringif : defaultStringifySearch,
760
- parseSearch: (_userOptions$parseSea = userOptions == null ? void 0 : userOptions.parseSearch) != null ? _userOptions$parseSea : defaultParseSearch
761
- });
762
- let router = {
854
+ context: undefined,
855
+ ...userOptions,
856
+ stringifySearch: (userOptions == null ? void 0 : userOptions.stringifySearch) ?? defaultStringifySearch,
857
+ parseSearch: (userOptions == null ? void 0 : userOptions.parseSearch) ?? defaultParseSearch
858
+ };
859
+ const [store, setStore] = createStore(getInitialRouterState());
860
+ let navigationPromise;
861
+ let startedLoadingAt = Date.now();
862
+ let resolveNavigation = () => {};
863
+ function onFocus() {
864
+ router.load();
865
+ }
866
+ function buildRouteTree(rootRouteConfig) {
867
+ const recurseRoutes = (routeConfigs, parent) => {
868
+ return routeConfigs.map((routeConfig, i) => {
869
+ const routeOptions = routeConfig.options;
870
+ const route = createRoute(routeConfig, routeOptions, i, parent, router);
871
+ const existingRoute = router.routesById[route.routeId];
872
+ if (existingRoute) {
873
+ if (process.env.NODE_ENV !== 'production') {
874
+ console.warn(`Duplicate routes found with id: ${String(route.routeId)}`, router.routesById, route);
875
+ }
876
+ throw new Error();
877
+ }
878
+ router.routesById[route.routeId] = route;
879
+ const children = routeConfig.children;
880
+ route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
881
+ return route;
882
+ });
883
+ };
884
+ const routes = recurseRoutes([rootRouteConfig]);
885
+ return routes[0];
886
+ }
887
+ function parseLocation(location, previousLocation) {
888
+ const parsedSearch = router.options.parseSearch(location.search);
889
+ return {
890
+ pathname: location.pathname,
891
+ searchStr: location.search,
892
+ search: sharedClone(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
893
+ hash: location.hash.split('#').reverse()[0] ?? '',
894
+ href: `${location.pathname}${location.search}${location.hash}`,
895
+ state: location.state,
896
+ key: location.key
897
+ };
898
+ }
899
+ function navigate(location) {
900
+ const next = router.buildNext(location);
901
+ return commitLocation(next, location.replace);
902
+ }
903
+ function buildLocation(dest) {
904
+ var _last, _dest$__preSearchFilt, _dest$__preSearchFilt2, _dest$__postSearchFil;
905
+ if (dest === void 0) {
906
+ dest = {};
907
+ }
908
+ const fromPathname = dest.fromCurrent ? store.latestLocation.pathname : dest.from ?? store.latestLocation.pathname;
909
+ let pathname = resolvePath(router.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
910
+ const fromMatches = router.matchRoutes(store.latestLocation.pathname, {
911
+ strictParseParams: true
912
+ });
913
+ const toMatches = router.matchRoutes(pathname);
914
+ const prevParams = {
915
+ ...((_last = last(fromMatches)) == null ? void 0 : _last.params)
916
+ };
917
+ let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
918
+ if (nextParams) {
919
+ toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
920
+ Object.assign({}, nextParams, fn(nextParams));
921
+ });
922
+ }
923
+ pathname = interpolatePath(pathname, nextParams ?? {});
924
+
925
+ // Pre filters first
926
+ const preFilteredSearch = (_dest$__preSearchFilt = dest.__preSearchFilters) != null && _dest$__preSearchFilt.length ? dest.__preSearchFilters.reduce((prev, next) => next(prev), store.latestLocation.search) : store.latestLocation.search;
927
+
928
+ // Then the link/navigate function
929
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
930
+ : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
931
+ : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
932
+ : {};
933
+
934
+ // Then post filters
935
+ const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
936
+ const search = sharedClone(store.latestLocation.search, postFilteredSearch);
937
+ const searchStr = router.options.stringifySearch(search);
938
+ let hash = dest.hash === true ? store.latestLocation.hash : functionalUpdate(dest.hash, store.latestLocation.hash);
939
+ hash = hash ? `#${hash}` : '';
940
+ return {
941
+ pathname,
942
+ search,
943
+ searchStr,
944
+ state: store.latestLocation.state,
945
+ hash,
946
+ href: `${pathname}${searchStr}${hash}`,
947
+ key: dest.key
948
+ };
949
+ }
950
+ function commitLocation(next, replace) {
951
+ const id = '' + Date.now() + Math.random();
952
+ let nextAction = 'replace';
953
+ if (!replace) {
954
+ nextAction = 'push';
955
+ }
956
+ const isSameUrl = parseLocation(router.history.location).href === next.href;
957
+ if (isSameUrl && !next.key) {
958
+ nextAction = 'replace';
959
+ }
960
+ router.history[nextAction]({
961
+ pathname: next.pathname,
962
+ hash: next.hash,
963
+ search: next.searchStr
964
+ }, {
965
+ id,
966
+ ...next.state
967
+ });
968
+ return navigationPromise = new Promise(resolve => {
969
+ const previousNavigationResolve = resolveNavigation;
970
+ resolveNavigation = () => {
971
+ previousNavigationResolve();
972
+ resolve();
973
+ };
974
+ });
975
+ }
976
+ const router = {
763
977
  types: undefined,
764
978
  // public api
765
- history,
979
+ history: (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory(),
980
+ store,
981
+ setStore,
766
982
  options: originalOptions,
767
- listeners: [],
768
- // Resolved after construction
769
983
  basepath: '',
770
984
  routeTree: undefined,
771
985
  routesById: {},
772
- //
773
- resolveNavigation: () => {},
774
- matchCache: {},
775
- state: getInitialRouterState(),
776
986
  reset: () => {
777
- router.state = getInitialRouterState();
778
- router.notify();
779
- },
780
- startedLoadingAt: Date.now(),
781
- subscribe: listener => {
782
- router.listeners.push(listener);
783
- return () => {
784
- router.listeners = router.listeners.filter(x => x !== listener);
785
- };
987
+ setStore(s => Object.assign(s, getInitialRouterState()));
786
988
  },
787
989
  getRoute: id => {
788
990
  return router.routesById[id];
789
991
  },
790
- notify: () => {
791
- const isFetching = router.state.status === 'loading' || router.state.currentMatches.some(d => d.isFetching);
792
- const isPreloading = Object.values(router.matchCache).some(d => d.match.isFetching && !router.state.currentMatches.find(dd => dd.matchId === d.match.matchId));
793
- if (router.state.isFetching !== isFetching || router.state.isPreloading !== isPreloading) {
794
- router.state = _extends({}, router.state, {
795
- isFetching,
796
- isPreloading
797
- });
798
- }
799
- cascadeLoaderData(router.state.currentMatches);
800
- router.listeners.forEach(listener => listener(router));
801
- },
802
992
  dehydrate: () => {
803
993
  return {
804
- state: _extends({}, pick(router.state, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']), {
805
- currentMatches: router.state.currentMatches.map(match => pick(match, ['matchId', 'status', 'routeLoaderData', 'loaderData', 'isInvalid', 'invalidAt']))
806
- }),
994
+ store: {
995
+ ...pick(store, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
996
+ currentMatches: store.currentMatches.map(match => ({
997
+ matchId: match.matchId,
998
+ store: pick(match.store, ['status', 'routeLoaderData', 'isInvalid', 'invalidAt'])
999
+ }))
1000
+ },
807
1001
  context: router.options.context
808
1002
  };
809
1003
  },
810
- hydrate: dehydratedState => {
811
- // Update the location
812
- router.state.latestLocation = dehydratedState.state.latestLocation;
813
- router.state.currentLocation = dehydratedState.state.currentLocation;
814
-
815
- // Update the context
816
- router.options.context = dehydratedState.context;
1004
+ hydrate: dehydratedRouter => {
1005
+ setStore(s => {
1006
+ // Update the context TODO: make this part of state?
1007
+ router.options.context = dehydratedRouter.context;
817
1008
 
818
- // Match the routes
819
- const currentMatches = router.matchRoutes(router.state.latestLocation.pathname, {
820
- strictParseParams: true
821
- });
822
- currentMatches.forEach((match, index) => {
823
- const dehydratedMatch = dehydratedState.state.currentMatches[index];
824
- invariant(dehydratedMatch, 'Oh no! Dehydrated route matches did not match the active state of the router 😬');
825
- Object.assign(match, dehydratedMatch);
826
- });
827
- currentMatches.forEach(match => match.__.validate());
828
- router.state = _extends({}, router.state, dehydratedState, {
829
- currentMatches
1009
+ // Match the routes
1010
+ const currentMatches = router.matchRoutes(dehydratedRouter.store.latestLocation.pathname, {
1011
+ strictParseParams: true
1012
+ });
1013
+ currentMatches.forEach((match, index) => {
1014
+ const dehydratedMatch = dehydratedRouter.store.currentMatches[index];
1015
+ invariant(dehydratedMatch && dehydratedMatch.matchId === match.matchId, 'Oh no! There was a hydration mismatch when attempting to restore the state of the router! 😬');
1016
+ Object.assign(match, dehydratedMatch);
1017
+ });
1018
+ currentMatches.forEach(match => match.__.validate());
1019
+ Object.assign(s, {
1020
+ ...dehydratedRouter.store,
1021
+ currentMatches
1022
+ });
830
1023
  });
831
1024
  },
832
1025
  mount: () => {
833
- if (!router.state.currentMatches.length) {
834
- router.load();
835
- }
836
- const unsub = router.history.listen(event => {
837
- router.load(router.__.parseLocation(event.location, router.state.latestLocation));
838
- });
1026
+ // Mount only does anything on the client
1027
+ if (!isServer) {
1028
+ // If the router matches are empty, load the matches
1029
+ if (!store.currentMatches.length) {
1030
+ router.load();
1031
+ }
1032
+ const unsub = router.history.listen(event => {
1033
+ router.load(parseLocation(event.location, store.latestLocation));
1034
+ });
839
1035
 
840
- // addEventListener does not exist in React Native, but window does
841
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
842
- if (!isServer && window.addEventListener) {
843
- // Listen to visibillitychange and focus
844
- window.addEventListener('visibilitychange', router.onFocus, false);
845
- window.addEventListener('focus', router.onFocus, false);
846
- }
847
- return () => {
848
- unsub();
849
- if (!isServer && window.removeEventListener) {
850
- // Be sure to unsubscribe if a new handler is set
851
- window.removeEventListener('visibilitychange', router.onFocus);
852
- window.removeEventListener('focus', router.onFocus);
1036
+ // addEventListener does not exist in React Native, but window does
1037
+ // In the future, we might need to invert control here for more adapters
1038
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1039
+ if (window.addEventListener) {
1040
+ // Listen to visibilitychange and focus
1041
+ window.addEventListener('visibilitychange', onFocus, false);
1042
+ window.addEventListener('focus', onFocus, false);
853
1043
  }
854
- };
855
- },
856
- onFocus: () => {
857
- router.load();
1044
+ return () => {
1045
+ unsub();
1046
+ if (window.removeEventListener) {
1047
+ // Be sure to unsubscribe if a new handler is set
1048
+ window.removeEventListener('visibilitychange', onFocus);
1049
+ window.removeEventListener('focus', onFocus);
1050
+ }
1051
+ };
1052
+ }
1053
+ return () => {};
858
1054
  },
859
1055
  update: opts => {
860
- var _trimPath;
861
1056
  const newHistory = (opts == null ? void 0 : opts.history) !== router.history;
862
- if (!router.state.latestLocation || newHistory) {
1057
+ if (!store.latestLocation || newHistory) {
863
1058
  if (opts != null && opts.history) {
864
1059
  router.history = opts.history;
865
1060
  }
866
- router.state.latestLocation = router.__.parseLocation(router.history.location);
867
- router.state.currentLocation = router.state.latestLocation;
1061
+ setStore(s => {
1062
+ s.latestLocation = parseLocation(router.history.location);
1063
+ s.currentLocation = s.latestLocation;
1064
+ });
868
1065
  }
869
1066
  Object.assign(router.options, opts);
870
1067
  const {
871
1068
  basepath,
872
1069
  routeConfig
873
1070
  } = router.options;
874
- router.basepath = "/" + ((_trimPath = trimPath(basepath != null ? basepath : '')) != null ? _trimPath : '');
1071
+ router.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
875
1072
  if (routeConfig) {
876
1073
  router.routesById = {};
877
- router.routeTree = router.__.buildRouteTree(routeConfig);
1074
+ router.routeTree = buildRouteTree(routeConfig);
878
1075
  }
879
1076
  return router;
880
1077
  },
881
1078
  cancelMatches: () => {
882
- var _router$state$pending;
883
- [...router.state.currentMatches, ...((_router$state$pending = router.state.pendingMatches) != null ? _router$state$pending : [])].forEach(match => {
1079
+ [...store.currentMatches, ...(store.pendingMatches || [])].forEach(match => {
884
1080
  match.cancel();
885
1081
  });
886
1082
  },
887
1083
  load: async next => {
888
- const id = Math.random();
889
- router.startedLoadingAt = id;
890
- if (next) {
891
- // Ingest the new location
892
- router.state.latestLocation = next;
893
- }
1084
+ let now = Date.now();
1085
+ const startedAt = now;
1086
+ startedLoadingAt = startedAt;
894
1087
 
895
1088
  // Cancel any pending matches
896
1089
  router.cancelMatches();
1090
+ let matches;
1091
+ batch(() => {
1092
+ if (next) {
1093
+ // Ingest the new location
1094
+ setStore(s => {
1095
+ s.latestLocation = next;
1096
+ });
1097
+ }
897
1098
 
898
- // Match the routes
899
- const matches = router.matchRoutes(router.state.latestLocation.pathname, {
900
- strictParseParams: true
901
- });
902
- if (typeof document !== 'undefined') {
903
- router.state = _extends({}, router.state, {
904
- status: 'loading',
905
- pendingMatches: matches,
906
- pendingLocation: router.state.latestLocation
1099
+ // Match the routes
1100
+ matches = router.matchRoutes(store.latestLocation.pathname, {
1101
+ strictParseParams: true
907
1102
  });
908
- } else {
909
- router.state = _extends({}, router.state, {
910
- status: 'loading',
911
- currentMatches: matches,
912
- currentLocation: router.state.latestLocation
1103
+ console.log('set loading', matches);
1104
+ setStore(s => {
1105
+ s.status = 'loading';
1106
+ s.pendingMatches = matches;
1107
+ s.pendingLocation = store.latestLocation;
913
1108
  });
914
- }
915
- router.notify();
1109
+ });
916
1110
 
917
1111
  // Load the matches
918
1112
  try {
@@ -921,11 +1115,11 @@ function createRouter(userOptions) {
921
1115
  console.log(err);
922
1116
  invariant(false, 'Matches failed to load due to error above ☝️. Navigation cancelled!');
923
1117
  }
924
- if (router.startedLoadingAt !== id) {
925
- // Ignore side-effects of match loading
926
- return router.navigationPromise;
1118
+ if (startedLoadingAt !== startedAt) {
1119
+ // Ignore side-effects of outdated side-effects
1120
+ return navigationPromise;
927
1121
  }
928
- const previousMatches = router.state.currentMatches;
1122
+ const previousMatches = store.currentMatches;
929
1123
  const exiting = [],
930
1124
  staying = [];
931
1125
  previousMatches.forEach(d => {
@@ -938,22 +1132,21 @@ function createRouter(userOptions) {
938
1132
  const entering = matches.filter(d => {
939
1133
  return !previousMatches.find(dd => dd.matchId === d.matchId);
940
1134
  });
941
- const now = Date.now();
1135
+ now = Date.now();
942
1136
  exiting.forEach(d => {
943
- var _ref, _d$options$loaderGcMa, _ref2, _d$options$loaderMaxA;
944
1137
  d.__.onExit == null ? void 0 : d.__.onExit({
945
1138
  params: d.params,
946
- search: d.routeSearch
1139
+ search: d.store.routeSearch
947
1140
  });
948
1141
 
949
1142
  // Clear idle error states when match leaves
950
- if (d.status === 'error' && !d.isFetching) {
951
- d.status = 'idle';
952
- d.error = undefined;
1143
+ if (d.store.status === 'error' && !d.store.isFetching) {
1144
+ d.store.status = 'idle';
1145
+ d.store.error = undefined;
953
1146
  }
954
- const gc = Math.max((_ref = (_d$options$loaderGcMa = d.options.loaderGcMaxAge) != null ? _d$options$loaderGcMa : router.options.defaultLoaderGcMaxAge) != null ? _ref : 0, (_ref2 = (_d$options$loaderMaxA = d.options.loaderMaxAge) != null ? _d$options$loaderMaxA : router.options.defaultLoaderMaxAge) != null ? _ref2 : 0);
1147
+ const gc = Math.max(d.options.loaderGcMaxAge ?? router.options.defaultLoaderGcMaxAge ?? 0, d.options.loaderMaxAge ?? router.options.defaultLoaderMaxAge ?? 0);
955
1148
  if (gc > 0) {
956
- router.matchCache[d.matchId] = {
1149
+ store.matchCache[d.matchId] = {
957
1150
  gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
958
1151
  match: d
959
1152
  };
@@ -962,59 +1155,64 @@ function createRouter(userOptions) {
962
1155
  staying.forEach(d => {
963
1156
  d.options.onTransition == null ? void 0 : d.options.onTransition({
964
1157
  params: d.params,
965
- search: d.routeSearch
1158
+ search: d.store.routeSearch
966
1159
  });
967
1160
  });
968
1161
  entering.forEach(d => {
969
1162
  d.__.onExit = d.options.onLoaded == null ? void 0 : d.options.onLoaded({
970
1163
  params: d.params,
971
- search: d.search
1164
+ search: d.store.search
972
1165
  });
973
- delete router.matchCache[d.matchId];
1166
+ delete store.matchCache[d.matchId];
974
1167
  });
975
- if (router.startedLoadingAt !== id) {
1168
+ if (startedLoadingAt !== startedAt) {
976
1169
  // Ignore side-effects of match loading
977
1170
  return;
978
1171
  }
979
1172
  matches.forEach(match => {
980
1173
  // Clear actions
981
1174
  if (match.action) {
1175
+ // TODO: Check reactivity here
982
1176
  match.action.current = undefined;
983
1177
  match.action.submissions = [];
984
1178
  }
985
1179
  });
986
- router.state = _extends({}, router.state, {
987
- status: 'idle',
988
- currentLocation: router.state.latestLocation,
989
- currentMatches: matches,
990
- pendingLocation: undefined,
991
- pendingMatches: undefined
1180
+ setStore(s => {
1181
+ console.log('set', matches);
1182
+ Object.assign(s, {
1183
+ status: 'idle',
1184
+ currentLocation: store.latestLocation,
1185
+ currentMatches: matches,
1186
+ pendingLocation: undefined,
1187
+ pendingMatches: undefined
1188
+ });
992
1189
  });
993
- router.notify();
994
- router.resolveNavigation();
1190
+ resolveNavigation();
995
1191
  },
996
1192
  cleanMatchCache: () => {
997
1193
  const now = Date.now();
998
- Object.keys(router.matchCache).forEach(matchId => {
999
- const entry = router.matchCache[matchId];
1194
+ setStore(s => {
1195
+ Object.keys(s.matchCache).forEach(matchId => {
1196
+ const entry = s.matchCache[matchId];
1000
1197
 
1001
- // Don't remove loading matches
1002
- if (entry.match.status === 'loading') {
1003
- return;
1004
- }
1198
+ // Don't remove loading matches
1199
+ if (entry.match.store.status === 'loading') {
1200
+ return;
1201
+ }
1005
1202
 
1006
- // Do not remove successful matches that are still valid
1007
- if (entry.gc > 0 && entry.gc > now) {
1008
- return;
1009
- }
1203
+ // Do not remove successful matches that are still valid
1204
+ if (entry.gc > 0 && entry.gc > now) {
1205
+ return;
1206
+ }
1010
1207
 
1011
- // Everything else gets removed
1012
- delete router.matchCache[matchId];
1208
+ // Everything else gets removed
1209
+ delete s.matchCache[matchId];
1210
+ });
1013
1211
  });
1014
1212
  },
1015
- loadRoute: async function loadRoute(navigateOpts) {
1213
+ loadRoute: async function (navigateOpts) {
1016
1214
  if (navigateOpts === void 0) {
1017
- navigateOpts = router.state.latestLocation;
1215
+ navigateOpts = store.latestLocation;
1018
1216
  }
1019
1217
  const next = router.buildNext(navigateOpts);
1020
1218
  const matches = router.matchRoutes(next.pathname, {
@@ -1023,10 +1221,9 @@ function createRouter(userOptions) {
1023
1221
  await router.loadMatches(matches);
1024
1222
  return matches;
1025
1223
  },
1026
- preloadRoute: async function preloadRoute(navigateOpts, loaderOpts) {
1027
- var _ref3, _ref4, _loaderOpts$maxAge, _ref5, _ref6, _loaderOpts$gcMaxAge;
1224
+ preloadRoute: async function (navigateOpts, loaderOpts) {
1028
1225
  if (navigateOpts === void 0) {
1029
- navigateOpts = router.state.latestLocation;
1226
+ navigateOpts = store.latestLocation;
1030
1227
  }
1031
1228
  const next = router.buildNext(navigateOpts);
1032
1229
  const matches = router.matchRoutes(next.pathname, {
@@ -1034,28 +1231,27 @@ function createRouter(userOptions) {
1034
1231
  });
1035
1232
  await router.loadMatches(matches, {
1036
1233
  preload: true,
1037
- maxAge: (_ref3 = (_ref4 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref4 : router.options.defaultLoaderMaxAge) != null ? _ref3 : 0,
1038
- gcMaxAge: (_ref5 = (_ref6 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref6 : router.options.defaultLoaderGcMaxAge) != null ? _ref5 : 0
1234
+ maxAge: loaderOpts.maxAge ?? router.options.defaultPreloadMaxAge ?? router.options.defaultLoaderMaxAge ?? 0,
1235
+ gcMaxAge: loaderOpts.gcMaxAge ?? router.options.defaultPreloadGcMaxAge ?? router.options.defaultLoaderGcMaxAge ?? 0
1039
1236
  });
1040
1237
  return matches;
1041
1238
  },
1042
1239
  matchRoutes: (pathname, opts) => {
1043
- var _router$state$pending2;
1044
1240
  router.cleanMatchCache();
1045
1241
  const matches = [];
1046
1242
  if (!router.routeTree) {
1047
1243
  return matches;
1048
1244
  }
1049
- const existingMatches = [...router.state.currentMatches, ...((_router$state$pending2 = router.state.pendingMatches) != null ? _router$state$pending2 : [])];
1245
+ const existingMatches = [...store.currentMatches, ...(store.pendingMatches ?? [])];
1050
1246
  const recurse = async routes => {
1051
- var _parentMatch$params, _router$options$filte, _foundRoute$childRout;
1247
+ var _foundRoute$childRout;
1052
1248
  const parentMatch = last(matches);
1053
- let params = (_parentMatch$params = parentMatch == null ? void 0 : parentMatch.params) != null ? _parentMatch$params : {};
1054
- const filteredRoutes = (_router$options$filte = router.options.filterRoutes == null ? void 0 : router.options.filterRoutes(routes)) != null ? _router$options$filte : routes;
1249
+ let params = (parentMatch == null ? void 0 : parentMatch.params) ?? {};
1250
+ const filteredRoutes = (router.options.filterRoutes == null ? void 0 : router.options.filterRoutes(routes)) ?? routes;
1055
1251
  let foundRoutes = [];
1056
1252
  const findMatchInRoutes = (parentRoutes, routes) => {
1057
1253
  routes.some(route => {
1058
- var _route$childRoutes, _route$childRoutes2, _route$options$caseSe;
1254
+ var _route$childRoutes, _route$childRoutes2;
1059
1255
  if (!route.routePath && (_route$childRoutes = route.childRoutes) != null && _route$childRoutes.length) {
1060
1256
  return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
1061
1257
  }
@@ -1063,28 +1259,21 @@ function createRouter(userOptions) {
1063
1259
  const matchParams = matchPathname(router.basepath, pathname, {
1064
1260
  to: route.fullPath,
1065
1261
  fuzzy,
1066
- caseSensitive: (_route$options$caseSe = route.options.caseSensitive) != null ? _route$options$caseSe : router.options.caseSensitive
1262
+ caseSensitive: route.options.caseSensitive ?? router.options.caseSensitive
1067
1263
  });
1068
-
1069
- // console.log(
1070
- // router.basepath,
1071
- // route.fullPath,
1072
- // fuzzy,
1073
- // pathname,
1074
- // matchParams,
1075
- // )
1076
-
1077
1264
  if (matchParams) {
1078
1265
  let parsedParams;
1079
1266
  try {
1080
- var _route$options$parseP;
1081
- parsedParams = (_route$options$parseP = route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) != null ? _route$options$parseP : matchParams;
1267
+ parsedParams = (route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) ?? matchParams;
1082
1268
  } catch (err) {
1083
1269
  if (opts != null && opts.strictParseParams) {
1084
1270
  throw err;
1085
1271
  }
1086
1272
  }
1087
- params = _extends({}, params, parsedParams);
1273
+ params = {
1274
+ ...params,
1275
+ ...parsedParams
1276
+ };
1088
1277
  }
1089
1278
  if (!!matchParams) {
1090
1279
  foundRoutes = [...parentRoutes, route];
@@ -1098,10 +1287,10 @@ function createRouter(userOptions) {
1098
1287
  return;
1099
1288
  }
1100
1289
  foundRoutes.forEach(foundRoute => {
1101
- var _router$matchCache$ma;
1290
+ var _store$matchCache$mat;
1102
1291
  const interpolatedPath = interpolatePath(foundRoute.routePath, params);
1103
1292
  const matchId = interpolatePath(foundRoute.routeId, params, true);
1104
- const match = existingMatches.find(d => d.matchId === matchId) || ((_router$matchCache$ma = router.matchCache[matchId]) == null ? void 0 : _router$matchCache$ma.match) || createRouteMatch(router, foundRoute, {
1293
+ const match = existingMatches.find(d => d.matchId === matchId) || ((_store$matchCache$mat = store.matchCache[matchId]) == null ? void 0 : _store$matchCache$mat.match) || createRouteMatch(router, foundRoute, {
1105
1294
  parentMatch,
1106
1295
  matchId,
1107
1296
  params,
@@ -1115,7 +1304,7 @@ function createRouter(userOptions) {
1115
1304
  }
1116
1305
  };
1117
1306
  recurse([router.routeTree]);
1118
- cascadeLoaderData(matches);
1307
+ linkMatches(matches);
1119
1308
  return matches;
1120
1309
  },
1121
1310
  loadMatches: async (resolvedMatches, loaderOpts) => {
@@ -1140,32 +1329,31 @@ function createRouter(userOptions) {
1140
1329
  }));
1141
1330
  const matchPromises = resolvedMatches.map(async match => {
1142
1331
  var _search$__data;
1143
- const search = match.search;
1332
+ const search = match.store.search;
1144
1333
  if ((_search$__data = search.__data) != null && _search$__data.matchId && search.__data.matchId !== match.matchId) {
1145
1334
  return;
1146
1335
  }
1147
1336
  match.load(loaderOpts);
1148
- if (match.status !== 'success' && match.__.loadPromise) {
1337
+ if (match.store.status !== 'success' && match.__.loadPromise) {
1149
1338
  // Wait for the first sign of activity from the match
1150
1339
  await match.__.loadPromise;
1151
1340
  }
1152
1341
  });
1153
- router.notify();
1154
1342
  await Promise.all(matchPromises);
1155
1343
  },
1156
1344
  loadMatchData: async routeMatch => {
1157
1345
  if (isServer || !router.options.useServerData) {
1158
- var _await$routeMatch$opt;
1159
- return (_await$routeMatch$opt = await (routeMatch.options.loader == null ? void 0 : routeMatch.options.loader({
1346
+ return (await (routeMatch.options.loader == null ? void 0 : routeMatch.options.loader({
1160
1347
  // parentLoaderPromise: routeMatch.parentMatch?.__.dataPromise,
1161
1348
  params: routeMatch.params,
1162
- search: routeMatch.routeSearch,
1349
+ search: routeMatch.store.routeSearch,
1163
1350
  signal: routeMatch.__.abortController.signal
1164
- }))) != null ? _await$routeMatch$opt : {};
1351
+ }))) || {};
1165
1352
  } else {
1166
1353
  const next = router.buildNext({
1167
1354
  to: '.',
1168
- search: d => _extends({}, d != null ? d : {}, {
1355
+ search: d => ({
1356
+ ...(d ?? {}),
1169
1357
  __data: {
1170
1358
  matchId: routeMatch.matchId
1171
1359
  }
@@ -1194,16 +1382,15 @@ function createRouter(userOptions) {
1194
1382
  }
1195
1383
  },
1196
1384
  invalidateRoute: opts => {
1197
- var _router$state$pending3;
1198
1385
  const next = router.buildNext(opts);
1199
1386
  const unloadedMatchIds = router.matchRoutes(next.pathname).map(d => d.matchId);
1200
- [...router.state.currentMatches, ...((_router$state$pending3 = router.state.pendingMatches) != null ? _router$state$pending3 : [])].forEach(match => {
1387
+ [...store.currentMatches, ...(store.pendingMatches ?? [])].forEach(match => {
1201
1388
  if (unloadedMatchIds.includes(match.matchId)) {
1202
1389
  match.invalidate();
1203
1390
  }
1204
1391
  });
1205
1392
  },
1206
- reload: () => router.__.navigate({
1393
+ reload: () => navigate({
1207
1394
  fromCurrent: true,
1208
1395
  replace: true,
1209
1396
  search: true
@@ -1212,26 +1399,28 @@ function createRouter(userOptions) {
1212
1399
  return resolvePath(router.basepath, from, cleanPath(path));
1213
1400
  },
1214
1401
  matchRoute: (location, opts) => {
1215
- var _location$from;
1216
1402
  // const location = router.buildNext(opts)
1217
1403
 
1218
- location = _extends({}, location, {
1219
- to: location.to ? router.resolvePath((_location$from = location.from) != null ? _location$from : '', location.to) : undefined
1220
- });
1404
+ location = {
1405
+ ...location,
1406
+ to: location.to ? router.resolvePath(location.from ?? '', location.to) : undefined
1407
+ };
1221
1408
  const next = router.buildNext(location);
1222
1409
  if (opts != null && opts.pending) {
1223
- if (!router.state.pendingLocation) {
1410
+ if (!store.pendingLocation) {
1224
1411
  return false;
1225
1412
  }
1226
- return !!matchPathname(router.basepath, router.state.pendingLocation.pathname, _extends({}, opts, {
1413
+ return !!matchPathname(router.basepath, store.pendingLocation.pathname, {
1414
+ ...opts,
1227
1415
  to: next.pathname
1228
- }));
1416
+ });
1229
1417
  }
1230
- return !!matchPathname(router.basepath, router.state.currentLocation.pathname, _extends({}, opts, {
1418
+ return matchPathname(router.basepath, store.currentLocation.pathname, {
1419
+ ...opts,
1231
1420
  to: next.pathname
1232
- }));
1421
+ });
1233
1422
  },
1234
- navigate: async _ref7 => {
1423
+ navigate: async _ref => {
1235
1424
  let {
1236
1425
  from,
1237
1426
  to = '.',
@@ -1239,7 +1428,7 @@ function createRouter(userOptions) {
1239
1428
  hash,
1240
1429
  replace,
1241
1430
  params
1242
- } = _ref7;
1431
+ } = _ref;
1243
1432
  // If this link simply reloads the current route,
1244
1433
  // make sure it has a new key so it will trigger a data refresh
1245
1434
 
@@ -1249,11 +1438,11 @@ function createRouter(userOptions) {
1249
1438
  const fromString = String(from);
1250
1439
  let isExternal;
1251
1440
  try {
1252
- new URL("" + toString);
1441
+ new URL(`${toString}`);
1253
1442
  isExternal = true;
1254
1443
  } catch (e) {}
1255
1444
  invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
1256
- return router.__.navigate({
1445
+ return navigate({
1257
1446
  from: fromString,
1258
1447
  to: toString,
1259
1448
  search,
@@ -1262,8 +1451,7 @@ function createRouter(userOptions) {
1262
1451
  params
1263
1452
  });
1264
1453
  },
1265
- buildLink: _ref8 => {
1266
- var _preload, _ref9;
1454
+ buildLink: _ref2 => {
1267
1455
  let {
1268
1456
  from,
1269
1457
  to = '.',
@@ -1278,7 +1466,7 @@ function createRouter(userOptions) {
1278
1466
  preloadGcMaxAge: userPreloadGcMaxAge,
1279
1467
  preloadDelay: userPreloadDelay,
1280
1468
  disabled
1281
- } = _ref8;
1469
+ } = _ref2;
1282
1470
  // If this link simply reloads the current route,
1283
1471
  // make sure it has a new key so it will trigger a data refresh
1284
1472
 
@@ -1286,7 +1474,7 @@ function createRouter(userOptions) {
1286
1474
  // null for LinkUtils
1287
1475
 
1288
1476
  try {
1289
- new URL("" + to);
1477
+ new URL(`${to}`);
1290
1478
  return {
1291
1479
  type: 'external',
1292
1480
  href: to
@@ -1301,15 +1489,15 @@ function createRouter(userOptions) {
1301
1489
  replace
1302
1490
  };
1303
1491
  const next = router.buildNext(nextOpts);
1304
- preload = (_preload = preload) != null ? _preload : router.options.defaultPreload;
1305
- const preloadDelay = (_ref9 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref9 : 0;
1492
+ preload = preload ?? router.options.defaultPreload;
1493
+ const preloadDelay = userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0;
1306
1494
 
1307
1495
  // Compare path/hash for matches
1308
- const pathIsEqual = router.state.currentLocation.pathname === next.pathname;
1309
- const currentPathSplit = router.state.currentLocation.pathname.split('/');
1496
+ const pathIsEqual = store.currentLocation.pathname === next.pathname;
1497
+ const currentPathSplit = store.currentLocation.pathname.split('/');
1310
1498
  const nextPathSplit = next.pathname.split('/');
1311
1499
  const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
1312
- const hashIsEqual = router.state.currentLocation.hash === next.hash;
1500
+ const hashIsEqual = store.currentLocation.hash === next.hash;
1313
1501
  // Combine the matches based on user options
1314
1502
  const pathTest = activeOptions != null && activeOptions.exact ? pathIsEqual : pathIsFuzzyEqual;
1315
1503
  const hashTest = activeOptions != null && activeOptions.includeHash ? hashIsEqual : true;
@@ -1325,8 +1513,8 @@ function createRouter(userOptions) {
1325
1513
  router.invalidateRoute(nextOpts);
1326
1514
  }
1327
1515
 
1328
- // All is well? Navigate!)
1329
- router.__.navigate(nextOpts);
1516
+ // All is well? Navigate!
1517
+ navigate(nextOpts);
1330
1518
  }
1331
1519
  };
1332
1520
 
@@ -1379,143 +1567,15 @@ function createRouter(userOptions) {
1379
1567
  };
1380
1568
  },
1381
1569
  buildNext: opts => {
1382
- const next = router.__.buildLocation(opts);
1570
+ const next = buildLocation(opts);
1383
1571
  const matches = router.matchRoutes(next.pathname);
1384
- const __preSearchFilters = matches.map(match => {
1385
- var _match$options$preSea;
1386
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
1387
- }).flat().filter(Boolean);
1388
- const __postSearchFilters = matches.map(match => {
1389
- var _match$options$postSe;
1390
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
1391
- }).flat().filter(Boolean);
1392
- return router.__.buildLocation(_extends({}, opts, {
1572
+ const __preSearchFilters = matches.map(match => match.options.preSearchFilters ?? []).flat().filter(Boolean);
1573
+ const __postSearchFilters = matches.map(match => match.options.postSearchFilters ?? []).flat().filter(Boolean);
1574
+ return buildLocation({
1575
+ ...opts,
1393
1576
  __preSearchFilters,
1394
1577
  __postSearchFilters
1395
- }));
1396
- },
1397
- __: {
1398
- buildRouteTree: rootRouteConfig => {
1399
- const recurseRoutes = (routeConfigs, parent) => {
1400
- return routeConfigs.map(routeConfig => {
1401
- const routeOptions = routeConfig.options;
1402
- const route = createRoute(routeConfig, routeOptions, parent, router);
1403
- const existingRoute = router.routesById[route.routeId];
1404
- if (existingRoute) {
1405
- if (process.env.NODE_ENV !== 'production') {
1406
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
1407
- }
1408
- throw new Error();
1409
- }
1410
- router.routesById[route.routeId] = route;
1411
- const children = routeConfig.children;
1412
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
1413
- return route;
1414
- });
1415
- };
1416
- const routes = recurseRoutes([rootRouteConfig]);
1417
- return routes[0];
1418
- },
1419
- parseLocation: (location, previousLocation) => {
1420
- var _location$hash$split$;
1421
- const parsedSearch = router.options.parseSearch(location.search);
1422
- return {
1423
- pathname: location.pathname,
1424
- searchStr: location.search,
1425
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
1426
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
1427
- href: "" + location.pathname + location.search + location.hash,
1428
- state: location.state,
1429
- key: location.key
1430
- };
1431
- },
1432
- navigate: location => {
1433
- const next = router.buildNext(location);
1434
- return router.__.commitLocation(next, location.replace);
1435
- },
1436
- buildLocation: function buildLocation(dest) {
1437
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
1438
- if (dest === void 0) {
1439
- dest = {};
1440
- }
1441
- const fromPathname = dest.fromCurrent ? router.state.latestLocation.pathname : (_dest$from = dest.from) != null ? _dest$from : router.state.latestLocation.pathname;
1442
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
1443
- const fromMatches = router.matchRoutes(router.state.latestLocation.pathname, {
1444
- strictParseParams: true
1445
- });
1446
- const toMatches = router.matchRoutes(pathname);
1447
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1448
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1449
- if (nextParams) {
1450
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
1451
- Object.assign({}, nextParams, fn(nextParams));
1452
- });
1453
- }
1454
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {});
1455
-
1456
- // Pre filters first
1457
- const preFilteredSearch = (_dest$__preSearchFilt = dest.__preSearchFilters) != null && _dest$__preSearchFilt.length ? dest.__preSearchFilters.reduce((prev, next) => next(prev), router.state.latestLocation.search) : router.state.latestLocation.search;
1458
-
1459
- // Then the link/navigate function
1460
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1461
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
1462
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
1463
- : {};
1464
-
1465
- // Then post filters
1466
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1467
- const search = replaceEqualDeep(router.state.latestLocation.search, postFilteredSearch);
1468
- const searchStr = router.options.stringifySearch(search);
1469
- let hash = dest.hash === true ? router.state.latestLocation.hash : functionalUpdate(dest.hash, router.state.latestLocation.hash);
1470
- hash = hash ? "#" + hash : '';
1471
- return {
1472
- pathname,
1473
- search,
1474
- searchStr,
1475
- state: router.state.latestLocation.state,
1476
- hash,
1477
- href: "" + pathname + searchStr + hash,
1478
- key: dest.key
1479
- };
1480
- },
1481
- commitLocation: (next, replace) => {
1482
- const id = '' + Date.now() + Math.random();
1483
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
1484
- let nextAction = 'replace';
1485
- if (!replace) {
1486
- nextAction = 'push';
1487
- }
1488
- const isSameUrl = router.__.parseLocation(history.location).href === next.href;
1489
- if (isSameUrl && !next.key) {
1490
- nextAction = 'replace';
1491
- }
1492
- if (nextAction === 'replace') {
1493
- history.replace({
1494
- pathname: next.pathname,
1495
- hash: next.hash,
1496
- search: next.searchStr
1497
- }, _extends({
1498
- id
1499
- }, next.state));
1500
- } else {
1501
- history.push({
1502
- pathname: next.pathname,
1503
- hash: next.hash,
1504
- search: next.searchStr
1505
- }, {
1506
- id
1507
- });
1508
- }
1509
- router.navigationPromise = new Promise(resolve => {
1510
- const previousNavigationResolve = router.resolveNavigation;
1511
- router.resolveNavigation = () => {
1512
- previousNavigationResolve();
1513
- resolve();
1514
- delete router.navigationPromise;
1515
- };
1516
- });
1517
- return router.navigationPromise;
1518
- }
1578
+ });
1519
1579
  }
1520
1580
  };
1521
1581
  router.update(userOptions);
@@ -1527,14 +1587,16 @@ function createRouter(userOptions) {
1527
1587
  function isCtrlEvent(e) {
1528
1588
  return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
1529
1589
  }
1530
- function cascadeLoaderData(matches) {
1590
+ function linkMatches(matches) {
1531
1591
  matches.forEach((match, index) => {
1532
1592
  const parent = matches[index - 1];
1533
1593
  if (parent) {
1534
- match.loaderData = replaceEqualDeep(match.loaderData, _extends({}, parent.loaderData, match.routeLoaderData));
1594
+ match.__.setParentMatch(parent);
1595
+ } else {
1596
+ match.__.setParentMatch(undefined);
1535
1597
  }
1536
1598
  });
1537
1599
  }
1538
1600
 
1539
- export { cleanPath, createRoute, createRouteConfig, createRouteMatch, createRouter, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, joinPaths, last, matchByPath, matchPathname, parsePathname, parseSearchWith, pick, replaceEqualDeep, resolvePath, rootRouteId, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, warning };
1601
+ export { cleanPath, createRoute, createRouteConfig, createRouteMatch, createRouter, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, joinPaths, last, matchByPath, matchPathname, parsePathname, parseSearchWith, pick, resolvePath, rootRouteId, sharedClone, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, warning };
1540
1602
  //# sourceMappingURL=index.js.map