@furystack/shades 13.2.1 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/CHANGELOG.md +150 -0
  2. package/esm/components/define-nested-routes.d.ts +27 -0
  3. package/esm/components/define-nested-routes.d.ts.map +1 -0
  4. package/esm/components/define-nested-routes.js +26 -0
  5. package/esm/components/define-nested-routes.js.map +1 -0
  6. package/esm/components/define-nested-routes.spec.d.ts +2 -0
  7. package/esm/components/define-nested-routes.spec.d.ts.map +1 -0
  8. package/esm/components/define-nested-routes.spec.js +81 -0
  9. package/esm/components/define-nested-routes.spec.js.map +1 -0
  10. package/esm/components/index.d.ts +3 -3
  11. package/esm/components/index.d.ts.map +1 -1
  12. package/esm/components/index.js +3 -3
  13. package/esm/components/index.js.map +1 -1
  14. package/esm/components/nested-hooks.d.ts +62 -0
  15. package/esm/components/nested-hooks.d.ts.map +1 -0
  16. package/esm/components/nested-hooks.js +73 -0
  17. package/esm/components/nested-hooks.js.map +1 -0
  18. package/esm/components/nested-hooks.spec.d.ts +2 -0
  19. package/esm/components/nested-hooks.spec.d.ts.map +1 -0
  20. package/esm/components/nested-hooks.spec.js +211 -0
  21. package/esm/components/nested-hooks.spec.js.map +1 -0
  22. package/esm/components/nested-navigate.d.ts +52 -21
  23. package/esm/components/nested-navigate.d.ts.map +1 -1
  24. package/esm/components/nested-navigate.js +32 -17
  25. package/esm/components/nested-navigate.js.map +1 -1
  26. package/esm/components/nested-navigate.spec.js +102 -12
  27. package/esm/components/nested-navigate.spec.js.map +1 -1
  28. package/esm/components/nested-replace.d.ts +36 -0
  29. package/esm/components/nested-replace.d.ts.map +1 -0
  30. package/esm/components/nested-replace.js +38 -0
  31. package/esm/components/nested-replace.js.map +1 -0
  32. package/esm/components/nested-replace.spec.d.ts +2 -0
  33. package/esm/components/nested-replace.spec.d.ts.map +1 -0
  34. package/esm/components/nested-replace.spec.js +59 -0
  35. package/esm/components/nested-replace.spec.js.map +1 -0
  36. package/esm/components/nested-route-link.d.ts +36 -26
  37. package/esm/components/nested-route-link.d.ts.map +1 -1
  38. package/esm/components/nested-route-link.js +17 -19
  39. package/esm/components/nested-route-link.js.map +1 -1
  40. package/esm/components/nested-route-link.spec.js +61 -11
  41. package/esm/components/nested-route-link.spec.js.map +1 -1
  42. package/esm/components/nested-route-types.d.ts +79 -2
  43. package/esm/components/nested-route-types.d.ts.map +1 -1
  44. package/esm/components/nested-router.d.ts +77 -7
  45. package/esm/components/nested-router.d.ts.map +1 -1
  46. package/esm/components/nested-router.js +137 -11
  47. package/esm/components/nested-router.js.map +1 -1
  48. package/esm/components/nested-router.spec.js +265 -34
  49. package/esm/components/nested-router.spec.js.map +1 -1
  50. package/esm/services/location-service.spec.js +33 -0
  51. package/esm/services/location-service.spec.js.map +1 -1
  52. package/esm/services/route-match-service.spec.js +4 -0
  53. package/esm/services/route-match-service.spec.js.map +1 -1
  54. package/esm/services/route-meta-utils.d.ts +28 -6
  55. package/esm/services/route-meta-utils.d.ts.map +1 -1
  56. package/esm/services/route-meta-utils.js +18 -4
  57. package/esm/services/route-meta-utils.js.map +1 -1
  58. package/esm/services/route-meta-utils.spec.js +57 -2
  59. package/esm/services/route-meta-utils.spec.js.map +1 -1
  60. package/esm/vnode.d.ts +1 -1
  61. package/esm/vnode.js +1 -1
  62. package/package.json +9 -9
  63. package/src/components/define-nested-routes.spec.ts +91 -0
  64. package/src/components/define-nested-routes.ts +27 -0
  65. package/src/components/index.ts +3 -3
  66. package/src/components/nested-hooks.spec.ts +254 -0
  67. package/src/components/nested-hooks.ts +109 -0
  68. package/src/components/nested-navigate.spec.ts +128 -25
  69. package/src/components/nested-navigate.ts +75 -26
  70. package/src/components/nested-replace.spec.ts +88 -0
  71. package/src/components/nested-replace.ts +46 -0
  72. package/src/components/nested-route-link.spec.tsx +84 -16
  73. package/src/components/nested-route-link.tsx +53 -28
  74. package/src/components/nested-route-types.ts +82 -2
  75. package/src/components/nested-router.spec.tsx +316 -33
  76. package/src/components/nested-router.tsx +182 -22
  77. package/src/services/location-service.spec.ts +39 -0
  78. package/src/services/route-match-service.spec.ts +4 -0
  79. package/src/services/route-meta-utils.spec.ts +75 -7
  80. package/src/services/route-meta-utils.ts +44 -15
  81. package/src/vnode.ts +1 -1
  82. package/esm/components/link-to-route.d.ts +0 -10
  83. package/esm/components/link-to-route.d.ts.map +0 -1
  84. package/esm/components/link-to-route.js +0 -16
  85. package/esm/components/link-to-route.js.map +0 -1
  86. package/esm/components/link-to-route.spec.d.ts +0 -2
  87. package/esm/components/link-to-route.spec.d.ts.map +0 -1
  88. package/esm/components/link-to-route.spec.js +0 -30
  89. package/esm/components/link-to-route.spec.js.map +0 -1
  90. package/esm/components/route-link.d.ts +0 -10
  91. package/esm/components/route-link.d.ts.map +0 -1
  92. package/esm/components/route-link.js +0 -25
  93. package/esm/components/route-link.js.map +0 -1
  94. package/esm/components/route-link.spec.d.ts +0 -2
  95. package/esm/components/route-link.spec.d.ts.map +0 -1
  96. package/esm/components/route-link.spec.js +0 -34
  97. package/esm/components/route-link.spec.js.map +0 -1
  98. package/esm/components/router.d.ts +0 -44
  99. package/esm/components/router.d.ts.map +0 -1
  100. package/esm/components/router.js +0 -66
  101. package/esm/components/router.js.map +0 -1
  102. package/esm/components/router.spec.d.ts +0 -2
  103. package/esm/components/router.spec.d.ts.map +0 -1
  104. package/esm/components/router.spec.js +0 -161
  105. package/esm/components/router.spec.js.map +0 -1
  106. package/src/components/link-to-route.spec.tsx +0 -45
  107. package/src/components/link-to-route.tsx +0 -26
  108. package/src/components/route-link.spec.tsx +0 -44
  109. package/src/components/route-link.tsx +0 -29
  110. package/src/components/router.spec.tsx +0 -217
  111. package/src/components/router.tsx +0 -103
