@furystack/shades 11.1.0 → 12.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 +291 -0
- package/README.md +13 -13
- package/esm/component-factory.spec.js +13 -5
- package/esm/component-factory.spec.js.map +1 -1
- package/esm/components/index.d.ts +4 -1
- package/esm/components/index.d.ts.map +1 -1
- package/esm/components/index.js +4 -1
- package/esm/components/index.js.map +1 -1
- package/esm/components/lazy-load.d.ts +2 -4
- package/esm/components/lazy-load.d.ts.map +1 -1
- package/esm/components/lazy-load.js +40 -24
- package/esm/components/lazy-load.js.map +1 -1
- package/esm/components/lazy-load.spec.js +57 -50
- package/esm/components/lazy-load.spec.js.map +1 -1
- package/esm/components/link-to-route.d.ts +2 -0
- package/esm/components/link-to-route.d.ts.map +1 -1
- package/esm/components/link-to-route.js +3 -2
- package/esm/components/link-to-route.js.map +1 -1
- package/esm/components/link-to-route.spec.js +13 -9
- package/esm/components/link-to-route.spec.js.map +1 -1
- package/esm/components/nested-route-link.d.ts +62 -0
- package/esm/components/nested-route-link.d.ts.map +1 -0
- package/esm/components/nested-route-link.js +66 -0
- package/esm/components/nested-route-link.js.map +1 -0
- package/esm/components/nested-route-link.spec.d.ts +2 -0
- package/esm/components/nested-route-link.spec.d.ts.map +1 -0
- package/esm/components/nested-route-link.spec.js +179 -0
- package/esm/components/nested-route-link.spec.js.map +1 -0
- package/esm/components/nested-route-types.d.ts +37 -0
- package/esm/components/nested-route-types.d.ts.map +1 -0
- package/esm/components/nested-route-types.js +2 -0
- package/esm/components/nested-route-types.js.map +1 -0
- package/esm/components/nested-router.d.ts +103 -0
- package/esm/components/nested-router.d.ts.map +1 -0
- package/esm/components/nested-router.js +178 -0
- package/esm/components/nested-router.js.map +1 -0
- package/esm/components/nested-router.spec.d.ts +2 -0
- package/esm/components/nested-router.spec.d.ts.map +1 -0
- package/esm/components/nested-router.spec.js +659 -0
- package/esm/components/nested-router.spec.js.map +1 -0
- package/esm/components/route-link.d.ts +4 -0
- package/esm/components/route-link.d.ts.map +1 -1
- package/esm/components/route-link.js +5 -5
- package/esm/components/route-link.js.map +1 -1
- package/esm/components/route-link.spec.js +16 -12
- package/esm/components/route-link.spec.js.map +1 -1
- package/esm/components/router.d.ts +20 -2
- package/esm/components/router.d.ts.map +1 -1
- package/esm/components/router.js +3 -0
- package/esm/components/router.js.map +1 -1
- package/esm/components/router.spec.js +75 -74
- package/esm/components/router.spec.js.map +1 -1
- package/esm/initialize.d.ts +11 -0
- package/esm/initialize.d.ts.map +1 -1
- package/esm/initialize.js +5 -0
- package/esm/initialize.js.map +1 -1
- package/esm/jsx.d.ts +83 -2
- package/esm/jsx.d.ts.map +1 -1
- package/esm/models/children-list.d.ts +5 -1
- package/esm/models/children-list.d.ts.map +1 -1
- package/esm/models/partial-element.d.ts +12 -2
- package/esm/models/partial-element.d.ts.map +1 -1
- package/esm/models/render-options.d.ts +89 -3
- package/esm/models/render-options.d.ts.map +1 -1
- package/esm/models/selection-state.d.ts +4 -0
- package/esm/models/selection-state.d.ts.map +1 -1
- package/esm/services/location-service.d.ts +11 -0
- package/esm/services/location-service.d.ts.map +1 -1
- package/esm/services/location-service.js +11 -0
- package/esm/services/location-service.js.map +1 -1
- package/esm/services/resource-manager.d.ts +24 -0
- package/esm/services/resource-manager.d.ts.map +1 -1
- package/esm/services/resource-manager.js +30 -0
- package/esm/services/resource-manager.js.map +1 -1
- package/esm/services/resource-manager.spec.js +93 -0
- package/esm/services/resource-manager.spec.js.map +1 -1
- package/esm/services/screen-service.d.ts +81 -4
- package/esm/services/screen-service.d.ts.map +1 -1
- package/esm/services/screen-service.js +75 -4
- package/esm/services/screen-service.js.map +1 -1
- package/esm/services/screen-service.spec.js +91 -7
- package/esm/services/screen-service.spec.js.map +1 -1
- package/esm/shade-component.d.ts +17 -4
- package/esm/shade-component.d.ts.map +1 -1
- package/esm/shade-component.js +67 -5
- package/esm/shade-component.js.map +1 -1
- package/esm/shade-host-props-ref.integration.spec.d.ts +2 -0
- package/esm/shade-host-props-ref.integration.spec.d.ts.map +1 -0
- package/esm/shade-host-props-ref.integration.spec.js +381 -0
- package/esm/shade-host-props-ref.integration.spec.js.map +1 -0
- package/esm/shade-resources.integration.spec.js +208 -39
- package/esm/shade-resources.integration.spec.js.map +1 -1
- package/esm/shade.d.ts +20 -17
- package/esm/shade.d.ts.map +1 -1
- package/esm/shade.js +172 -33
- package/esm/shade.js.map +1 -1
- package/esm/shade.spec.js +31 -30
- package/esm/shade.spec.js.map +1 -1
- package/esm/shades.integration.spec.js +135 -72
- package/esm/shades.integration.spec.js.map +1 -1
- package/esm/style-manager.d.ts +2 -2
- package/esm/style-manager.js +2 -2
- package/esm/svg-types.d.ts +389 -0
- package/esm/svg-types.d.ts.map +1 -0
- package/esm/svg-types.js +9 -0
- package/esm/svg-types.js.map +1 -0
- package/esm/svg.d.ts +15 -0
- package/esm/svg.d.ts.map +1 -0
- package/esm/svg.js +76 -0
- package/esm/svg.js.map +1 -0
- package/esm/svg.spec.d.ts +2 -0
- package/esm/svg.spec.d.ts.map +1 -0
- package/esm/svg.spec.js +80 -0
- package/esm/svg.spec.js.map +1 -0
- package/esm/vnode.d.ts +103 -0
- package/esm/vnode.d.ts.map +1 -0
- package/esm/vnode.integration.spec.d.ts +2 -0
- package/esm/vnode.integration.spec.d.ts.map +1 -0
- package/esm/vnode.integration.spec.js +494 -0
- package/esm/vnode.integration.spec.js.map +1 -0
- package/esm/vnode.js +453 -0
- package/esm/vnode.js.map +1 -0
- package/esm/vnode.spec.d.ts +2 -0
- package/esm/vnode.spec.d.ts.map +1 -0
- package/esm/vnode.spec.js +473 -0
- package/esm/vnode.spec.js.map +1 -0
- package/package.json +3 -3
- package/src/component-factory.spec.tsx +18 -5
- package/src/components/index.ts +4 -1
- package/src/components/lazy-load.spec.tsx +82 -75
- package/src/components/lazy-load.tsx +49 -27
- package/src/components/link-to-route.spec.tsx +25 -21
- package/src/components/link-to-route.tsx +4 -2
- package/src/components/nested-route-link.spec.tsx +303 -0
- package/src/components/nested-route-link.tsx +100 -0
- package/src/components/nested-route-types.ts +42 -0
- package/src/components/nested-router.spec.tsx +817 -0
- package/src/components/nested-router.tsx +256 -0
- package/src/components/route-link.spec.tsx +22 -18
- package/src/components/route-link.tsx +6 -5
- package/src/components/router.spec.tsx +109 -108
- package/src/components/router.tsx +15 -2
- package/src/initialize.ts +12 -0
- package/src/jsx.ts +129 -2
- package/src/models/children-list.ts +7 -1
- package/src/models/partial-element.ts +13 -2
- package/src/models/render-options.ts +90 -3
- package/src/models/selection-state.ts +4 -0
- package/src/services/location-service.tsx +11 -0
- package/src/services/resource-manager.spec.ts +116 -0
- package/src/services/resource-manager.ts +30 -0
- package/src/services/screen-service.spec.ts +109 -7
- package/src/services/screen-service.ts +81 -4
- package/src/shade-component.ts +72 -6
- package/src/shade-host-props-ref.integration.spec.tsx +460 -0
- package/src/shade-resources.integration.spec.tsx +276 -52
- package/src/shade.spec.tsx +40 -39
- package/src/shade.ts +186 -58
- package/src/shades.integration.spec.tsx +154 -80
- package/src/style-manager.ts +2 -2
- package/src/svg-types.ts +437 -0
- package/src/svg.spec.ts +89 -0
- package/src/svg.ts +78 -0
- package/src/vnode.integration.spec.tsx +657 -0
- package/src/vnode.spec.ts +579 -0
- package/src/vnode.ts +508 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject';
|
|
2
|
-
import { sleepAsync } from '@furystack/utils';
|
|
2
|
+
import { sleepAsync, usingAsync } from '@furystack/utils';
|
|
3
3
|
import { LazyLoad } from './lazy-load.js';
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
5
|
import { initializeShadeRoot } from '../initialize.js';
|
|
6
6
|
import { createComponent } from '../shade-component.js';
|
|
7
|
+
import { flushUpdates } from '../shade.js';
|
|
7
8
|
describe('Lazy Load', () => {
|
|
8
9
|
beforeEach(() => {
|
|
9
10
|
document.body.innerHTML = '<div id="root"></div>';
|
|
@@ -12,62 +13,68 @@ describe('Lazy Load', () => {
|
|
|
12
13
|
document.body.innerHTML = '';
|
|
13
14
|
});
|
|
14
15
|
it('Shuld display the loader and completed state', async () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
17
|
+
const rootElement = document.getElementById('root');
|
|
18
|
+
initializeShadeRoot({
|
|
19
|
+
injector,
|
|
20
|
+
rootElement,
|
|
21
|
+
jsxElement: (createComponent(LazyLoad, { loader: createComponent("div", null, "Loading..."), component: async () => {
|
|
22
|
+
await sleepAsync(100);
|
|
23
|
+
return createComponent("div", null, "Loaded");
|
|
24
|
+
} })),
|
|
25
|
+
});
|
|
26
|
+
await flushUpdates();
|
|
27
|
+
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>Loading...</div></lazy-load></div>');
|
|
28
|
+
await sleepAsync(150);
|
|
29
|
+
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>Loaded</div></lazy-load></div>');
|
|
24
30
|
});
|
|
25
|
-
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>Loading...</div></lazy-load></div>');
|
|
26
|
-
await sleepAsync(150);
|
|
27
|
-
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>Loaded</div></lazy-load></div>');
|
|
28
31
|
});
|
|
29
32
|
it('Shuld display the failed state with a retryer', async () => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
34
|
+
const rootElement = document.getElementById('root');
|
|
35
|
+
const load = vi.fn(async () => {
|
|
36
|
+
throw Error(':(');
|
|
37
|
+
});
|
|
38
|
+
initializeShadeRoot({
|
|
39
|
+
injector,
|
|
40
|
+
rootElement,
|
|
41
|
+
jsxElement: (createComponent(LazyLoad, { loader: createComponent("div", null, "Loading..."), component: load, error: (e, retry) => (createComponent("button", { id: "retry", onclick: retry }, e.message)) })),
|
|
42
|
+
});
|
|
43
|
+
await flushUpdates();
|
|
44
|
+
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>Loading...</div></lazy-load></div>');
|
|
45
|
+
await sleepAsync(1);
|
|
46
|
+
expect(load).toBeCalledTimes(1);
|
|
47
|
+
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><button id="retry">:(</button></lazy-load></div>');
|
|
48
|
+
document.getElementById('retry')?.click();
|
|
49
|
+
expect(load).toBeCalledTimes(2);
|
|
39
50
|
});
|
|
40
|
-
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>Loading...</div></lazy-load></div>');
|
|
41
|
-
await sleepAsync(1);
|
|
42
|
-
expect(load).toBeCalledTimes(1);
|
|
43
|
-
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><button id="retry">:(</button></lazy-load></div>');
|
|
44
|
-
document.getElementById('retry')?.click();
|
|
45
|
-
expect(load).toBeCalledTimes(2);
|
|
46
51
|
});
|
|
47
52
|
it('Shuld display the failed state with a retryer', async () => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
54
|
+
const rootElement = document.getElementById('root');
|
|
55
|
+
let counter = 0;
|
|
56
|
+
const load = vi.fn(async () => {
|
|
57
|
+
if (!counter) {
|
|
58
|
+
counter += 1;
|
|
59
|
+
throw Error(':(');
|
|
60
|
+
}
|
|
61
|
+
return createComponent("div", null, "success");
|
|
62
|
+
});
|
|
63
|
+
initializeShadeRoot({
|
|
64
|
+
injector,
|
|
65
|
+
rootElement,
|
|
66
|
+
jsxElement: (createComponent(LazyLoad, { loader: createComponent("div", null, "Loading..."), component: load, error: (e, retry) => (createComponent("button", { id: "retry", onclick: retry }, e.message)) })),
|
|
67
|
+
});
|
|
68
|
+
await flushUpdates();
|
|
69
|
+
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>Loading...</div></lazy-load></div>');
|
|
70
|
+
await sleepAsync(1);
|
|
71
|
+
expect(load).toBeCalledTimes(1);
|
|
72
|
+
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><button id="retry">:(</button></lazy-load></div>');
|
|
73
|
+
document.getElementById('retry')?.click();
|
|
74
|
+
expect(load).toBeCalledTimes(2);
|
|
75
|
+
await sleepAsync(1);
|
|
76
|
+
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>success</div></lazy-load></div>');
|
|
62
77
|
});
|
|
63
|
-
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>Loading...</div></lazy-load></div>');
|
|
64
|
-
await sleepAsync(1);
|
|
65
|
-
expect(load).toBeCalledTimes(1);
|
|
66
|
-
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><button id="retry">:(</button></lazy-load></div>');
|
|
67
|
-
document.getElementById('retry')?.click();
|
|
68
|
-
expect(load).toBeCalledTimes(2);
|
|
69
|
-
await sleepAsync(1);
|
|
70
|
-
expect(document.body.innerHTML).toBe('<div id="root"><lazy-load><div>success</div></lazy-load></div>');
|
|
71
78
|
});
|
|
72
79
|
});
|
|
73
80
|
//# sourceMappingURL=lazy-load.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy-load.spec.js","sourceRoot":"","sources":["../../src/components/lazy-load.spec.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"lazy-load.spec.js","sourceRoot":"","sources":["../../src/components/lazy-load.spec.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { ChildrenList } from '../models/children-list.js';
|
|
2
2
|
import type { Route } from './router.js';
|
|
3
|
+
/** @deprecated Use `NestedRouteLinkProps` from `nested-route-link` instead */
|
|
3
4
|
export type LinkToRouteProps<T extends object> = {
|
|
4
5
|
route: Route<T>;
|
|
5
6
|
params: T;
|
|
6
7
|
} & Omit<JSX.IntrinsicElements['a'], 'href'>;
|
|
8
|
+
/** @deprecated Use `NestedRouteLink` from `nested-route-link` instead */
|
|
7
9
|
export declare const LinkToRoute: <T extends object>(props: LinkToRouteProps<T>, children?: ChildrenList) => JSX.Element;
|
|
8
10
|
//# sourceMappingURL=link-to-route.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-to-route.d.ts","sourceRoot":"","sources":["../../src/components/link-to-route.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAG9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAExC,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,IAAI;IAC/C,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;IACf,MAAM,EAAE,CAAC,CAAA;CACV,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAA;AAE5C,eAAO,MAAM,WAAW,EAAE,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,YAAY,KAAK,GAAG,CAAC,OAYrG,CAAA"}
|
|
1
|
+
{"version":3,"file":"link-to-route.d.ts","sourceRoot":"","sources":["../../src/components/link-to-route.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAG9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAExC,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,IAAI;IAC/C,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;IACf,MAAM,EAAE,CAAC,CAAA;CACV,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAA;AAE5C,yEAAyE;AACzE,eAAO,MAAM,WAAW,EAAE,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,YAAY,KAAK,GAAG,CAAC,OAYrG,CAAA"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { compileRoute } from '../compile-route.js';
|
|
2
2
|
import { createComponent } from '../shade-component.js';
|
|
3
3
|
import { Shade } from '../shade.js';
|
|
4
|
+
/** @deprecated Use `NestedRouteLink` from `nested-route-link` instead */
|
|
4
5
|
export const LinkToRoute = Shade({
|
|
5
6
|
shadowDomName: 'link-to-route',
|
|
6
7
|
elementBase: HTMLAnchorElement,
|
|
7
8
|
elementBaseName: 'a',
|
|
8
|
-
render: ({ props,
|
|
9
|
+
render: ({ props, useHostProps, children }) => {
|
|
9
10
|
const { route, params } = props;
|
|
10
11
|
const url = compileRoute(route.url, params);
|
|
11
|
-
|
|
12
|
+
useHostProps({ href: url });
|
|
12
13
|
return createComponent(createComponent, null, children);
|
|
13
14
|
},
|
|
14
15
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-to-route.js","sourceRoot":"","sources":["../../src/components/link-to-route.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"link-to-route.js","sourceRoot":"","sources":["../../src/components/link-to-route.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AASnC,yEAAyE;AACzE,MAAM,CAAC,MAAM,WAAW,GACtB,KAAK,CAAC;IACJ,aAAa,EAAE,eAAe;IAC9B,WAAW,EAAE,iBAAiB;IAC9B,eAAe,EAAE,GAAG;IACpB,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC5C,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;QAE/B,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QAC3C,YAAY,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;QAC3B,OAAO,uCAAG,QAAQ,CAAI,CAAA;IACxB,CAAC;CACF,CAAC,CAAA"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject';
|
|
2
|
+
import { usingAsync } from '@furystack/utils';
|
|
2
3
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
4
|
import { initializeShadeRoot } from '../initialize.js';
|
|
4
5
|
import { createComponent } from '../shade-component.js';
|
|
6
|
+
import { flushUpdates } from '../shade.js';
|
|
5
7
|
import { LinkToRoute } from './link-to-route.js';
|
|
6
8
|
describe('LinkToRoute', () => {
|
|
7
9
|
beforeEach(() => {
|
|
@@ -11,16 +13,18 @@ describe('LinkToRoute', () => {
|
|
|
11
13
|
document.body.innerHTML = '';
|
|
12
14
|
});
|
|
13
15
|
it('Shuld display the loader and completed state', async () => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
17
|
+
const rootElement = document.getElementById('root');
|
|
18
|
+
initializeShadeRoot({
|
|
19
|
+
injector,
|
|
20
|
+
rootElement,
|
|
21
|
+
jsxElement: (createComponent(LinkToRoute, { route: {
|
|
22
|
+
url: '/subroute/:id',
|
|
23
|
+
}, params: { id: 123 }, id: "route" }, "Link")),
|
|
24
|
+
});
|
|
25
|
+
await flushUpdates();
|
|
26
|
+
expect(document.body.innerHTML).toBe('<div id="root"><a is="link-to-route" id="route" href="/subroute/123">Link</a></div>');
|
|
22
27
|
});
|
|
23
|
-
expect(document.body.innerHTML).toBe('<div id="root"><a is="link-to-route" id="route" href="/subroute/123">Link</a></div>');
|
|
24
28
|
});
|
|
25
29
|
});
|
|
26
30
|
//# sourceMappingURL=link-to-route.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-to-route.spec.js","sourceRoot":"","sources":["../../src/components/link-to-route.spec.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGhD,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,uBAAuB,CAAA;IACnD,CAAC,CAAC,CAAA;IACF,SAAS,CAAC,GAAG,EAAE;QACb,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IAC9B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,
|
|
1
|
+
{"version":3,"file":"link-to-route.spec.js","sourceRoot":"","sources":["../../src/components/link-to-route.spec.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGhD,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,uBAAuB,CAAA;IACnD,CAAC,CAAC,CAAA;IACF,SAAS,CAAC,GAAG,EAAE;QACb,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IAC9B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,UAAU,CAAC,IAAI,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YAClD,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAmB,CAAA;YAErE,mBAAmB,CAAC;gBAClB,QAAQ;gBACR,WAAW;gBACX,UAAU,EAAE,CACV,gBAAC,WAAW,IACV,KAAK,EACH;wBACE,GAAG,EAAE,eAAe;qBACI,EAE5B,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EACnB,EAAE,EAAC,OAAO,WAGE,CACf;aACF,CAAC,CAAA;YACF,MAAM,YAAY,EAAE,CAAA;YACpB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAClC,qFAAqF,CACtF,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ChildrenList } from '../models/children-list.js';
|
|
2
|
+
import type { PartialElement } from '../models/partial-element.js';
|
|
3
|
+
import type { ExtractRouteParams, ExtractRoutePaths } from './nested-route-types.js';
|
|
4
|
+
import type { NestedRoute } from './nested-router.js';
|
|
5
|
+
/**
|
|
6
|
+
* Props for the NestedRouteLink component.
|
|
7
|
+
* Combines SPA navigation from RouteLink with parameter compilation from LinkToRoute.
|
|
8
|
+
*/
|
|
9
|
+
export type NestedRouteLinkProps = {
|
|
10
|
+
href: string;
|
|
11
|
+
params?: Record<string, string>;
|
|
12
|
+
} & PartialElement<Omit<HTMLAnchorElement, 'onclick' | 'href'>>;
|
|
13
|
+
/**
|
|
14
|
+
* Props for a type-safe nested route link.
|
|
15
|
+
* When the path contains parameters (e.g. `:id`), the `params` prop becomes required.
|
|
16
|
+
* @typeParam TPath - A specific route path string
|
|
17
|
+
*/
|
|
18
|
+
export type TypedNestedRouteLinkProps<TPath extends string> = {
|
|
19
|
+
href: TPath;
|
|
20
|
+
} & (string extends keyof ExtractRouteParams<TPath> ? {
|
|
21
|
+
params?: Record<string, string>;
|
|
22
|
+
} : {
|
|
23
|
+
params: ExtractRouteParams<TPath>;
|
|
24
|
+
}) & PartialElement<Omit<HTMLAnchorElement, 'onclick' | 'href'>>;
|
|
25
|
+
/**
|
|
26
|
+
* A link component for NestedRouter that supports SPA navigation with
|
|
27
|
+
* type-safe route parameter compilation.
|
|
28
|
+
*
|
|
29
|
+
* Intercepts click events to use `history.pushState` for client-side navigation,
|
|
30
|
+
* and compiles parameterized routes (e.g. `/users/:id`) when `params` is provided.
|
|
31
|
+
*
|
|
32
|
+
* Route parameters are automatically inferred from the `href` pattern:
|
|
33
|
+
* - `href="/buttons"` — `params` is optional
|
|
34
|
+
* - `href="/users/:id"` — `params: { id: string }` is required
|
|
35
|
+
*
|
|
36
|
+
* For additional URL validation against a route tree, use {@link createNestedRouteLink}.
|
|
37
|
+
*/
|
|
38
|
+
export declare const NestedRouteLink: <TPath extends string = string>(props: TypedNestedRouteLinkProps<TPath>, children?: ChildrenList) => JSX.Element;
|
|
39
|
+
/**
|
|
40
|
+
* Creates a type-safe wrapper around NestedRouteLink constrained to a specific route tree.
|
|
41
|
+
* The returned component has the same runtime behavior but narrows `href` to only accept
|
|
42
|
+
* valid route paths, and requires `params` when the route has parameters.
|
|
43
|
+
*
|
|
44
|
+
* @typeParam TRoutes - The route tree type (use `typeof yourRoutes`)
|
|
45
|
+
* @returns A narrowed NestedRouteLink component
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const AppLink = createNestedRouteLink<typeof appRoutes>()
|
|
50
|
+
*
|
|
51
|
+
* // Type-safe: only valid paths accepted
|
|
52
|
+
* <AppLink href="/buttons">Buttons</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>
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare const createNestedRouteLink: <TRoutes extends Record<string, NestedRoute<unknown>>>() => <TPath extends ExtractRoutePaths<TRoutes>>(props: TypedNestedRouteLinkProps<TPath>, children?: ChildrenList) => JSX.Element;
|
|
62
|
+
//# sourceMappingURL=nested-route-link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-route-link.d.ts","sourceRoot":"","sources":["../../src/components/nested-route-link.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAIlE,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC,GAAG,cAAc,CAAC,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,CAAA;AAE/D;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,CAAC,KAAK,SAAS,MAAM,IAAI;IAC5D,IAAI,EAAE,KAAK,CAAA;CACZ,GAAG,CAAC,MAAM,SAAS,MAAM,kBAAkB,CAAC,KAAK,CAAC,GAC/C;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAA;CAAE,CAAC,GACxC,cAAc,CAAC,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,CAAA;AA0B7D;;;;;;;;;;;;GAYG;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;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,OAClD,CAAC,KAAK,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAC7E,KAAK,EAAE,yBAAyB,CAAC,KAAK,CAAC,EACvC,QAAQ,CAAC,EAAE,YAAY,KACpB,GAAG,CAAC,OACV,CAAA"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { compileRoute } from '../compile-route.js';
|
|
2
|
+
import { LocationService } from '../services/location-service.js';
|
|
3
|
+
import { createComponent } from '../shade-component.js';
|
|
4
|
+
import { Shade } from '../shade.js';
|
|
5
|
+
const _NestedRouteLink = Shade({
|
|
6
|
+
shadowDomName: 'nested-route-link',
|
|
7
|
+
elementBase: HTMLAnchorElement,
|
|
8
|
+
elementBaseName: 'a',
|
|
9
|
+
css: {
|
|
10
|
+
color: 'inherit',
|
|
11
|
+
textDecoration: 'inherit',
|
|
12
|
+
},
|
|
13
|
+
render: ({ children, props, injector, useHostProps }) => {
|
|
14
|
+
const { href, params } = props;
|
|
15
|
+
const resolvedUrl = params ? compileRoute(href, params) : href;
|
|
16
|
+
useHostProps({
|
|
17
|
+
href: resolvedUrl,
|
|
18
|
+
onclick: (ev) => {
|
|
19
|
+
ev.preventDefault();
|
|
20
|
+
history.pushState('', props.title || '', resolvedUrl);
|
|
21
|
+
injector.getInstance(LocationService).updateState();
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
return createComponent(createComponent, null, children);
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* A link component for NestedRouter that supports SPA navigation with
|
|
29
|
+
* type-safe route parameter compilation.
|
|
30
|
+
*
|
|
31
|
+
* Intercepts click events to use `history.pushState` for client-side navigation,
|
|
32
|
+
* and compiles parameterized routes (e.g. `/users/:id`) when `params` is provided.
|
|
33
|
+
*
|
|
34
|
+
* Route parameters are automatically inferred from the `href` pattern:
|
|
35
|
+
* - `href="/buttons"` — `params` is optional
|
|
36
|
+
* - `href="/users/:id"` — `params: { id: string }` is required
|
|
37
|
+
*
|
|
38
|
+
* For additional URL validation against a route tree, use {@link createNestedRouteLink}.
|
|
39
|
+
*/
|
|
40
|
+
export const NestedRouteLink = _NestedRouteLink;
|
|
41
|
+
/**
|
|
42
|
+
* Creates a type-safe wrapper around NestedRouteLink constrained to a specific route tree.
|
|
43
|
+
* The returned component has the same runtime behavior but narrows `href` to only accept
|
|
44
|
+
* valid route paths, and requires `params` when the route has parameters.
|
|
45
|
+
*
|
|
46
|
+
* @typeParam TRoutes - The route tree type (use `typeof yourRoutes`)
|
|
47
|
+
* @returns A narrowed NestedRouteLink component
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const AppLink = createNestedRouteLink<typeof appRoutes>()
|
|
52
|
+
*
|
|
53
|
+
* // Type-safe: only valid paths accepted
|
|
54
|
+
* <AppLink href="/buttons">Buttons</AppLink>
|
|
55
|
+
*
|
|
56
|
+
* // TypeScript error: invalid path
|
|
57
|
+
* <AppLink href="/nonexistent">Error!</AppLink>
|
|
58
|
+
*
|
|
59
|
+
* // Params required for parameterized routes
|
|
60
|
+
* <AppLink href="/users/:id" params={{ id: '123' }}>User</AppLink>
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export const createNestedRouteLink = () => {
|
|
64
|
+
return _NestedRouteLink;
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=nested-route-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-route-link.js","sourceRoot":"","sources":["../../src/components/nested-route-link.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAyBnC,MAAM,gBAAgB,GAAG,KAAK,CAAuB;IACnD,aAAa,EAAE,mBAAmB;IAClC,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,GAAG,KAAK,CAAA;QAC9B,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAE9D,YAAY,CAAC;YACX,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,CAAC,EAAc,EAAE,EAAE;gBAC1B,EAAE,CAAC,cAAc,EAAE,CAAA;gBACnB,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,WAAW,CAAC,CAAA;gBACrD,QAAQ,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,WAAW,EAAE,CAAA;YACrD,CAAC;SACF,CAAC,CAAA;QACF,OAAO,uCAAG,QAAQ,CAAI,CAAA;IACxB,CAAC;CACF,CAAC,CAAA;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,gBAGf,CAAA;AAEhB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAyD,EAAE;IAC9F,OAAO,gBAGS,CAAA;AAClB,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-route-link.spec.d.ts","sourceRoot":"","sources":["../../src/components/nested-route-link.spec.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject';
|
|
2
|
+
import { usingAsync } from '@furystack/utils';
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, expectTypeOf, it, vi } from 'vitest';
|
|
4
|
+
import { initializeShadeRoot } from '../initialize.js';
|
|
5
|
+
import { LocationService } from '../services/location-service.js';
|
|
6
|
+
import { createComponent } from '../shade-component.js';
|
|
7
|
+
import { flushUpdates } from '../shade.js';
|
|
8
|
+
import { NestedRouteLink, createNestedRouteLink } from './nested-route-link.js';
|
|
9
|
+
describe('NestedRouteLink', () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
document.body.innerHTML = '<div id="root"></div>';
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
document.body.innerHTML = '';
|
|
15
|
+
});
|
|
16
|
+
it('Should render a link with the correct href', async () => {
|
|
17
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
18
|
+
const rootElement = document.getElementById('root');
|
|
19
|
+
initializeShadeRoot({
|
|
20
|
+
injector,
|
|
21
|
+
rootElement,
|
|
22
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", href: "/buttons" }, "Buttons")),
|
|
23
|
+
});
|
|
24
|
+
await flushUpdates();
|
|
25
|
+
expect(document.body.innerHTML).toBe('<div id="root"><a is="nested-route-link" id="link" href="/buttons">Buttons</a></div>');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
it('Should trigger SPA navigation on click', async () => {
|
|
29
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
30
|
+
const rootElement = document.getElementById('root');
|
|
31
|
+
const onRouteChange = vi.fn();
|
|
32
|
+
injector.getInstance(LocationService).onLocationPathChanged.subscribe(onRouteChange);
|
|
33
|
+
initializeShadeRoot({
|
|
34
|
+
injector,
|
|
35
|
+
rootElement,
|
|
36
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", href: "/buttons" }, "Buttons")),
|
|
37
|
+
});
|
|
38
|
+
await flushUpdates();
|
|
39
|
+
expect(onRouteChange).not.toBeCalled();
|
|
40
|
+
document.getElementById('link')?.click();
|
|
41
|
+
expect(onRouteChange).toBeCalledTimes(1);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
it('Should compile route params in the href', async () => {
|
|
45
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
46
|
+
const rootElement = document.getElementById('root');
|
|
47
|
+
initializeShadeRoot({
|
|
48
|
+
injector,
|
|
49
|
+
rootElement,
|
|
50
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", href: "/users/:id", params: { id: '42' } }, "User 42")),
|
|
51
|
+
});
|
|
52
|
+
await flushUpdates();
|
|
53
|
+
expect(document.body.innerHTML).toBe('<div id="root"><a is="nested-route-link" id="link" href="/users/42">User 42</a></div>');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
it('Should compile route params with multiple segments', async () => {
|
|
57
|
+
await usingAsync(new Injector(), async (injector) => {
|
|
58
|
+
const rootElement = document.getElementById('root');
|
|
59
|
+
initializeShadeRoot({
|
|
60
|
+
injector,
|
|
61
|
+
rootElement,
|
|
62
|
+
jsxElement: (createComponent(NestedRouteLink, { id: "link", href: "/users/:userId/posts/:postId", params: { userId: '1', postId: '99' } }, "Post")),
|
|
63
|
+
});
|
|
64
|
+
await flushUpdates();
|
|
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
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('Type utilities', () => {
|
|
70
|
+
describe('ConcatPaths', () => {
|
|
71
|
+
it('Should strip root "/" when concatenating', () => {
|
|
72
|
+
expectTypeOf().toEqualTypeOf();
|
|
73
|
+
});
|
|
74
|
+
it('Should concatenate non-root parent paths', () => {
|
|
75
|
+
expectTypeOf().toEqualTypeOf();
|
|
76
|
+
});
|
|
77
|
+
it('Should handle deeply nested paths', () => {
|
|
78
|
+
expectTypeOf().toEqualTypeOf();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('ExtractRouteParams', () => {
|
|
82
|
+
it('Should return Record<string, never> for paths without params', () => {
|
|
83
|
+
expectTypeOf().toEqualTypeOf();
|
|
84
|
+
});
|
|
85
|
+
it('Should extract a single param', () => {
|
|
86
|
+
expectTypeOf().toEqualTypeOf();
|
|
87
|
+
});
|
|
88
|
+
it('Should extract multiple params', () => {
|
|
89
|
+
expectTypeOf().toEqualTypeOf();
|
|
90
|
+
});
|
|
91
|
+
it('Should handle params at the beginning of the path', () => {
|
|
92
|
+
expectTypeOf().toEqualTypeOf();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe('ExtractRoutePaths', () => {
|
|
96
|
+
it('Should extract top-level paths', () => {
|
|
97
|
+
expectTypeOf().toEqualTypeOf();
|
|
98
|
+
});
|
|
99
|
+
it('Should extract nested child paths with root parent', () => {
|
|
100
|
+
expectTypeOf().toEqualTypeOf();
|
|
101
|
+
});
|
|
102
|
+
it('Should extract nested child paths with non-root parent', () => {
|
|
103
|
+
expectTypeOf().toEqualTypeOf();
|
|
104
|
+
});
|
|
105
|
+
it('Should handle mixed flat and nested routes', () => {
|
|
106
|
+
expectTypeOf().toEqualTypeOf();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('UrlTree', () => {
|
|
110
|
+
it('Should accept a flat object of valid paths', () => {
|
|
111
|
+
const urls = {
|
|
112
|
+
a: '/a',
|
|
113
|
+
b: '/b',
|
|
114
|
+
};
|
|
115
|
+
expectTypeOf(urls).toExtend();
|
|
116
|
+
});
|
|
117
|
+
it('Should accept nested objects of valid paths', () => {
|
|
118
|
+
const urls = {
|
|
119
|
+
home: '/',
|
|
120
|
+
buttons: '/buttons',
|
|
121
|
+
layoutTests: {
|
|
122
|
+
index: '/layout-tests',
|
|
123
|
+
appBarOnly: '/layout-tests/appbar-only',
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
expectTypeOf(urls).toExtend();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('TypedNestedRouteLinkProps', () => {
|
|
130
|
+
it('Should make params optional for paths without parameters', () => {
|
|
131
|
+
expectTypeOf().toEqualTypeOf();
|
|
132
|
+
expectTypeOf().toExtend();
|
|
133
|
+
});
|
|
134
|
+
it('Should require params for parameterized paths', () => {
|
|
135
|
+
expectTypeOf().toEqualTypeOf();
|
|
136
|
+
expectTypeOf().toExtend();
|
|
137
|
+
});
|
|
138
|
+
it('Should require all params for multi-param paths', () => {
|
|
139
|
+
expectTypeOf().toExtend();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe('NestedRouteLink param inference', () => {
|
|
143
|
+
it('Should infer params as optional when href has no parameters', () => {
|
|
144
|
+
expectTypeOf(NestedRouteLink).parameter(0).toHaveProperty('params');
|
|
145
|
+
expectTypeOf((NestedRouteLink))
|
|
146
|
+
.parameter(0)
|
|
147
|
+
.toExtend();
|
|
148
|
+
});
|
|
149
|
+
it('Should infer params as required when href has a parameter', () => {
|
|
150
|
+
expectTypeOf((NestedRouteLink))
|
|
151
|
+
.parameter(0)
|
|
152
|
+
.toExtend();
|
|
153
|
+
});
|
|
154
|
+
it('Should infer multiple params from href', () => {
|
|
155
|
+
expectTypeOf((NestedRouteLink))
|
|
156
|
+
.parameter(0)
|
|
157
|
+
.toExtend();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('createNestedRouteLink', () => {
|
|
161
|
+
it('Should constrain href to valid route paths', () => {
|
|
162
|
+
const AppLink = createNestedRouteLink();
|
|
163
|
+
expectTypeOf(AppLink).parameter(0).toHaveProperty('href');
|
|
164
|
+
});
|
|
165
|
+
it('Should require params for parameterized routes in the tree', () => {
|
|
166
|
+
const AppLink = createNestedRouteLink();
|
|
167
|
+
expectTypeOf((AppLink))
|
|
168
|
+
.parameter(0)
|
|
169
|
+
.toExtend();
|
|
170
|
+
});
|
|
171
|
+
it('Should require combined params from parent and child route segments', () => {
|
|
172
|
+
const AppLink = createNestedRouteLink();
|
|
173
|
+
expectTypeOf((AppLink))
|
|
174
|
+
.parameter(0)
|
|
175
|
+
.toExtend();
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
//# sourceMappingURL=nested-route-link.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-route-link.spec.js","sourceRoot":"","sources":["../../src/components/nested-route-link.spec.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { NestedRoute } from './nested-router.js';
|
|
2
|
+
/**
|
|
3
|
+
* Concatenates parent and child route paths, handling the '/' root specially
|
|
4
|
+
* to avoid double slashes.
|
|
5
|
+
* @typeParam Parent - The parent route path
|
|
6
|
+
* @typeParam Child - The child route path
|
|
7
|
+
*/
|
|
8
|
+
export type ConcatPaths<Parent extends string, Child extends string> = Parent extends '/' ? Child : `${Parent}${Child}`;
|
|
9
|
+
/**
|
|
10
|
+
* Recursively extracts all valid full URL paths from a nested route tree.
|
|
11
|
+
* @typeParam T - A record of route patterns to NestedRoute definitions
|
|
12
|
+
*/
|
|
13
|
+
export type ExtractRoutePaths<T extends Record<string, NestedRoute<unknown>>> = {
|
|
14
|
+
[K in keyof T & string]: K | (T[K] extends {
|
|
15
|
+
children: infer C extends Record<string, NestedRoute<unknown>>;
|
|
16
|
+
} ? ConcatPaths<K, ExtractRoutePaths<C> & string> : never);
|
|
17
|
+
}[keyof T & string];
|
|
18
|
+
/**
|
|
19
|
+
* Extracts route parameter names from a URL pattern and creates a record type
|
|
20
|
+
* mapping each parameter name to `string`.
|
|
21
|
+
* Returns `Record<string, never>` when no parameters are present.
|
|
22
|
+
* @typeParam T - A URL pattern string potentially containing `:param` segments
|
|
23
|
+
*/
|
|
24
|
+
export type ExtractRouteParams<T extends string> = T extends `${string}:${infer Param}/${infer Rest}` ? {
|
|
25
|
+
[K in Param | keyof ExtractRouteParams<`/${Rest}`>]: string;
|
|
26
|
+
} : T extends `${string}:${infer Param}` ? {
|
|
27
|
+
[K in Param]: string;
|
|
28
|
+
} : Record<string, never>;
|
|
29
|
+
/**
|
|
30
|
+
* A recursive type for validating URL constant objects against a set of valid paths.
|
|
31
|
+
* Leaf values must be valid route paths, and intermediate values can be nested UrlTree objects.
|
|
32
|
+
* @typeParam TPaths - Union of valid route path strings
|
|
33
|
+
*/
|
|
34
|
+
export type UrlTree<TPaths extends string> = {
|
|
35
|
+
[key: string]: TPaths | UrlTree<TPaths>;
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=nested-route-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-route-types.d.ts","sourceRoot":"","sources":["../../src/components/nested-route-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD;;;;;GAKG;AACH,MAAM,MAAM,WAAW,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,SAAS,MAAM,IAAI,MAAM,SAAS,GAAG,GAAG,KAAK,GAAG,GAAG,MAAM,GAAG,KAAK,EAAE,CAAA;AAEvH;;;GAGG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI;KAC7E,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,GAClB,CAAC,GACD,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAA;KAAE,GAC5E,WAAW,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAC7C,KAAK,CAAC;CACf,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAA;AAEnB;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,IAAI,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE,GACjG;KAAG,CAAC,IAAI,KAAK,GAAG,MAAM,kBAAkB,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,MAAM;CAAE,GAC/D,CAAC,SAAS,GAAG,MAAM,IAAI,MAAM,KAAK,EAAE,GAClC;KAAG,CAAC,IAAI,KAAK,GAAG,MAAM;CAAE,GACxB,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;AAE3B;;;;GAIG;AACH,MAAM,MAAM,OAAO,CAAC,MAAM,SAAS,MAAM,IAAI;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACxC,CAAA"}
|