@furystack/shades 13.2.2 → 15.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.
- package/CHANGELOG.md +157 -0
- package/esm/component-factory.spec.d.ts.map +1 -1
- package/esm/component-factory.spec.js +2 -2
- package/esm/component-factory.spec.js.map +1 -1
- package/esm/components/define-nested-routes.d.ts +27 -0
- package/esm/components/define-nested-routes.d.ts.map +1 -0
- package/esm/components/define-nested-routes.js +26 -0
- package/esm/components/define-nested-routes.js.map +1 -0
- package/esm/components/define-nested-routes.spec.d.ts +2 -0
- package/esm/components/define-nested-routes.spec.d.ts.map +1 -0
- package/esm/components/define-nested-routes.spec.js +81 -0
- package/esm/components/define-nested-routes.spec.js.map +1 -0
- package/esm/components/index.d.ts +3 -3
- package/esm/components/index.d.ts.map +1 -1
- package/esm/components/index.js +3 -3
- package/esm/components/index.js.map +1 -1
- package/esm/components/nested-hooks.d.ts +62 -0
- package/esm/components/nested-hooks.d.ts.map +1 -0
- package/esm/components/nested-hooks.js +73 -0
- package/esm/components/nested-hooks.js.map +1 -0
- package/esm/components/nested-hooks.spec.d.ts +2 -0
- package/esm/components/nested-hooks.spec.d.ts.map +1 -0
- package/esm/components/nested-hooks.spec.js +211 -0
- package/esm/components/nested-hooks.spec.js.map +1 -0
- package/esm/components/nested-navigate.d.ts +52 -21
- package/esm/components/nested-navigate.d.ts.map +1 -1
- package/esm/components/nested-navigate.js +32 -17
- package/esm/components/nested-navigate.js.map +1 -1
- package/esm/components/nested-navigate.spec.js +109 -19
- package/esm/components/nested-navigate.spec.js.map +1 -1
- package/esm/components/nested-replace.d.ts +36 -0
- package/esm/components/nested-replace.d.ts.map +1 -0
- package/esm/components/nested-replace.js +38 -0
- package/esm/components/nested-replace.js.map +1 -0
- package/esm/components/nested-replace.spec.d.ts +2 -0
- package/esm/components/nested-replace.spec.d.ts.map +1 -0
- package/esm/components/nested-replace.spec.js +59 -0
- package/esm/components/nested-replace.spec.js.map +1 -0
- package/esm/components/nested-route-link.d.ts +36 -26
- package/esm/components/nested-route-link.d.ts.map +1 -1
- package/esm/components/nested-route-link.js +18 -20
- package/esm/components/nested-route-link.js.map +1 -1
- package/esm/components/nested-route-link.spec.js +67 -17
- package/esm/components/nested-route-link.spec.js.map +1 -1
- package/esm/components/nested-route-types.d.ts +79 -2
- package/esm/components/nested-route-types.d.ts.map +1 -1
- package/esm/components/nested-router.d.ts +77 -7
- package/esm/components/nested-router.d.ts.map +1 -1
- package/esm/components/nested-router.js +139 -13
- package/esm/components/nested-router.js.map +1 -1
- package/esm/components/nested-router.spec.js +283 -52
- package/esm/components/nested-router.spec.js.map +1 -1
- package/esm/services/location-service.d.ts +39 -42
- package/esm/services/location-service.d.ts.map +1 -1
- package/esm/services/location-service.js +115 -134
- package/esm/services/location-service.js.map +1 -1
- package/esm/services/location-service.spec.js +59 -24
- package/esm/services/location-service.spec.js.map +1 -1
- package/esm/services/route-match-service.d.ts +3 -2
- package/esm/services/route-match-service.d.ts.map +1 -1
- package/esm/services/route-match-service.js +13 -22
- package/esm/services/route-match-service.js.map +1 -1
- package/esm/services/route-match-service.spec.js +42 -49
- package/esm/services/route-match-service.spec.js.map +1 -1
- package/esm/services/route-meta-utils.d.ts +28 -6
- package/esm/services/route-meta-utils.d.ts.map +1 -1
- package/esm/services/route-meta-utils.js +18 -4
- package/esm/services/route-meta-utils.js.map +1 -1
- package/esm/services/route-meta-utils.spec.js +60 -5
- package/esm/services/route-meta-utils.spec.js.map +1 -1
- package/esm/services/screen-service.d.ts +13 -72
- package/esm/services/screen-service.d.ts.map +1 -1
- package/esm/services/screen-service.js +45 -137
- package/esm/services/screen-service.js.map +1 -1
- package/esm/services/screen-service.spec.js +19 -18
- package/esm/services/screen-service.spec.js.map +1 -1
- package/esm/services/spatial-navigation-service.d.ts +17 -39
- package/esm/services/spatial-navigation-service.d.ts.map +1 -1
- package/esm/services/spatial-navigation-service.js +280 -313
- package/esm/services/spatial-navigation-service.js.map +1 -1
- package/esm/services/spatial-navigation-service.spec.js +163 -158
- package/esm/services/spatial-navigation-service.spec.js.map +1 -1
- package/esm/shade.d.ts +1 -1
- package/esm/shade.d.ts.map +1 -1
- package/esm/shade.js +10 -7
- package/esm/shade.js.map +1 -1
- package/esm/vnode.d.ts +1 -1
- package/esm/vnode.js +1 -1
- package/package.json +5 -4
- package/src/component-factory.spec.tsx +3 -2
- package/src/components/define-nested-routes.spec.ts +91 -0
- package/src/components/define-nested-routes.ts +27 -0
- package/src/components/index.ts +3 -3
- package/src/components/nested-hooks.spec.ts +254 -0
- package/src/components/nested-hooks.ts +109 -0
- package/src/components/nested-navigate.spec.ts +136 -32
- package/src/components/nested-navigate.ts +75 -26
- package/src/components/nested-replace.spec.ts +89 -0
- package/src/components/nested-replace.ts +46 -0
- package/src/components/nested-route-link.spec.tsx +90 -22
- package/src/components/nested-route-link.tsx +54 -29
- package/src/components/nested-route-types.ts +82 -2
- package/src/components/nested-router.spec.tsx +334 -51
- package/src/components/nested-router.tsx +184 -24
- package/src/services/location-service.spec.ts +68 -25
- package/src/services/location-service.tsx +156 -122
- package/src/services/route-match-service.spec.ts +41 -28
- package/src/services/route-match-service.ts +17 -8
- package/src/services/route-meta-utils.spec.ts +78 -10
- package/src/services/route-meta-utils.ts +44 -15
- package/src/services/screen-service.spec.ts +19 -18
- package/src/services/screen-service.ts +65 -110
- package/src/services/spatial-navigation-service.spec.ts +165 -160
- package/src/services/spatial-navigation-service.ts +299 -287
- package/src/shade.ts +11 -8
- package/src/vnode.ts +1 -1
- package/esm/components/link-to-route.d.ts +0 -10
- package/esm/components/link-to-route.d.ts.map +0 -1
- package/esm/components/link-to-route.js +0 -16
- package/esm/components/link-to-route.js.map +0 -1
- package/esm/components/link-to-route.spec.d.ts +0 -2
- package/esm/components/link-to-route.spec.d.ts.map +0 -1
- package/esm/components/link-to-route.spec.js +0 -30
- package/esm/components/link-to-route.spec.js.map +0 -1
- package/esm/components/route-link.d.ts +0 -10
- package/esm/components/route-link.d.ts.map +0 -1
- package/esm/components/route-link.js +0 -25
- package/esm/components/route-link.js.map +0 -1
- package/esm/components/route-link.spec.d.ts +0 -2
- package/esm/components/route-link.spec.d.ts.map +0 -1
- package/esm/components/route-link.spec.js +0 -34
- package/esm/components/route-link.spec.js.map +0 -1
- package/esm/components/router.d.ts +0 -44
- package/esm/components/router.d.ts.map +0 -1
- package/esm/components/router.js +0 -66
- package/esm/components/router.js.map +0 -1
- package/esm/components/router.spec.d.ts +0 -2
- package/esm/components/router.spec.d.ts.map +0 -1
- package/esm/components/router.spec.js +0 -161
- package/esm/components/router.spec.js.map +0 -1
- package/src/components/link-to-route.spec.tsx +0 -45
- package/src/components/link-to-route.tsx +0 -26
- package/src/components/route-link.spec.tsx +0 -44
- package/src/components/route-link.tsx +0 -29
- package/src/components/router.spec.tsx +0 -217
- package/src/components/router.tsx +0 -103
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Injector } from '@furystack/inject';
|
|
2
|
+
import type { NestedNavigateArgs, TypedNestedNavigateArgs } from './nested-navigate.js';
|
|
3
|
+
import type { ExtractRoutePaths } from './nested-route-types.js';
|
|
4
|
+
import type { NestedRoute } from './nested-router.js';
|
|
5
|
+
/**
|
|
6
|
+
* Replaces the current history entry with a route using the LocationService
|
|
7
|
+
* resolved from the given injector. Has the same URL-composition semantics as
|
|
8
|
+
* `nestedNavigate`, but calls `history.replaceState` under the hood so the
|
|
9
|
+
* intermediate URL does not appear in the browser's back / forward stack.
|
|
10
|
+
*
|
|
11
|
+
* Use this for SPA redirects (e.g. canonicalization, auth guards) where the
|
|
12
|
+
* caller's URL should not be recoverable with the Back button.
|
|
13
|
+
*
|
|
14
|
+
* @param injector - The injector instance to resolve LocationService from
|
|
15
|
+
* @param args - The navigation arguments
|
|
16
|
+
*/
|
|
17
|
+
export declare const nestedReplace: (injector: Injector, args: NestedNavigateArgs) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a type-safe replace function constrained to a specific route tree.
|
|
20
|
+
* The returned function has the same runtime behavior as {@link nestedReplace}
|
|
21
|
+
* but narrows `path` to valid route paths, requires `params` when the route has
|
|
22
|
+
* parameters, and enforces the route's declared `query` and `hash` schemas.
|
|
23
|
+
*
|
|
24
|
+
* @typeParam TRoutes - The route tree type (use `typeof yourRoutes`)
|
|
25
|
+
* @returns A type-safe replace function
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const appReplace = createNestedReplace<typeof appRoutes>()
|
|
30
|
+
*
|
|
31
|
+
* // Redirect an unauthenticated visitor without polluting history
|
|
32
|
+
* appReplace(injector, { path: '/login' })
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare const createNestedReplace: <TRoutes extends Record<string, NestedRoute<any, any, any>>>() => <TPath extends ExtractRoutePaths<TRoutes>>(injector: Injector, args: TypedNestedNavigateArgs<TRoutes, TPath>) => void;
|
|
36
|
+
//# sourceMappingURL=nested-replace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-replace.d.ts","sourceRoot":"","sources":["../../src/components/nested-replace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAEvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GAAI,UAAU,QAAQ,EAAE,MAAM,kBAAkB,KAAG,IAE5E,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,OACpE,CAAC,KAAK,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAC/D,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,uBAAuB,CAAC,OAAO,EAAE,KAAK,CAAC,KAC1C,IACN,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { LocationService } from '../services/location-service.js';
|
|
2
|
+
import { buildNestedNavigateUrl } from './nested-navigate.js';
|
|
3
|
+
/**
|
|
4
|
+
* Replaces the current history entry with a route using the LocationService
|
|
5
|
+
* resolved from the given injector. Has the same URL-composition semantics as
|
|
6
|
+
* `nestedNavigate`, but calls `history.replaceState` under the hood so the
|
|
7
|
+
* intermediate URL does not appear in the browser's back / forward stack.
|
|
8
|
+
*
|
|
9
|
+
* Use this for SPA redirects (e.g. canonicalization, auth guards) where the
|
|
10
|
+
* caller's URL should not be recoverable with the Back button.
|
|
11
|
+
*
|
|
12
|
+
* @param injector - The injector instance to resolve LocationService from
|
|
13
|
+
* @param args - The navigation arguments
|
|
14
|
+
*/
|
|
15
|
+
export const nestedReplace = (injector, args) => {
|
|
16
|
+
injector.get(LocationService).replace(buildNestedNavigateUrl(args));
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Creates a type-safe replace function constrained to a specific route tree.
|
|
20
|
+
* The returned function has the same runtime behavior as {@link nestedReplace}
|
|
21
|
+
* but narrows `path` to valid route paths, requires `params` when the route has
|
|
22
|
+
* parameters, and enforces the route's declared `query` and `hash` schemas.
|
|
23
|
+
*
|
|
24
|
+
* @typeParam TRoutes - The route tree type (use `typeof yourRoutes`)
|
|
25
|
+
* @returns A type-safe replace function
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const appReplace = createNestedReplace<typeof appRoutes>()
|
|
30
|
+
*
|
|
31
|
+
* // Redirect an unauthenticated visitor without polluting history
|
|
32
|
+
* appReplace(injector, { path: '/login' })
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const createNestedReplace = () => {
|
|
36
|
+
return nestedReplace;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=nested-replace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-replace.js","sourceRoot":"","sources":["../../src/components/nested-replace.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAEjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAI7D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAkB,EAAE,IAAwB,EAAQ,EAAE;IAClF,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAA;AACrE,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAA+D,EAAE;IAClG,OAAO,aAGE,CAAA;AACX,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-replace.spec.d.ts","sourceRoot":"","sources":["../../src/components/nested-replace.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createInjector } from '@furystack/inject';
|
|
2
|
+
import { usingAsync } from '@furystack/utils';
|
|
3
|
+
import { describe, expect, expectTypeOf, it, vi } from 'vitest';
|
|
4
|
+
import { LocationService } from '../services/location-service.js';
|
|
5
|
+
import { createNestedReplace, nestedReplace } from './nested-replace.js';
|
|
6
|
+
describe('nestedReplace', () => {
|
|
7
|
+
it('Should replace the current history entry with a simple path', async () => {
|
|
8
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
9
|
+
const locationService = injector.get(LocationService);
|
|
10
|
+
const navigateSpy = vi.spyOn(locationService, 'navigate');
|
|
11
|
+
const replaceSpy = vi.spyOn(locationService, 'replace');
|
|
12
|
+
nestedReplace(injector, { path: '/buttons' });
|
|
13
|
+
expect(replaceSpy).toHaveBeenCalledWith('/buttons');
|
|
14
|
+
expect(navigateSpy).not.toHaveBeenCalled();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
it('Should compile params, query and hash for a replace call', async () => {
|
|
18
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
19
|
+
const locationService = injector.get(LocationService);
|
|
20
|
+
const replaceSpy = vi.spyOn(locationService, 'replace');
|
|
21
|
+
nestedReplace(injector, {
|
|
22
|
+
path: '/users/:id',
|
|
23
|
+
params: { id: '7' },
|
|
24
|
+
query: { tab: 'profile' },
|
|
25
|
+
hash: 'notes',
|
|
26
|
+
});
|
|
27
|
+
expect(replaceSpy).toHaveBeenCalledTimes(1);
|
|
28
|
+
const replacedUrl = replaceSpy.mock.calls[0][0];
|
|
29
|
+
expect(replacedUrl.startsWith('/users/7?')).toBe(true);
|
|
30
|
+
expect(replacedUrl.endsWith('#notes')).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('createNestedReplace', () => {
|
|
35
|
+
it('Should constrain path to valid route paths', () => {
|
|
36
|
+
const appReplace = createNestedReplace();
|
|
37
|
+
expectTypeOf((appReplace))
|
|
38
|
+
.parameter(0)
|
|
39
|
+
.toEqualTypeOf();
|
|
40
|
+
});
|
|
41
|
+
it('Should reject invalid paths', () => {
|
|
42
|
+
const appReplace = createNestedReplace();
|
|
43
|
+
// @ts-expect-error -- '/nonexistent' is not a valid route path
|
|
44
|
+
appReplace(createInjector(), { path: '/nonexistent' });
|
|
45
|
+
});
|
|
46
|
+
it('Should enforce a declared required query shape', () => {
|
|
47
|
+
const routes = {
|
|
48
|
+
'/list': {
|
|
49
|
+
component: () => null,
|
|
50
|
+
query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
const appReplace = createNestedReplace();
|
|
54
|
+
expectTypeOf((appReplace))
|
|
55
|
+
.parameter(1)
|
|
56
|
+
.toExtend();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=nested-replace.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-replace.spec.js","sourceRoot":"","sources":["../../src/components/nested-replace.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,45 +1,60 @@
|
|
|
1
1
|
import type { ChildrenList } from '../models/children-list.js';
|
|
2
2
|
import type { PartialElement } from '../models/partial-element.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ExtractRouteHash, ExtractRouteQuery, ExtractRoutePaths, RouteAt, TypedHashArg, TypedParamsArg, TypedQueryArg } from './nested-route-types.js';
|
|
4
4
|
import type { NestedRoute } from './nested-router.js';
|
|
5
5
|
/**
|
|
6
6
|
* Props for the NestedRouteLink component.
|
|
7
|
-
* Combines SPA navigation
|
|
7
|
+
* Combines SPA navigation with parameter compilation for nested routes,
|
|
8
|
+
* plus optional query string and hash fragment composition.
|
|
8
9
|
*/
|
|
9
10
|
export type NestedRouteLinkProps = {
|
|
10
|
-
|
|
11
|
+
path: string;
|
|
11
12
|
params?: Record<string, string>;
|
|
13
|
+
query?: Record<string, unknown>;
|
|
14
|
+
hash?: string;
|
|
12
15
|
} & PartialElement<Omit<HTMLAnchorElement, 'onclick' | 'href'>>;
|
|
13
16
|
/**
|
|
14
17
|
* Props for a type-safe nested route link.
|
|
15
18
|
* When the path contains parameters (e.g. `:id`), the `params` prop becomes required.
|
|
19
|
+
* `query` and `hash` remain loose (untyped) on this variant; use
|
|
20
|
+
* {@link createNestedRouteLink} to narrow them against a specific route tree.
|
|
16
21
|
* @typeParam TPath - A specific route path string
|
|
17
22
|
*/
|
|
18
23
|
export type TypedNestedRouteLinkProps<TPath extends string> = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
path: TPath;
|
|
25
|
+
query?: Record<string, unknown>;
|
|
26
|
+
hash?: string;
|
|
27
|
+
} & TypedParamsArg<TPath> & PartialElement<Omit<HTMLAnchorElement, 'onclick' | 'href'>>;
|
|
28
|
+
/**
|
|
29
|
+
* Props for a route-tree-aware nested route link. Narrows `query` and `hash`
|
|
30
|
+
* against the specific route at `TPath` in `TRoutes`.
|
|
31
|
+
* @typeParam TRoutes - The route tree
|
|
32
|
+
* @typeParam TPath - A composed route path within `TRoutes`
|
|
33
|
+
*/
|
|
34
|
+
export type TreeAwareNestedRouteLinkProps<TRoutes extends Record<string, NestedRoute<any, any, any>>, TPath extends string> = {
|
|
35
|
+
path: TPath;
|
|
36
|
+
} & TypedParamsArg<TPath> & TypedQueryArg<ExtractRouteQuery<RouteAt<TRoutes, TPath>>> & TypedHashArg<ExtractRouteHash<RouteAt<TRoutes, TPath>>> & PartialElement<Omit<HTMLAnchorElement, 'onclick' | 'href'>>;
|
|
25
37
|
/**
|
|
26
38
|
* A link component for NestedRouter that supports SPA navigation with
|
|
27
39
|
* type-safe route parameter compilation.
|
|
28
40
|
*
|
|
29
41
|
* Intercepts click events to use `history.pushState` for client-side navigation,
|
|
30
|
-
*
|
|
42
|
+
* compiles parameterized routes (e.g. `/users/:id`) when `params` is provided,
|
|
43
|
+
* serializes `query` to the URL search string and appends `hash` when set.
|
|
31
44
|
*
|
|
32
|
-
* Route parameters are automatically inferred from the `
|
|
33
|
-
* - `
|
|
34
|
-
* - `
|
|
45
|
+
* Route parameters are automatically inferred from the `path` pattern:
|
|
46
|
+
* - `path="/buttons"` — `params` is optional
|
|
47
|
+
* - `path="/users/:id"` — `params: { id: string }` is required
|
|
35
48
|
*
|
|
36
|
-
* For additional URL validation against a route tree
|
|
49
|
+
* For additional URL validation against a route tree (including `query` and
|
|
50
|
+
* `hash` narrowing), use {@link createNestedRouteLink}.
|
|
37
51
|
*/
|
|
38
52
|
export declare const NestedRouteLink: <TPath extends string = string>(props: TypedNestedRouteLinkProps<TPath>, children?: ChildrenList) => JSX.Element;
|
|
39
53
|
/**
|
|
40
|
-
* Creates a type-safe wrapper around NestedRouteLink constrained to a specific
|
|
41
|
-
* The returned component has the same runtime behavior but narrows
|
|
42
|
-
* valid route paths,
|
|
54
|
+
* Creates a type-safe wrapper around NestedRouteLink constrained to a specific
|
|
55
|
+
* route tree. The returned component has the same runtime behavior but narrows
|
|
56
|
+
* `path` to only accept valid route paths, requires `params` when the route
|
|
57
|
+
* has parameters, and enforces the route's declared `query` and `hash` schemas.
|
|
43
58
|
*
|
|
44
59
|
* @typeParam TRoutes - The route tree type (use `typeof yourRoutes`)
|
|
45
60
|
* @returns A narrowed NestedRouteLink component
|
|
@@ -48,15 +63,10 @@ export declare const NestedRouteLink: <TPath extends string = string>(props: Typ
|
|
|
48
63
|
* ```typescript
|
|
49
64
|
* const AppLink = createNestedRouteLink<typeof appRoutes>()
|
|
50
65
|
*
|
|
51
|
-
*
|
|
52
|
-
* <AppLink
|
|
53
|
-
*
|
|
54
|
-
* // TypeScript error: invalid path
|
|
55
|
-
* <AppLink href="/nonexistent">Error!</AppLink>
|
|
56
|
-
*
|
|
57
|
-
* // Params required for parameterized routes
|
|
58
|
-
* <AppLink href="/users/:id" params={{ id: '123' }}>User</AppLink>
|
|
66
|
+
* <AppLink path="/buttons">Buttons</AppLink>
|
|
67
|
+
* <AppLink path="/users/:id" params={{ id: '123' }}>User</AppLink>
|
|
68
|
+
* <AppLink path="/users/:id" params={{ id: '1' }} query={{ tab: 'profile' }} hash="notes">User</AppLink>
|
|
59
69
|
* ```
|
|
60
70
|
*/
|
|
61
|
-
export declare const createNestedRouteLink: <TRoutes extends Record<string, NestedRoute<any>>>() => <TPath extends ExtractRoutePaths<TRoutes>>(props:
|
|
71
|
+
export declare const createNestedRouteLink: <TRoutes extends Record<string, NestedRoute<any, any, any>>>() => <TPath extends ExtractRoutePaths<TRoutes>>(props: TreeAwareNestedRouteLinkProps<TRoutes, TPath>, children?: ChildrenList) => JSX.Element;
|
|
62
72
|
//# sourceMappingURL=nested-route-link.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-route-link.d.ts","sourceRoot":"","sources":["../../src/components/nested-route-link.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nested-route-link.d.ts","sourceRoot":"","sources":["../../src/components/nested-route-link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAKlE,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,OAAO,EACP,YAAY,EACZ,cAAc,EACd,aAAa,EACd,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,cAAc,CAAC,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,CAAA;AAE/D;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,CAAC,KAAK,SAAS,MAAM,IAAI;IAC5D,IAAI,EAAE,KAAK,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,cAAc,CAAC,KAAK,CAAC,GACvB,cAAc,CAAC,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,CAAA;AAE7D;;;;;GAKG;AACH,MAAM,MAAM,6BAA6B,CACvC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,EAC1D,KAAK,SAAS,MAAM,IAClB;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAAG,cAAc,CAAC,KAAK,CAAC,GACzC,aAAa,CAAC,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,GACzD,YAAY,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,GACvD,cAAc,CAAC,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,CAAA;AA2B7D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,EAAkC,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EAC1F,KAAK,EAAE,yBAAyB,CAAC,KAAK,CAAC,EACvC,QAAQ,CAAC,EAAE,YAAY,KACpB,GAAG,CAAC,OAAO,CAAA;AAEhB;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,OACxD,CAAC,KAAK,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAC7E,KAAK,EAAE,6BAA6B,CAAC,OAAO,EAAE,KAAK,CAAC,EACpD,QAAQ,CAAC,EAAE,YAAY,KACpB,GAAG,CAAC,OACV,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { compileRoute } from '../compile-route.js';
|
|
2
1
|
import { LocationService } from '../services/location-service.js';
|
|
3
2
|
import { createComponent } from '../shade-component.js';
|
|
4
3
|
import { Shade } from '../shade.js';
|
|
4
|
+
import { buildNestedNavigateUrl } from './nested-navigate.js';
|
|
5
5
|
const _NestedRouteLink = Shade({
|
|
6
6
|
customElementName: 'nested-route-link',
|
|
7
7
|
elementBase: HTMLAnchorElement,
|
|
@@ -11,15 +11,15 @@ const _NestedRouteLink = Shade({
|
|
|
11
11
|
textDecoration: 'inherit',
|
|
12
12
|
},
|
|
13
13
|
render: ({ children, props, injector, useHostProps }) => {
|
|
14
|
-
const {
|
|
15
|
-
const resolvedUrl =
|
|
14
|
+
const { path, params, query, hash } = props;
|
|
15
|
+
const resolvedUrl = buildNestedNavigateUrl({ path, params, query, hash });
|
|
16
16
|
useHostProps({
|
|
17
17
|
href: resolvedUrl,
|
|
18
18
|
onclick: (ev) => {
|
|
19
19
|
ev.preventDefault();
|
|
20
20
|
// eslint-disable-next-line furystack/prefer-location-service -- This IS the SPA link component; it must call pushState directly.
|
|
21
21
|
history.pushState('', props.title || '', resolvedUrl);
|
|
22
|
-
injector.
|
|
22
|
+
injector.get(LocationService).updateState();
|
|
23
23
|
},
|
|
24
24
|
});
|
|
25
25
|
return createComponent(createComponent, null, children);
|
|
@@ -30,19 +30,22 @@ const _NestedRouteLink = Shade({
|
|
|
30
30
|
* type-safe route parameter compilation.
|
|
31
31
|
*
|
|
32
32
|
* Intercepts click events to use `history.pushState` for client-side navigation,
|
|
33
|
-
*
|
|
33
|
+
* compiles parameterized routes (e.g. `/users/:id`) when `params` is provided,
|
|
34
|
+
* serializes `query` to the URL search string and appends `hash` when set.
|
|
34
35
|
*
|
|
35
|
-
* Route parameters are automatically inferred from the `
|
|
36
|
-
* - `
|
|
37
|
-
* - `
|
|
36
|
+
* Route parameters are automatically inferred from the `path` pattern:
|
|
37
|
+
* - `path="/buttons"` — `params` is optional
|
|
38
|
+
* - `path="/users/:id"` — `params: { id: string }` is required
|
|
38
39
|
*
|
|
39
|
-
* For additional URL validation against a route tree
|
|
40
|
+
* For additional URL validation against a route tree (including `query` and
|
|
41
|
+
* `hash` narrowing), use {@link createNestedRouteLink}.
|
|
40
42
|
*/
|
|
41
43
|
export const NestedRouteLink = _NestedRouteLink;
|
|
42
44
|
/**
|
|
43
|
-
* Creates a type-safe wrapper around NestedRouteLink constrained to a specific
|
|
44
|
-
* The returned component has the same runtime behavior but narrows
|
|
45
|
-
* valid route paths,
|
|
45
|
+
* Creates a type-safe wrapper around NestedRouteLink constrained to a specific
|
|
46
|
+
* route tree. The returned component has the same runtime behavior but narrows
|
|
47
|
+
* `path` to only accept valid route paths, requires `params` when the route
|
|
48
|
+
* has parameters, and enforces the route's declared `query` and `hash` schemas.
|
|
46
49
|
*
|
|
47
50
|
* @typeParam TRoutes - The route tree type (use `typeof yourRoutes`)
|
|
48
51
|
* @returns A narrowed NestedRouteLink component
|
|
@@ -51,14 +54,9 @@ export const NestedRouteLink = _NestedRouteLink;
|
|
|
51
54
|
* ```typescript
|
|
52
55
|
* const AppLink = createNestedRouteLink<typeof appRoutes>()
|
|
53
56
|
*
|
|
54
|
-
*
|
|
55
|
-
* <AppLink
|
|
56
|
-
*
|
|
57
|
-
* // TypeScript error: invalid path
|
|
58
|
-
* <AppLink href="/nonexistent">Error!</AppLink>
|
|
59
|
-
*
|
|
60
|
-
* // Params required for parameterized routes
|
|
61
|
-
* <AppLink href="/users/:id" params={{ id: '123' }}>User</AppLink>
|
|
57
|
+
* <AppLink path="/buttons">Buttons</AppLink>
|
|
58
|
+
* <AppLink path="/users/:id" params={{ id: '123' }}>User</AppLink>
|
|
59
|
+
* <AppLink path="/users/:id" params={{ id: '1' }} query={{ tab: 'profile' }} hash="notes">User</AppLink>
|
|
62
60
|
* ```
|
|
63
61
|
*/
|
|
64
62
|
export const createNestedRouteLink = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-route-link.js","sourceRoot":"","sources":["../../src/components/nested-route-link.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nested-route-link.js","sourceRoot":"","sources":["../../src/components/nested-route-link.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAoD7D,MAAM,gBAAgB,GAAG,KAAK,CAAuB;IACnD,iBAAiB,EAAE,mBAAmB;IACtC,WAAW,EAAE,iBAAiB;IAC9B,eAAe,EAAE,GAAG;IACpB,GAAG,EAAE;QACH,KAAK,EAAE,SAAS;QAChB,cAAc,EAAE,SAAS;KAC1B;IACD,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE;QACtD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;QAC3C,MAAM,WAAW,GAAG,sBAAsB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAEzE,YAAY,CAAC;YACX,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,CAAC,EAAc,EAAE,EAAE;gBAC1B,EAAE,CAAC,cAAc,EAAE,CAAA;gBACnB,iIAAiI;gBACjI,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,WAAW,CAAC,CAAA;gBACrD,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,WAAW,EAAE,CAAA;YAC7C,CAAC;SACF,CAAC,CAAA;QACF,OAAO,uCAAG,QAAQ,CAAI,CAAA;IACxB,CAAC;CACF,CAAC,CAAA;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,gBAGf,CAAA;AAEhB;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAA+D,EAAE;IACpG,OAAO,gBAGS,CAAA;AAClB,CAAC,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createInjector } from '@furystack/inject';
|
|
2
2
|
import { usingAsync } from '@furystack/utils';
|
|
3
3
|
import { afterEach, beforeEach, describe, expect, expectTypeOf, it, vi } from 'vitest';
|
|
4
4
|
import { initializeShadeRoot } from '../initialize.js';
|
|
@@ -14,26 +14,26 @@ describe('NestedRouteLink', () => {
|
|
|
14
14
|
document.body.innerHTML = '';
|
|
15
15
|
});
|
|
16
16
|
it('Should render a link with the correct href', async () => {
|
|
17
|
-
await usingAsync(
|
|
17
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
18
18
|
const rootElement = document.getElementById('root');
|
|
19
19
|
initializeShadeRoot({
|
|
20
20
|
injector,
|
|
21
21
|
rootElement,
|
|
22
|
-
jsxElement: (createComponent(NestedRouteLink, { id: "link",
|
|
22
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", path: "/buttons" }, "Buttons")),
|
|
23
23
|
});
|
|
24
24
|
await flushUpdates();
|
|
25
25
|
expect(document.body.innerHTML).toBe('<div id="root"><a is="nested-route-link" id="link" href="/buttons">Buttons</a></div>');
|
|
26
26
|
});
|
|
27
27
|
});
|
|
28
28
|
it('Should trigger SPA navigation on click', async () => {
|
|
29
|
-
await usingAsync(
|
|
29
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
30
30
|
const rootElement = document.getElementById('root');
|
|
31
31
|
const onRouteChange = vi.fn();
|
|
32
|
-
injector.
|
|
32
|
+
injector.get(LocationService).onLocationPathChanged.subscribe(onRouteChange);
|
|
33
33
|
initializeShadeRoot({
|
|
34
34
|
injector,
|
|
35
35
|
rootElement,
|
|
36
|
-
jsxElement: (createComponent(NestedRouteLink, { id: "link",
|
|
36
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", path: "/buttons" }, "Buttons")),
|
|
37
37
|
});
|
|
38
38
|
await flushUpdates();
|
|
39
39
|
expect(onRouteChange).not.toBeCalled();
|
|
@@ -42,29 +42,55 @@ describe('NestedRouteLink', () => {
|
|
|
42
42
|
});
|
|
43
43
|
});
|
|
44
44
|
it('Should compile route params in the href', async () => {
|
|
45
|
-
await usingAsync(
|
|
45
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
46
46
|
const rootElement = document.getElementById('root');
|
|
47
47
|
initializeShadeRoot({
|
|
48
48
|
injector,
|
|
49
49
|
rootElement,
|
|
50
|
-
jsxElement: (createComponent(NestedRouteLink, { id: "link",
|
|
50
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", path: "/users/:id", params: { id: '42' } }, "User 42")),
|
|
51
51
|
});
|
|
52
52
|
await flushUpdates();
|
|
53
53
|
expect(document.body.innerHTML).toBe('<div id="root"><a is="nested-route-link" id="link" href="/users/42">User 42</a></div>');
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
56
|
it('Should compile route params with multiple segments', async () => {
|
|
57
|
-
await usingAsync(
|
|
57
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
58
58
|
const rootElement = document.getElementById('root');
|
|
59
59
|
initializeShadeRoot({
|
|
60
60
|
injector,
|
|
61
61
|
rootElement,
|
|
62
|
-
jsxElement: (createComponent(NestedRouteLink, { id: "link",
|
|
62
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", path: "/users/:userId/posts/:postId", params: { userId: '1', postId: '99' } }, "Post")),
|
|
63
63
|
});
|
|
64
64
|
await flushUpdates();
|
|
65
65
|
expect(document.body.innerHTML).toBe('<div id="root"><a is="nested-route-link" id="link" href="/users/1/posts/99">Post</a></div>');
|
|
66
66
|
});
|
|
67
67
|
});
|
|
68
|
+
it('Should append a serialized query string to the rendered href', async () => {
|
|
69
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
70
|
+
const rootElement = document.getElementById('root');
|
|
71
|
+
initializeShadeRoot({
|
|
72
|
+
injector,
|
|
73
|
+
rootElement,
|
|
74
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", path: "/buttons", query: { page: 2 } }, "Buttons")),
|
|
75
|
+
});
|
|
76
|
+
await flushUpdates();
|
|
77
|
+
const link = document.getElementById('link');
|
|
78
|
+
expect(link.getAttribute('href')?.startsWith('/buttons?')).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
it('Should append the hash segment to the rendered href', async () => {
|
|
82
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
83
|
+
const rootElement = document.getElementById('root');
|
|
84
|
+
initializeShadeRoot({
|
|
85
|
+
injector,
|
|
86
|
+
rootElement,
|
|
87
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", path: "/buttons", hash: "overview" }, "Buttons")),
|
|
88
|
+
});
|
|
89
|
+
await flushUpdates();
|
|
90
|
+
const link = document.getElementById('link');
|
|
91
|
+
expect(link.getAttribute('href')).toBe('/buttons#overview');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
68
94
|
});
|
|
69
95
|
describe('Type utilities', () => {
|
|
70
96
|
describe('ConcatPaths', () => {
|
|
@@ -140,32 +166,32 @@ describe('Type utilities', () => {
|
|
|
140
166
|
});
|
|
141
167
|
});
|
|
142
168
|
describe('NestedRouteLink param inference', () => {
|
|
143
|
-
it('Should infer params as optional when
|
|
169
|
+
it('Should infer params as optional when path has no parameters', () => {
|
|
144
170
|
expectTypeOf(NestedRouteLink).parameter(0).toHaveProperty('params');
|
|
145
171
|
expectTypeOf((NestedRouteLink))
|
|
146
172
|
.parameter(0)
|
|
147
173
|
.toExtend();
|
|
148
174
|
});
|
|
149
|
-
it('Should infer params as required when
|
|
175
|
+
it('Should infer params as required when path has a parameter', () => {
|
|
150
176
|
expectTypeOf((NestedRouteLink))
|
|
151
177
|
.parameter(0)
|
|
152
178
|
.toExtend();
|
|
153
179
|
});
|
|
154
|
-
it('Should infer multiple params from
|
|
180
|
+
it('Should infer multiple params from path', () => {
|
|
155
181
|
expectTypeOf((NestedRouteLink))
|
|
156
182
|
.parameter(0)
|
|
157
183
|
.toExtend();
|
|
158
184
|
});
|
|
159
185
|
});
|
|
160
186
|
describe('createNestedRouteLink', () => {
|
|
161
|
-
it('Should constrain
|
|
187
|
+
it('Should constrain path to valid route paths', () => {
|
|
162
188
|
const AppLink = createNestedRouteLink();
|
|
163
|
-
expectTypeOf(AppLink).parameter(0).toHaveProperty('
|
|
189
|
+
expectTypeOf(AppLink).parameter(0).toHaveProperty('path');
|
|
164
190
|
});
|
|
165
191
|
it('Should reject invalid paths', () => {
|
|
166
192
|
const AppLink = createNestedRouteLink();
|
|
167
193
|
// @ts-expect-error -- '/nonexistent' is not a valid route path
|
|
168
|
-
AppLink({
|
|
194
|
+
AppLink({ path: '/nonexistent' });
|
|
169
195
|
});
|
|
170
196
|
it('Should require params for parameterized routes in the tree', () => {
|
|
171
197
|
const AppLink = createNestedRouteLink();
|
|
@@ -207,7 +233,31 @@ describe('Type utilities', () => {
|
|
|
207
233
|
},
|
|
208
234
|
};
|
|
209
235
|
const AppLink = createNestedRouteLink();
|
|
210
|
-
expectTypeOf(AppLink).parameter(0).toHaveProperty('
|
|
236
|
+
expectTypeOf(AppLink).parameter(0).toHaveProperty('path');
|
|
237
|
+
expectTypeOf((AppLink))
|
|
238
|
+
.parameter(0)
|
|
239
|
+
.toExtend();
|
|
240
|
+
});
|
|
241
|
+
it('Should enforce a declared required query shape on the link', () => {
|
|
242
|
+
const routes = {
|
|
243
|
+
'/list': {
|
|
244
|
+
component: () => null,
|
|
245
|
+
query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
const AppLink = createNestedRouteLink();
|
|
249
|
+
expectTypeOf((AppLink))
|
|
250
|
+
.parameter(0)
|
|
251
|
+
.toExtend();
|
|
252
|
+
});
|
|
253
|
+
it('Should narrow hash on the link to the declared literal tuple', () => {
|
|
254
|
+
const routes = {
|
|
255
|
+
'/tabs': {
|
|
256
|
+
component: () => null,
|
|
257
|
+
hash: ['overview', 'details'],
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
const AppLink = createNestedRouteLink();
|
|
211
261
|
expectTypeOf((AppLink))
|
|
212
262
|
.parameter(0)
|
|
213
263
|
.toExtend();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-route-link.spec.js","sourceRoot":"","sources":["../../src/components/nested-route-link.spec.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"nested-route-link.spec.js","sourceRoot":"","sources":["../../src/components/nested-route-link.spec.tsx"],"names":[],"mappings":"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"}
|