@@ -1,11 +1,13 @@
1
1
  import { Injector } from '@furystack/inject';
2
+ import { serializeValue } from '@furystack/rest';
2
3
  import { sleepAsync, usingAsync } from '@furystack/utils';
3
4
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
5
  import { initializeShadeRoot } from '../initialize.js';
5
6
  import { createComponent } from '../shade-component.js';
6
7
  import { flushUpdates } from '../shade.js';
7
8
  import { RouteMatchService } from '../services/route-match-service.js';
8
- import { buildMatchChain, findDivergenceIndex, NestedRouter, renderMatchChain, resolveViewTransition, } from './nested-router.js';
9
+ import { LocationService } from '../services/location-service.js';
10
+ import { buildMatchChain, enrichMatchChain, findDivergenceIndex, hasQueryOrHashChanged, NestedRouter, renderMatchChain, resolveViewTransition, } from './nested-router.js';
9
11
  import { NestedRouteLink } from './nested-route-link.js';
10
12
  describe('buildMatchChain', () => {
11
13
  it('should match a simple leaf route', () => {
@@ -122,6 +124,8 @@ describe('findDivergenceIndex', () => {
122
124
  const makeEntry = (id, params = {}) => ({
123
125
  route: { component: () => createComponent("div", null, id) },
124
126
  match: { path: '/', params },
127
+ query: null,
128
+ hash: undefined,
125
129
  });
126
130
  it('should return 0 for completely different chains', () => {
127
131
  const oldChain = [makeEntry(1)];
@@ -142,10 +146,106 @@ describe('findDivergenceIndex', () => {
142
146
  });
143
147
  it('should detect divergence from changed params', () => {
144
148
  const route = { component: () => createComponent("div", null) };
145
- const oldChain = [{ route, match: { path: '/', params: { id: '1' } } }];
146
- const newChain = [{ route, match: { path: '/', params: { id: '2' } } }];
149
+ const oldChain = [
150
+ { route, match: { path: '/', params: { id: '1' } }, query: null, hash: undefined },
151
+ ];
152
+ const newChain = [
153
+ { route, match: { path: '/', params: { id: '2' } }, query: null, hash: undefined },
154
+ ];
147
155
  expect(findDivergenceIndex(oldChain, newChain)).toBe(0);
148
156
  });
157
+ it('should ignore query and hash differences when deciding divergence', () => {
158
+ const route = { component: () => createComponent("div", null) };
159
+ const oldChain = [{ route, match: { path: '/', params: {} }, query: { page: 1 }, hash: 'a' }];
160
+ const newChain = [{ route, match: { path: '/', params: {} }, query: { page: 2 }, hash: 'b' }];
161
+ expect(findDivergenceIndex(oldChain, newChain)).toBe(1);
162
+ });
163
+ });
164
+ describe('enrichMatchChain', () => {
165
+ it('should return the input chain unchanged when no entry declares query or hash', () => {
166
+ const route = { component: () => createComponent("div", null) };
167
+ const chain = [{ route, match: { path: '/', params: {} }, query: null, hash: undefined }];
168
+ const result = enrichMatchChain(chain, {}, '');
169
+ expect(result).toBe(chain);
170
+ });
171
+ it('should populate query from the route validator', () => {
172
+ const route = {
173
+ component: () => createComponent("div", null),
174
+ query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
175
+ };
176
+ const chain = [{ route, match: { path: '/', params: {} }, query: null, hash: undefined }];
177
+ const result = enrichMatchChain(chain, { page: 3 }, '');
178
+ expect(result).not.toBe(chain);
179
+ expect(result[0].query).toEqual({ page: 3 });
180
+ });
181
+ it('should set query to null when the validator rejects the current search', () => {
182
+ const route = {
183
+ component: () => createComponent("div", null),
184
+ query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
185
+ };
186
+ const chain = [{ route, match: { path: '/', params: {} }, query: null, hash: undefined }];
187
+ const result = enrichMatchChain(chain, { page: 'nope' }, '');
188
+ expect(result[0].query).toBeNull();
189
+ });
190
+ it('should populate hash only when the current hash is listed in the declared tuple', () => {
191
+ const route = {
192
+ component: () => createComponent("div", null),
193
+ hash: ['a', 'b'],
194
+ };
195
+ const chain = [{ route, match: { path: '/', params: {} }, query: null, hash: undefined }];
196
+ expect(enrichMatchChain(chain, {}, 'a')[0].hash).toBe('a');
197
+ expect(enrichMatchChain(chain, {}, 'unknown')[0].hash).toBeUndefined();
198
+ });
199
+ it('should leave entries without a declared schema as null/undefined', () => {
200
+ const bareRoute = { component: () => createComponent("div", null) };
201
+ const declaringRoute = {
202
+ component: () => createComponent("div", null),
203
+ hash: ['a'],
204
+ };
205
+ const chain = [
206
+ { route: bareRoute, match: { path: '/', params: {} }, query: null, hash: undefined },
207
+ { route: declaringRoute, match: { path: '/', params: {} }, query: null, hash: undefined },
208
+ ];
209
+ const result = enrichMatchChain(chain, {}, 'a');
210
+ expect(result[0].query).toBeNull();
211
+ expect(result[0].hash).toBeUndefined();
212
+ expect(result[1].hash).toBe('a');
213
+ });
214
+ });
215
+ describe('hasQueryOrHashChanged', () => {
216
+ const makeEntry = (query, hash) => ({
217
+ route: { component: () => createComponent("div", null) },
218
+ match: { path: '/', params: {} },
219
+ query,
220
+ hash,
221
+ });
222
+ it('should return false when both chains are empty', () => {
223
+ expect(hasQueryOrHashChanged([], [])).toBe(false);
224
+ });
225
+ it('should return false for identical chains', () => {
226
+ const oldChain = [makeEntry({ page: 1 }, 'a')];
227
+ const newChain = [makeEntry({ page: 1 }, 'a')];
228
+ expect(hasQueryOrHashChanged(oldChain, newChain)).toBe(false);
229
+ });
230
+ it('should return true when the hash differs', () => {
231
+ expect(hasQueryOrHashChanged([makeEntry(null, 'a')], [makeEntry(null, 'b')])).toBe(true);
232
+ });
233
+ it('should return true when the query differs', () => {
234
+ expect(hasQueryOrHashChanged([makeEntry({ page: 1 }, undefined)], [makeEntry({ page: 2 }, undefined)])).toBe(true);
235
+ });
236
+ it('should treat equal query objects as unchanged regardless of key order', () => {
237
+ const oldChain = [makeEntry({ a: 1, b: 2 }, undefined)];
238
+ const newChain = [makeEntry({ b: 2, a: 1 }, undefined)];
239
+ expect(hasQueryOrHashChanged(oldChain, newChain)).toBe(false);
240
+ });
241
+ it('should detect query diffs on arrays', () => {
242
+ expect(hasQueryOrHashChanged([makeEntry([1, 2], undefined)], [makeEntry([1, 3], undefined)])).toBe(true);
243
+ });
244
+ it('should ignore chain entries beyond the shorter length', () => {
245
+ const oldChain = [makeEntry(null, 'a')];
246
+ const newChain = [makeEntry(null, 'a'), makeEntry({ x: 1 }, 'b')];
247
+ expect(hasQueryOrHashChanged(oldChain, newChain)).toBe(false);
248
+ });
149
249
  });
150
250
  describe('renderMatchChain', () => {
151
251
  it('should render a single leaf route with outlet undefined', () => {
@@ -156,6 +256,8 @@ describe('renderMatchChain', () => {
156
256
  {
157
257
  route: { component: componentFn },
158
258
  match: { path: '/leaf', params: {} },
259
+ query: null,
260
+ hash: undefined,
159
261
  },
160
262
  ];
161
263
  const result = renderMatchChain(chain, '/leaf');
@@ -163,6 +265,8 @@ describe('renderMatchChain', () => {
163
265
  expect(componentFn).toHaveBeenCalledWith({
164
266
  currentUrl: '/leaf',
165
267
  match: { path: '/leaf', params: {} },
268
+ query: null,
269
+ hash: undefined,
166
270
  outlet: undefined,
167
271
  });
168
272
  expect(result.chainElements).toHaveLength(1);
@@ -186,10 +290,14 @@ describe('renderMatchChain', () => {
186
290
  {
187
291
  route: { component: parentComponent },
188
292
  match: { path: '/parent', params: {} },
293
+ query: null,
294
+ hash: undefined,
189
295
  },
190
296
  {
191
297
  route: { component: childComponent },
192
298
  match: { path: '/child', params: {} },
299
+ query: null,
300
+ hash: undefined,
193
301
  },
194
302
  ];
195
303
  const result = renderMatchChain(chain, '/parent/child');
@@ -210,9 +318,9 @@ describe('renderMatchChain', () => {
210
318
  const child = makeComponent();
211
319
  const parent = makeComponent();
212
320
  const chain = [
213
- { route: { component: parent }, match: { path: '/a', params: {} } },
214
- { route: { component: child }, match: { path: '/b', params: {} } },
215
- { route: { component: grandchild }, match: { path: '/c', params: {} } },
321
+ { route: { component: parent }, match: { path: '/a', params: {} }, query: null, hash: undefined },
322
+ { route: { component: child }, match: { path: '/b', params: {} }, query: null, hash: undefined },
323
+ { route: { component: grandchild }, match: { path: '/c', params: {} }, query: null, hash: undefined },
216
324
  ];
217
325
  renderMatchChain(chain, '/a/b/c');
218
326
  expect(urls).toEqual(['/a/b/c', '/a/b/c', '/a/b/c']);
@@ -226,9 +334,9 @@ describe('renderMatchChain', () => {
226
334
  "parent",
227
335
  outlet));
228
336
  const chain = [
229
- { route: { component: parentComponent }, match: { path: '/a', params: {} } },
230
- { route: { component: childComponent }, match: { path: '/b', params: {} } },
231
- { route: { component: () => grandchildEl }, match: { path: '/c', params: {} } },
337
+ { route: { component: parentComponent }, match: { path: '/a', params: {} }, query: null, hash: undefined },
338
+ { route: { component: childComponent }, match: { path: '/b', params: {} }, query: null, hash: undefined },
339
+ { route: { component: () => grandchildEl }, match: { path: '/c', params: {} }, query: null, hash: undefined },
232
340
  ];
233
341
  const result = renderMatchChain(chain, '/a/b/c');
234
342
  expect(result.chainElements).toHaveLength(3);
@@ -283,10 +391,10 @@ describe('NestedRouter lifecycle hooks', () => {
283
391
  injector,
284
392
  rootElement,
285
393
  jsxElement: (createComponent("div", null,
286
- createComponent(NestedRouteLink, { id: "child-a", href: "/parent/child-a" }, "child-a"),
287
- createComponent(NestedRouteLink, { id: "child-b", href: "/parent/child-b" }, "child-b"),
288
- createComponent(NestedRouteLink, { id: "other", href: "/other" }, "other"),
289
- createComponent(NestedRouteLink, { id: "nowhere", href: "/nowhere" }, "nowhere"),
394
+ createComponent(NestedRouteLink, { id: "child-a", path: "/parent/child-a" }, "child-a"),
395
+ createComponent(NestedRouteLink, { id: "child-b", path: "/parent/child-b" }, "child-b"),
396
+ createComponent(NestedRouteLink, { id: "other", path: "/other" }, "other"),
397
+ createComponent(NestedRouteLink, { id: "nowhere", path: "/nowhere" }, "nowhere"),
290
398
  createComponent(NestedRouter, { routes: {
291
399
  '/parent': {
292
400
  component: ({ outlet }) => createComponent("div", { id: "wrapper" }, outlet ?? createComponent("div", { id: "content" }, "parent-index")),
@@ -358,6 +466,127 @@ describe('NestedRouter lifecycle hooks', () => {
358
466
  });
359
467
  });
360
468
  });
469
+ describe('NestedRouter query / hash re-render', () => {
470
+ beforeEach(() => {
471
+ document.body.innerHTML = '<div id="root"></div>';
472
+ });
473
+ afterEach(() => {
474
+ document.body.innerHTML = '';
475
+ });
476
+ it('should re-render the chain on a hash-only change without firing lifecycle hooks', async () => {
477
+ history.pushState(null, '', '/tabs');
478
+ const onVisit = vi.fn(async () => { });
479
+ const onLeave = vi.fn(async () => { });
480
+ const componentFn = vi.fn(({ hash }) => createComponent("div", { id: "content" },
481
+ "hash=",
482
+ hash ?? 'none'));
483
+ await usingAsync(new Injector(), async (injector) => {
484
+ const rootElement = document.getElementById('root');
485
+ initializeShadeRoot({
486
+ injector,
487
+ rootElement,
488
+ jsxElement: (createComponent(NestedRouter, { routes: {
489
+ '/tabs': {
490
+ component: componentFn,
491
+ onVisit,
492
+ onLeave,
493
+ hash: ['a', 'b'],
494
+ },
495
+ } })),
496
+ });
497
+ await flushUpdates();
498
+ expect(document.getElementById('content')?.innerHTML).toBe('hash=none');
499
+ expect(onVisit).toBeCalledTimes(1);
500
+ expect(onLeave).not.toBeCalled();
501
+ const locationService = injector.getInstance(LocationService);
502
+ locationService.navigate('/tabs#a');
503
+ await flushUpdates();
504
+ await flushUpdates();
505
+ expect(document.getElementById('content')?.innerHTML).toBe('hash=a');
506
+ expect(onVisit).toBeCalledTimes(1);
507
+ expect(onLeave).not.toBeCalled();
508
+ locationService.navigate('/tabs#b');
509
+ await flushUpdates();
510
+ await flushUpdates();
511
+ expect(document.getElementById('content')?.innerHTML).toBe('hash=b');
512
+ expect(onVisit).toBeCalledTimes(1);
513
+ expect(onLeave).not.toBeCalled();
514
+ });
515
+ });
516
+ it('should re-render the chain on a query-only change without firing lifecycle hooks', async () => {
517
+ history.pushState(null, '', '/list');
518
+ const onVisit = vi.fn(async () => { });
519
+ const onLeave = vi.fn(async () => { });
520
+ const componentFn = vi.fn(({ query }) => (createComponent("div", { id: "content" },
521
+ "page=",
522
+ query?.page ?? 'none')));
523
+ await usingAsync(new Injector(), async (injector) => {
524
+ const rootElement = document.getElementById('root');
525
+ initializeShadeRoot({
526
+ injector,
527
+ rootElement,
528
+ jsxElement: (createComponent(NestedRouter, { routes: {
529
+ '/list': {
530
+ component: componentFn,
531
+ onVisit,
532
+ onLeave,
533
+ query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
534
+ },
535
+ } })),
536
+ });
537
+ await flushUpdates();
538
+ expect(document.getElementById('content')?.innerHTML).toBe('page=none');
539
+ expect(onVisit).toBeCalledTimes(1);
540
+ const locationService = injector.getInstance(LocationService);
541
+ locationService.navigate(`/list?page=${serializeValue(2)}`);
542
+ await flushUpdates();
543
+ await flushUpdates();
544
+ expect(document.getElementById('content')?.innerHTML).toBe('page=2');
545
+ expect(onVisit).toBeCalledTimes(1);
546
+ expect(onLeave).not.toBeCalled();
547
+ locationService.navigate(`/list?page=${serializeValue(5)}`);
548
+ await flushUpdates();
549
+ await flushUpdates();
550
+ expect(document.getElementById('content')?.innerHTML).toBe('page=5');
551
+ expect(onVisit).toBeCalledTimes(1);
552
+ expect(onLeave).not.toBeCalled();
553
+ });
554
+ });
555
+ it('should coalesce path + query + hash bursts into a single updateUrl', async () => {
556
+ history.pushState(null, '', '/a');
557
+ const aComponent = vi.fn(() => createComponent("div", { id: "content" }, "a"));
558
+ const bComponent = vi.fn(({ query, hash }) => (createComponent("div", { id: "content" },
559
+ "b-page=",
560
+ query?.page ?? 'none',
561
+ "-hash=",
562
+ hash ?? 'none')));
563
+ await usingAsync(new Injector(), async (injector) => {
564
+ const rootElement = document.getElementById('root');
565
+ initializeShadeRoot({
566
+ injector,
567
+ rootElement,
568
+ jsxElement: (createComponent(NestedRouter, { routes: {
569
+ '/a': { component: aComponent },
570
+ '/b': {
571
+ component: bComponent,
572
+ hash: ['x'],
573
+ query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
574
+ },
575
+ } })),
576
+ });
577
+ await flushUpdates();
578
+ expect(document.getElementById('content')?.innerHTML).toBe('a');
579
+ bComponent.mockClear();
580
+ injector.getInstance(LocationService).navigate(`/b?page=${serializeValue(7)}#x`);
581
+ await flushUpdates();
582
+ await flushUpdates();
583
+ expect(document.getElementById('content')?.innerHTML).toBe('b-page=7-hash=x');
584
+ // A single logical navigation should render the /b component exactly once,
585
+ // not three times (once per observable subscription).
586
+ expect(bComponent).toHaveBeenCalledTimes(1);
587
+ });
588
+ });
589
+ });
361
590
  describe('NestedRouter latest-wins on rapid navigation', () => {
362
591
  beforeEach(() => {
363
592
  document.body.innerHTML = '<div id="root"></div>';
@@ -393,9 +622,9 @@ describe('NestedRouter latest-wins on rapid navigation', () => {
393
622
  injector,
394
623
  rootElement,
395
624
  jsxElement: (createComponent("div", null,
396
- createComponent(NestedRouteLink, { id: "go-a", href: "/route-a" }, "a"),
397
- createComponent(NestedRouteLink, { id: "go-b", href: "/route-b" }, "b"),
398
- createComponent(NestedRouteLink, { id: "go-c", href: "/route-c" }, "c"),
625
+ createComponent(NestedRouteLink, { id: "go-a", path: "/route-a" }, "a"),
626
+ createComponent(NestedRouteLink, { id: "go-b", path: "/route-b" }, "b"),
627
+ createComponent(NestedRouteLink, { id: "go-c", path: "/route-c" }, "c"),
399
628
  createComponent(NestedRouter, { routes: {
400
629
  '/route-a': {
401
630
  component: () => createComponent("div", { id: "content" }, "route-a"),
@@ -453,8 +682,8 @@ describe('NestedRouter lifecycle element scope', () => {
453
682
  injector,
454
683
  rootElement,
455
684
  jsxElement: (createComponent("div", null,
456
- createComponent(NestedRouteLink, { id: "child-a", href: "/parent/child-a" }, "child-a"),
457
- createComponent(NestedRouteLink, { id: "child-b", href: "/parent/child-b" }, "child-b"),
685
+ createComponent(NestedRouteLink, { id: "child-a", path: "/parent/child-a" }, "child-a"),
686
+ createComponent(NestedRouteLink, { id: "child-b", path: "/parent/child-b" }, "child-b"),
458
687
  createComponent(NestedRouter, { routes: {
459
688
  '/parent': {
460
689
  component: ({ outlet }) => createComponent("div", { id: "wrapper" }, outlet ?? createComponent("span", null, "index")),
@@ -528,9 +757,9 @@ describe('NestedRouter flat routes', () => {
528
757
  injector,
529
758
  rootElement,
530
759
  jsxElement: (createComponent("div", null,
531
- createComponent(NestedRouteLink, { id: "home", href: "/" }, "home"),
532
- createComponent(NestedRouteLink, { id: "about", href: "/about" }, "about"),
533
- createComponent(NestedRouteLink, { id: "contact", href: "/contact" }, "contact"),
760
+ createComponent(NestedRouteLink, { id: "home", path: "/" }, "home"),
761
+ createComponent(NestedRouteLink, { id: "about", path: "/about" }, "about"),
762
+ createComponent(NestedRouteLink, { id: "contact", path: "/contact" }, "contact"),
534
763
  createComponent(NestedRouter, { routes: {
535
764
  '/about': { component: () => createComponent("div", { id: "content" }, "about-page") },
536
765
  '/contact': { component: () => createComponent("div", { id: "content" }, "contact-page") },
@@ -640,9 +869,9 @@ describe('NestedRouter route param changes', () => {
640
869
  injector,
641
870
  rootElement,
642
871
  jsxElement: (createComponent("div", null,
643
- createComponent(NestedRouteLink, { id: "user-1", href: "/users/1" }, "User 1"),
644
- createComponent(NestedRouteLink, { id: "user-2", href: "/users/2" }, "User 2"),
645
- createComponent(NestedRouteLink, { id: "user-3", href: "/users/3" }, "User 3"),
872
+ createComponent(NestedRouteLink, { id: "user-1", path: "/users/1" }, "User 1"),
873
+ createComponent(NestedRouteLink, { id: "user-2", path: "/users/2" }, "User 2"),
874
+ createComponent(NestedRouteLink, { id: "user-3", path: "/users/3" }, "User 3"),
646
875
  createComponent(NestedRouter, { routes: {
647
876
  '/users/:id': {
648
877
  component: ({ match }) => createComponent("div", { id: "content" },
@@ -698,8 +927,8 @@ describe('NestedRouter route param changes', () => {
698
927
  injector,
699
928
  rootElement,
700
929
  jsxElement: (createComponent("div", null,
701
- createComponent(NestedRouteLink, { id: "alpha-dash", href: "/org/alpha/dashboard" }, "Alpha Dashboard"),
702
- createComponent(NestedRouteLink, { id: "beta-dash", href: "/org/beta/dashboard" }, "Beta Dashboard"),
930
+ createComponent(NestedRouteLink, { id: "alpha-dash", path: "/org/alpha/dashboard" }, "Alpha Dashboard"),
931
+ createComponent(NestedRouteLink, { id: "beta-dash", path: "/org/beta/dashboard" }, "Beta Dashboard"),
703
932
  createComponent(NestedRouter, { routes: {
704
933
  '/org/:orgId': {
705
934
  component: ({ match, outlet }) => (createComponent("div", { id: "org" },
@@ -768,9 +997,9 @@ describe('NestedRouter + RouteMatchService integration', () => {
768
997
  injector,
769
998
  rootElement,
770
999
  jsxElement: (createComponent("div", null,
771
- createComponent(NestedRouteLink, { id: "child-a", href: "/parent/child-a" }, "child-a"),
772
- createComponent(NestedRouteLink, { id: "child-b", href: "/parent/child-b" }, "child-b"),
773
- createComponent(NestedRouteLink, { id: "nowhere", href: "/nowhere" }, "nowhere"),
1000
+ createComponent(NestedRouteLink, { id: "child-a", path: "/parent/child-a" }, "child-a"),
1001
+ createComponent(NestedRouteLink, { id: "child-b", path: "/parent/child-b" }, "child-b"),
1002
+ createComponent(NestedRouteLink, { id: "nowhere", path: "/nowhere" }, "nowhere"),
774
1003
  createComponent(NestedRouter, { routes: { '/parent': parentRoute }, notFound: createComponent("div", { id: "content" }, "not found") }))),
775
1004
  });
776
1005
  // Initial load
@@ -823,6 +1052,8 @@ describe('resolveViewTransition', () => {
823
1052
  const makeEntry = (viewTransition) => ({
824
1053
  route: { component: () => createComponent("div", null), viewTransition },
825
1054
  match: { path: '/', params: {} },
1055
+ query: null,
1056
+ hash: undefined,
826
1057
  });
827
1058
  it('should return false when router config is undefined and route has no override', () => {
828
1059
  expect(resolveViewTransition(undefined, [makeEntry()])).toBe(false);
@@ -881,7 +1112,7 @@ describe('NestedRouter view transitions', () => {
881
1112
  injector,
882
1113
  rootElement,
883
1114
  jsxElement: (createComponent("div", null,
884
- createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
1115
+ createComponent(NestedRouteLink, { id: "go-about", path: "/about" }, "about"),
885
1116
  createComponent(NestedRouter, { viewTransition: true, routes: {
886
1117
  '/about': { component: () => createComponent("div", { id: "content" }, "about") },
887
1118
  '/': { component: () => createComponent("div", { id: "content" }, "home") },
@@ -903,7 +1134,7 @@ describe('NestedRouter view transitions', () => {
903
1134
  injector,
904
1135
  rootElement,
905
1136
  jsxElement: (createComponent("div", null,
906
- createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
1137
+ createComponent(NestedRouteLink, { id: "go-about", path: "/about" }, "about"),
907
1138
  createComponent(NestedRouter, { routes: {
908
1139
  '/about': { component: () => createComponent("div", { id: "content" }, "about") },
909
1140
  '/': { component: () => createComponent("div", { id: "content" }, "home") },
@@ -925,7 +1156,7 @@ describe('NestedRouter view transitions', () => {
925
1156
  injector,
926
1157
  rootElement,
927
1158
  jsxElement: (createComponent("div", null,
928
- createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
1159
+ createComponent(NestedRouteLink, { id: "go-about", path: "/about" }, "about"),
929
1160
  createComponent(NestedRouter, { viewTransition: { types: ['slide'] }, routes: {
930
1161
  '/about': { component: () => createComponent("div", { id: "content" }, "about") },
931
1162
  '/': { component: () => createComponent("div", { id: "content" }, "home") },
@@ -946,7 +1177,7 @@ describe('NestedRouter view transitions', () => {
946
1177
  injector,
947
1178
  rootElement,
948
1179
  jsxElement: (createComponent("div", null,
949
- createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
1180
+ createComponent(NestedRouteLink, { id: "go-about", path: "/about" }, "about"),
950
1181
  createComponent(NestedRouter, { viewTransition: true, routes: {
951
1182
  '/about': {
952
1183
  component: () => createComponent("div", { id: "content" }, "about"),
@@ -972,7 +1203,7 @@ describe('NestedRouter view transitions', () => {
972
1203
  injector,
973
1204
  rootElement,
974
1205
  jsxElement: (createComponent("div", null,
975
- createComponent(NestedRouteLink, { id: "go-about", href: "/about" }, "about"),
1206
+ createComponent(NestedRouteLink, { id: "go-about", path: "/about" }, "about"),
976
1207
  createComponent(NestedRouter, { viewTransition: true, routes: {
977
1208
  '/about': { component: () => createComponent("div", { id: "content" }, "about") },
978
1209
  '/': { component: () => createComponent("div", { id: "content" }, "home") },