@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,211 @@
|
|
|
1
|
+
import { createInjector } from '@furystack/inject';
|
|
2
|
+
import { usingAsync } from '@furystack/utils';
|
|
3
|
+
import { describe, expect, expectTypeOf, it } from 'vitest';
|
|
4
|
+
import { LocationService } from '../services/location-service.js';
|
|
5
|
+
import { createNestedHooks, walkRoute } from './nested-hooks.js';
|
|
6
|
+
const makeComponent = () => null;
|
|
7
|
+
describe('walkRoute', () => {
|
|
8
|
+
it('Should return the route when the pattern matches the path exactly', () => {
|
|
9
|
+
const leaf = { component: () => makeComponent() };
|
|
10
|
+
const routes = { '/users': leaf };
|
|
11
|
+
expect(walkRoute(routes, '/users')).toBe(leaf);
|
|
12
|
+
});
|
|
13
|
+
it('Should return undefined when no pattern matches', () => {
|
|
14
|
+
const routes = { '/users': { component: () => makeComponent() } };
|
|
15
|
+
expect(walkRoute(routes, '/nonexistent')).toBeUndefined();
|
|
16
|
+
});
|
|
17
|
+
it('Should descend through a `/` root pattern transparently', () => {
|
|
18
|
+
const leaf = { component: () => makeComponent() };
|
|
19
|
+
const routes = {
|
|
20
|
+
'/': {
|
|
21
|
+
component: () => makeComponent(),
|
|
22
|
+
children: {
|
|
23
|
+
'/home': leaf,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
expect(walkRoute(routes, '/home')).toBe(leaf);
|
|
28
|
+
});
|
|
29
|
+
it('Should resolve a deeply nested path by walking children', () => {
|
|
30
|
+
const leaf = { component: () => makeComponent() };
|
|
31
|
+
const routes = {
|
|
32
|
+
'/navigation': {
|
|
33
|
+
component: () => makeComponent(),
|
|
34
|
+
children: {
|
|
35
|
+
'/tabs': leaf,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
expect(walkRoute(routes, '/navigation/tabs')).toBe(leaf);
|
|
40
|
+
});
|
|
41
|
+
it('Should resolve through two levels of `/` roots', () => {
|
|
42
|
+
const leaf = { component: () => makeComponent() };
|
|
43
|
+
const routes = {
|
|
44
|
+
'/': {
|
|
45
|
+
component: () => makeComponent(),
|
|
46
|
+
children: {
|
|
47
|
+
'/navigation': {
|
|
48
|
+
component: () => makeComponent(),
|
|
49
|
+
children: {
|
|
50
|
+
'/tabs': leaf,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
expect(walkRoute(routes, '/navigation/tabs')).toBe(leaf);
|
|
57
|
+
});
|
|
58
|
+
it('Should match a parent prefix when the path is exactly the parent pattern', () => {
|
|
59
|
+
const parent = {
|
|
60
|
+
component: () => makeComponent(),
|
|
61
|
+
children: {
|
|
62
|
+
'/child': { component: () => makeComponent() },
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const routes = { '/parent': parent };
|
|
66
|
+
expect(walkRoute(routes, '/parent')).toBe(parent);
|
|
67
|
+
});
|
|
68
|
+
it('Should not confuse a prefix pattern that is not followed by a `/`', () => {
|
|
69
|
+
const routes = {
|
|
70
|
+
'/users': {
|
|
71
|
+
component: () => makeComponent(),
|
|
72
|
+
children: {
|
|
73
|
+
'/:id': { component: () => makeComponent() },
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
expect(walkRoute(routes, '/usersextra')).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('createNestedHooks', () => {
|
|
81
|
+
describe('getTypedQuery', () => {
|
|
82
|
+
it('Should return null when the route has no declared query validator', async () => {
|
|
83
|
+
const routes = {
|
|
84
|
+
'/bare': { component: () => makeComponent() },
|
|
85
|
+
};
|
|
86
|
+
const { getTypedQuery } = createNestedHooks(routes);
|
|
87
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
88
|
+
expect(getTypedQuery(injector, '/bare')).toBeNull();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
it('Should return the validated query when the current search matches', async () => {
|
|
92
|
+
const routes = {
|
|
93
|
+
'/list': {
|
|
94
|
+
component: () => makeComponent(),
|
|
95
|
+
query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const { getTypedQuery } = createNestedHooks(routes);
|
|
99
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
100
|
+
const locationService = injector.get(LocationService);
|
|
101
|
+
locationService.onDeserializedLocationSearchChanged.setValue({ page: 3 });
|
|
102
|
+
expect(getTypedQuery(injector, '/list')).toEqual({ page: 3 });
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
it('Should return null when the validator rejects the current search', async () => {
|
|
106
|
+
const routes = {
|
|
107
|
+
'/list': {
|
|
108
|
+
component: () => makeComponent(),
|
|
109
|
+
query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
const { getTypedQuery } = createNestedHooks(routes);
|
|
113
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
114
|
+
const locationService = injector.get(LocationService);
|
|
115
|
+
locationService.onDeserializedLocationSearchChanged.setValue({ page: 'not-a-number' });
|
|
116
|
+
expect(getTypedQuery(injector, '/list')).toBeNull();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('getTypedHash', () => {
|
|
121
|
+
it('Should return undefined when the route has no declared hash tuple', async () => {
|
|
122
|
+
const routes = {
|
|
123
|
+
'/bare': { component: () => makeComponent() },
|
|
124
|
+
};
|
|
125
|
+
const { getTypedHash } = createNestedHooks(routes);
|
|
126
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
127
|
+
expect(getTypedHash(injector, '/bare')).toBeUndefined();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
it('Should return the current hash when it matches a declared literal', async () => {
|
|
131
|
+
const routes = {
|
|
132
|
+
'/tabs': {
|
|
133
|
+
component: () => makeComponent(),
|
|
134
|
+
hash: ['overview', 'details'],
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
const { getTypedHash } = createNestedHooks(routes);
|
|
138
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
139
|
+
const locationService = injector.get(LocationService);
|
|
140
|
+
locationService.onLocationHashChanged.setValue('details');
|
|
141
|
+
expect(getTypedHash(injector, '/tabs')).toBe('details');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
it('Should return undefined when the current hash is not in the declared tuple', async () => {
|
|
145
|
+
const routes = {
|
|
146
|
+
'/tabs': {
|
|
147
|
+
component: () => makeComponent(),
|
|
148
|
+
hash: ['overview', 'details'],
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
const { getTypedHash } = createNestedHooks(routes);
|
|
152
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
153
|
+
const locationService = injector.get(LocationService);
|
|
154
|
+
locationService.onLocationHashChanged.setValue('something-else');
|
|
155
|
+
expect(getTypedHash(injector, '/tabs')).toBeUndefined();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
it('Should resolve hashes through nested routes', async () => {
|
|
159
|
+
const routes = {
|
|
160
|
+
'/navigation': {
|
|
161
|
+
component: () => makeComponent(),
|
|
162
|
+
children: {
|
|
163
|
+
'/tabs': {
|
|
164
|
+
component: () => makeComponent(),
|
|
165
|
+
hash: ['ctrl-1', 'ctrl-2'],
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
const { getTypedHash } = createNestedHooks(routes);
|
|
171
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
172
|
+
const locationService = injector.get(LocationService);
|
|
173
|
+
locationService.onLocationHashChanged.setValue('ctrl-1');
|
|
174
|
+
expect(getTypedHash(injector, '/navigation/tabs')).toBe('ctrl-1');
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
describe('Type utilities', () => {
|
|
179
|
+
it('Should narrow getTypedHash against the declared literal tuple', () => {
|
|
180
|
+
const routes = {
|
|
181
|
+
'/tabs': {
|
|
182
|
+
component: () => makeComponent(),
|
|
183
|
+
hash: ['overview', 'details'],
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
const { getTypedHash } = createNestedHooks(routes);
|
|
187
|
+
expectTypeOf((getTypedHash)).returns.toEqualTypeOf();
|
|
188
|
+
});
|
|
189
|
+
it('Should narrow getTypedQuery against the declared validator return type', () => {
|
|
190
|
+
const routes = {
|
|
191
|
+
'/list': {
|
|
192
|
+
component: () => makeComponent(),
|
|
193
|
+
query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
const { getTypedQuery } = createNestedHooks(routes);
|
|
197
|
+
expectTypeOf((getTypedQuery)).returns.toEqualTypeOf();
|
|
198
|
+
});
|
|
199
|
+
it('Should reject paths not present in the route tree', () => {
|
|
200
|
+
const routes = {
|
|
201
|
+
'/tabs': {
|
|
202
|
+
component: () => makeComponent(),
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
const { getTypedHash } = createNestedHooks(routes);
|
|
206
|
+
// @ts-expect-error -- '/nonexistent' is not a valid route path
|
|
207
|
+
getTypedHash(createInjector(), '/nonexistent');
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
//# sourceMappingURL=nested-hooks.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested-hooks.spec.js","sourceRoot":"","sources":["../../src/components/nested-hooks.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACjE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAGhE,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,IAA8B,CAAA;AAE1D,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,IAAI,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE,CAAA;QACjD,MAAM,MAAM,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAuD,CAAA;QACtF,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAChD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,MAAM,GAAG,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE,EAG9D,CAAA;QACD,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,IAAI,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE,CAAA;QACjD,MAAM,MAAM,GAAG;YACb,GAAG,EAAE;gBACH,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;gBAChC,QAAQ,EAAE;oBACR,OAAO,EAAE,IAAI;iBACd;aACF;SACmD,CAAA;QAEtD,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,IAAI,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE,CAAA;QACjD,MAAM,MAAM,GAAG;YACb,aAAa,EAAE;gBACb,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;gBAChC,QAAQ,EAAE;oBACR,OAAO,EAAE,IAAI;iBACd;aACF;SACmD,CAAA;QAEtD,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,IAAI,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE,CAAA;QACjD,MAAM,MAAM,GAAG;YACb,GAAG,EAAE;gBACH,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;gBAChC,QAAQ,EAAE;oBACR,aAAa,EAAE;wBACb,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;wBAChC,QAAQ,EAAE;4BACR,OAAO,EAAE,IAAI;yBACd;qBACF;iBACF;aACF;SACmD,CAAA;QAEtD,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,MAAM,MAAM,GAAG;YACb,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;YAChC,QAAQ,EAAE;gBACR,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE;aAC/C;SACF,CAAA;QACD,MAAM,MAAM,GAAG,EAAE,SAAS,EAAE,MAAM,EAAuD,CAAA;QAEzF,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,MAAM,GAAG;YACb,QAAQ,EAAE;gBACR,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;gBAChC,QAAQ,EAAE;oBACR,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE;iBAC7C;aACF;SACmD,CAAA;QAEtD,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;IAC1D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;YACjF,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE;aACO,CAAA;YAEtD,MAAM,EAAE,aAAa,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAEnD,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACpD,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;YACrD,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;YACjF,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE;oBACP,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;oBAChC,KAAK,EAAE,CAAC,GAAG,EAA2B,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBACpG;aACmD,CAAA;YAEtD,MAAM,EAAE,aAAa,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAEnD,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACpD,MAAM,eAAe,GAAG,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;gBACrD,eAAe,CAAC,mCAAmC,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;gBACzE,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;YAC/D,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;YAChF,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE;oBACP,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;oBAChC,KAAK,EAAE,CAAC,GAAG,EAA2B,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBACpG;aACmD,CAAA;YAEtD,MAAM,EAAE,aAAa,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAEnD,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACpD,MAAM,eAAe,GAAG,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;gBACrD,eAAe,CAAC,mCAAmC,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAA;gBACtF,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;YACrD,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;YACjF,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,EAAE;aACO,CAAA;YAEtD,MAAM,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAElD,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACpD,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;YACzD,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;YACjF,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE;oBACP,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;oBAChC,IAAI,EAAE,CAAC,UAAU,EAAE,SAAS,CAAU;iBACvC;aACmD,CAAA;YAEtD,MAAM,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAElD,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACpD,MAAM,eAAe,GAAG,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;gBACrD,eAAe,CAAC,qBAAqB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;gBACzD,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YACzD,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;YAC1F,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE;oBACP,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;oBAChC,IAAI,EAAE,CAAC,UAAU,EAAE,SAAS,CAAU;iBACvC;aACmD,CAAA;YAEtD,MAAM,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAElD,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACpD,MAAM,eAAe,GAAG,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;gBACrD,eAAe,CAAC,qBAAqB,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAA;gBAChE,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;YACzD,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,MAAM,GAAG;gBACb,aAAa,EAAE;oBACb,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;oBAChC,QAAQ,EAAE;wBACR,OAAO,EAAE;4BACP,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;4BAChC,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAU;yBACpC;qBACF;iBACF;aACmD,CAAA;YAEtD,MAAM,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAElD,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACpD,MAAM,eAAe,GAAG,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;gBACrD,eAAe,CAAC,qBAAqB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;gBACxD,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACnE,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;YACvE,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE;oBACP,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;oBAChC,IAAI,EAAE,CAAC,UAAU,EAAE,SAAS,CAAU;iBACvC;aACmD,CAAA;YAEtD,MAAM,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAClD,YAAY,CAAC,CAAA,YAAqB,CAAA,CAAC,CAAC,OAAO,CAAC,aAAa,EAAsC,CAAA;QACjG,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;YAChF,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE;oBACP,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;oBAChC,KAAK,EAAE,CAAC,GAAG,EAA2B,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBACpG;aACmD,CAAA;YAEtD,MAAM,EAAE,aAAa,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YACnD,YAAY,CAAC,CAAA,aAAsB,CAAA,CAAC,CAAC,OAAO,CAAC,aAAa,EAA2B,CAAA;QACvF,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE;oBACP,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;iBACjC;aACmD,CAAA;YAEtD,MAAM,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YAClD,+DAA+D;YAC/D,YAAY,CAAC,cAAc,EAAE,EAAE,cAAc,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -1,26 +1,57 @@
|
|
|
1
1
|
import type { Injector } from '@furystack/inject';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ExtractRouteHash, ExtractRouteQuery, ExtractRoutePaths, RouteAt, TypedHashArg, TypedParamsArg, TypedQueryArg } from './nested-route-types.js';
|
|
3
3
|
import type { NestedRoute } from './nested-router.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @
|
|
5
|
+
* Untyped runtime arguments for a nested navigate call.
|
|
6
|
+
* Used by the base {@link nestedNavigate} implementation; the typed variants
|
|
7
|
+
* returned by {@link createNestedNavigate} narrow each field against the route
|
|
8
|
+
* tree at compile time.
|
|
8
9
|
*/
|
|
9
|
-
export type
|
|
10
|
+
export type NestedNavigateArgs = {
|
|
11
|
+
path: string;
|
|
12
|
+
params?: Record<string, string>;
|
|
13
|
+
query?: Record<string, unknown>;
|
|
14
|
+
hash?: string;
|
|
15
|
+
};
|
|
10
16
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
17
|
+
* Typed arguments for a nested navigate call, derived from the route tree and
|
|
18
|
+
* the specific target path.
|
|
19
|
+
*
|
|
20
|
+
* - `params` is required when the path contains `:param` segments.
|
|
21
|
+
* - `query` is required when the route's declared query shape has any required
|
|
22
|
+
* key, optional when all keys are optional, and forbidden when the route
|
|
23
|
+
* declares no `query` validator.
|
|
24
|
+
* - `hash` is always optional and restricted to the route's declared literal
|
|
25
|
+
* tuple; forbidden when the route declares no `hash`.
|
|
26
|
+
*
|
|
27
|
+
* @typeParam TRoutes - The route tree
|
|
28
|
+
* @typeParam TPath - A composed route path within `TRoutes`
|
|
29
|
+
*/
|
|
30
|
+
export type TypedNestedNavigateArgs<TRoutes extends Record<string, NestedRoute<any, any, any>>, TPath extends string> = {
|
|
31
|
+
path: TPath;
|
|
32
|
+
} & TypedParamsArg<TPath> & TypedQueryArg<ExtractRouteQuery<RouteAt<TRoutes, TPath>>> & TypedHashArg<ExtractRouteHash<RouteAt<TRoutes, TPath>>>;
|
|
33
|
+
/**
|
|
34
|
+
* Builds the resolved URL for a nested navigate call, including path parameters,
|
|
35
|
+
* serialized query string and hash segment. Exported for callers that need the
|
|
36
|
+
* URL without side effects (e.g. link rendering helpers).
|
|
37
|
+
*/
|
|
38
|
+
export declare const buildNestedNavigateUrl: (args: NestedNavigateArgs) => string;
|
|
39
|
+
/**
|
|
40
|
+
* Navigates to a route using the LocationService resolved from the given injector.
|
|
41
|
+
* Compiles parameterized routes (e.g. `/users/:id`), serializes the optional
|
|
42
|
+
* `query` record with the default `@furystack/rest` serializer, and appends the
|
|
43
|
+
* optional `hash` segment.
|
|
13
44
|
*
|
|
14
45
|
* @param injector - The injector instance to resolve LocationService from
|
|
15
|
-
* @param
|
|
16
|
-
* @param params - Optional route parameters to compile into the path
|
|
46
|
+
* @param args - The navigation arguments
|
|
17
47
|
*/
|
|
18
|
-
export declare const nestedNavigate: (injector: Injector,
|
|
48
|
+
export declare const nestedNavigate: (injector: Injector, args: NestedNavigateArgs) => void;
|
|
19
49
|
/**
|
|
20
50
|
* Creates a type-safe navigate function constrained to a specific route tree.
|
|
21
51
|
* The returned function has the same runtime behavior as {@link nestedNavigate}
|
|
22
|
-
* but narrows `path` to only accept valid route paths,
|
|
23
|
-
*
|
|
52
|
+
* but narrows `path` to only accept valid route paths, requires `params` when
|
|
53
|
+
* the route has parameters, and enforces the route's declared `query` and
|
|
54
|
+
* `hash` schemas.
|
|
24
55
|
*
|
|
25
56
|
* Unlike {@link createNestedRouteLink}, the injector is passed at call time,
|
|
26
57
|
* not at creation time.
|
|
@@ -32,15 +63,15 @@ export declare const nestedNavigate: (injector: Injector, path: string, params?:
|
|
|
32
63
|
* ```typescript
|
|
33
64
|
* const appNavigate = createNestedNavigate<typeof appRoutes>()
|
|
34
65
|
*
|
|
35
|
-
*
|
|
36
|
-
* appNavigate(injector, '/
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
66
|
+
* appNavigate(injector, { path: '/buttons' })
|
|
67
|
+
* appNavigate(injector, { path: '/users/:id', params: { id: '123' } })
|
|
68
|
+
* appNavigate(injector, {
|
|
69
|
+
* path: '/users/:id',
|
|
70
|
+
* params: { id: '123' },
|
|
71
|
+
* query: { tab: 'profile' },
|
|
72
|
+
* hash: 'settings',
|
|
73
|
+
* })
|
|
43
74
|
* ```
|
|
44
75
|
*/
|
|
45
|
-
export declare const createNestedNavigate: <TRoutes extends Record<string, NestedRoute<any>>>() => <TPath extends ExtractRoutePaths<TRoutes>>(injector: Injector,
|
|
76
|
+
export declare const createNestedNavigate: <TRoutes extends Record<string, NestedRoute<any, any, any>>>() => <TPath extends ExtractRoutePaths<TRoutes>>(injector: Injector, args: TypedNestedNavigateArgs<TRoutes, TPath>) => void;
|
|
46
77
|
//# sourceMappingURL=nested-navigate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-navigate.d.ts","sourceRoot":"","sources":["../../src/components/nested-navigate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"nested-navigate.d.ts","sourceRoot":"","sources":["../../src/components/nested-navigate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAIjD,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;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,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,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,uBAAuB,CACjC,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,CAAA;AAEzD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,MAAM,kBAAkB,KAAG,MAOjE,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAI,UAAU,QAAQ,EAAE,MAAM,kBAAkB,KAAG,IAE7E,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,OACpE,CAAC,KAAK,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAChE,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,uBAAuB,CAAC,OAAO,EAAE,KAAK,CAAC,KAC1C,IACN,CAAA"}
|
|
@@ -1,22 +1,37 @@
|
|
|
1
|
+
import { serializeToQueryString } from '@furystack/rest';
|
|
1
2
|
import { compileRoute } from '../compile-route.js';
|
|
2
3
|
import { LocationService } from '../services/location-service.js';
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* Builds the resolved URL for a nested navigate call, including path parameters,
|
|
6
|
+
* serialized query string and hash segment. Exported for callers that need the
|
|
7
|
+
* URL without side effects (e.g. link rendering helpers).
|
|
8
|
+
*/
|
|
9
|
+
export const buildNestedNavigateUrl = (args) => {
|
|
10
|
+
const { path, params, query, hash } = args;
|
|
11
|
+
const resolvedPath = params && Object.keys(params).length > 0 ? compileRoute(path, params) : path;
|
|
12
|
+
const hasQuery = query && Object.keys(query).length > 0;
|
|
13
|
+
const search = hasQuery ? `?${serializeToQueryString(query)}` : '';
|
|
14
|
+
const hashPart = hash ? `#${hash}` : '';
|
|
15
|
+
return `${resolvedPath}${search}${hashPart}`;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Navigates to a route using the LocationService resolved from the given injector.
|
|
19
|
+
* Compiles parameterized routes (e.g. `/users/:id`), serializes the optional
|
|
20
|
+
* `query` record with the default `@furystack/rest` serializer, and appends the
|
|
21
|
+
* optional `hash` segment.
|
|
6
22
|
*
|
|
7
23
|
* @param injector - The injector instance to resolve LocationService from
|
|
8
|
-
* @param
|
|
9
|
-
* @param params - Optional route parameters to compile into the path
|
|
24
|
+
* @param args - The navigation arguments
|
|
10
25
|
*/
|
|
11
|
-
export const nestedNavigate = (injector,
|
|
12
|
-
|
|
13
|
-
injector.getInstance(LocationService).navigate(resolvedUrl);
|
|
26
|
+
export const nestedNavigate = (injector, args) => {
|
|
27
|
+
injector.get(LocationService).navigate(buildNestedNavigateUrl(args));
|
|
14
28
|
};
|
|
15
29
|
/**
|
|
16
30
|
* Creates a type-safe navigate function constrained to a specific route tree.
|
|
17
31
|
* The returned function has the same runtime behavior as {@link nestedNavigate}
|
|
18
|
-
* but narrows `path` to only accept valid route paths,
|
|
19
|
-
*
|
|
32
|
+
* but narrows `path` to only accept valid route paths, requires `params` when
|
|
33
|
+
* the route has parameters, and enforces the route's declared `query` and
|
|
34
|
+
* `hash` schemas.
|
|
20
35
|
*
|
|
21
36
|
* Unlike {@link createNestedRouteLink}, the injector is passed at call time,
|
|
22
37
|
* not at creation time.
|
|
@@ -28,14 +43,14 @@ export const nestedNavigate = (injector, path, params) => {
|
|
|
28
43
|
* ```typescript
|
|
29
44
|
* const appNavigate = createNestedNavigate<typeof appRoutes>()
|
|
30
45
|
*
|
|
31
|
-
*
|
|
32
|
-
* appNavigate(injector, '/
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
46
|
+
* appNavigate(injector, { path: '/buttons' })
|
|
47
|
+
* appNavigate(injector, { path: '/users/:id', params: { id: '123' } })
|
|
48
|
+
* appNavigate(injector, {
|
|
49
|
+
* path: '/users/:id',
|
|
50
|
+
* params: { id: '123' },
|
|
51
|
+
* query: { tab: 'profile' },
|
|
52
|
+
* hash: 'settings',
|
|
53
|
+
* })
|
|
39
54
|
* ```
|
|
40
55
|
*/
|
|
41
56
|
export const createNestedNavigate = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-navigate.js","sourceRoot":"","sources":["../../src/components/nested-navigate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"nested-navigate.js","sourceRoot":"","sources":["../../src/components/nested-navigate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AA8CjE;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAAwB,EAAU,EAAE;IACzE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAA;IAC1C,MAAM,YAAY,GAAG,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACjG,MAAM,QAAQ,GAAG,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;IACvD,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACvC,OAAO,GAAG,YAAY,GAAG,MAAM,GAAG,QAAQ,EAAE,CAAA;AAC9C,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAkB,EAAE,IAAwB,EAAQ,EAAE;IACnF,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAA;AACtE,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAA+D,EAAE;IACnG,OAAO,cAGE,CAAA;AACX,CAAC,CAAA"}
|
|
@@ -1,44 +1,104 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createInjector } from '@furystack/inject';
|
|
2
2
|
import { usingAsync } from '@furystack/utils';
|
|
3
3
|
import { describe, expect, expectTypeOf, it, vi } from 'vitest';
|
|
4
4
|
import { LocationService } from '../services/location-service.js';
|
|
5
|
-
import { createNestedNavigate, nestedNavigate } from './nested-navigate.js';
|
|
5
|
+
import { buildNestedNavigateUrl, createNestedNavigate, nestedNavigate } from './nested-navigate.js';
|
|
6
6
|
describe('nestedNavigate', () => {
|
|
7
7
|
it('Should navigate to a simple path', async () => {
|
|
8
|
-
await usingAsync(
|
|
9
|
-
const locationService = injector.
|
|
8
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
9
|
+
const locationService = injector.get(LocationService);
|
|
10
10
|
const spy = vi.spyOn(locationService, 'navigate');
|
|
11
|
-
nestedNavigate(injector, '/buttons');
|
|
11
|
+
nestedNavigate(injector, { path: '/buttons' });
|
|
12
12
|
expect(spy).toHaveBeenCalledWith('/buttons');
|
|
13
13
|
});
|
|
14
14
|
});
|
|
15
15
|
it('Should compile params into the path', async () => {
|
|
16
|
-
await usingAsync(
|
|
17
|
-
const locationService = injector.
|
|
16
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
17
|
+
const locationService = injector.get(LocationService);
|
|
18
18
|
const spy = vi.spyOn(locationService, 'navigate');
|
|
19
|
-
nestedNavigate(injector, '/users/:id', { id: '42' });
|
|
19
|
+
nestedNavigate(injector, { path: '/users/:id', params: { id: '42' } });
|
|
20
20
|
expect(spy).toHaveBeenCalledWith('/users/42');
|
|
21
21
|
});
|
|
22
22
|
});
|
|
23
23
|
it('Should compile multiple params into the path', async () => {
|
|
24
|
-
await usingAsync(
|
|
25
|
-
const locationService = injector.
|
|
24
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
25
|
+
const locationService = injector.get(LocationService);
|
|
26
26
|
const spy = vi.spyOn(locationService, 'navigate');
|
|
27
|
-
nestedNavigate(injector,
|
|
27
|
+
nestedNavigate(injector, {
|
|
28
|
+
path: '/users/:userId/posts/:postId',
|
|
29
|
+
params: { userId: '1', postId: '99' },
|
|
30
|
+
});
|
|
28
31
|
expect(spy).toHaveBeenCalledWith('/users/1/posts/99');
|
|
29
32
|
});
|
|
30
33
|
});
|
|
34
|
+
it('Should append serialized query string when provided', async () => {
|
|
35
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
36
|
+
const locationService = injector.get(LocationService);
|
|
37
|
+
const spy = vi.spyOn(locationService, 'navigate');
|
|
38
|
+
nestedNavigate(injector, { path: '/buttons', query: { page: 2 } });
|
|
39
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
40
|
+
const navigatedUrl = spy.mock.calls[0][0];
|
|
41
|
+
expect(navigatedUrl.startsWith('/buttons?')).toBe(true);
|
|
42
|
+
const { deserializeQueryString } = locationService;
|
|
43
|
+
const search = navigatedUrl.slice(navigatedUrl.indexOf('?') + 1);
|
|
44
|
+
expect(deserializeQueryString(search)).toEqual({ page: 2 });
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
it('Should omit the query string when no keys are provided', async () => {
|
|
48
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
49
|
+
const locationService = injector.get(LocationService);
|
|
50
|
+
const spy = vi.spyOn(locationService, 'navigate');
|
|
51
|
+
nestedNavigate(injector, { path: '/buttons', query: {} });
|
|
52
|
+
expect(spy).toHaveBeenCalledWith('/buttons');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
it('Should append the hash segment when provided', async () => {
|
|
56
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
57
|
+
const locationService = injector.get(LocationService);
|
|
58
|
+
const spy = vi.spyOn(locationService, 'navigate');
|
|
59
|
+
nestedNavigate(injector, { path: '/buttons', hash: 'overview' });
|
|
60
|
+
expect(spy).toHaveBeenCalledWith('/buttons#overview');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('Should combine params, query and hash in the correct order', async () => {
|
|
64
|
+
await usingAsync(createInjector(), async (injector) => {
|
|
65
|
+
const locationService = injector.get(LocationService);
|
|
66
|
+
const spy = vi.spyOn(locationService, 'navigate');
|
|
67
|
+
nestedNavigate(injector, {
|
|
68
|
+
path: '/users/:id',
|
|
69
|
+
params: { id: '7' },
|
|
70
|
+
query: { tab: 'profile' },
|
|
71
|
+
hash: 'notes',
|
|
72
|
+
});
|
|
73
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
74
|
+
const navigatedUrl = spy.mock.calls[0][0];
|
|
75
|
+
expect(navigatedUrl.startsWith('/users/7?')).toBe(true);
|
|
76
|
+
expect(navigatedUrl.endsWith('#notes')).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('buildNestedNavigateUrl', () => {
|
|
81
|
+
it('Should build a bare path URL', () => {
|
|
82
|
+
expect(buildNestedNavigateUrl({ path: '/buttons' })).toBe('/buttons');
|
|
83
|
+
});
|
|
84
|
+
it('Should build a URL with compiled params', () => {
|
|
85
|
+
expect(buildNestedNavigateUrl({ path: '/users/:id', params: { id: '42' } })).toBe('/users/42');
|
|
86
|
+
});
|
|
87
|
+
it('Should append a hash segment', () => {
|
|
88
|
+
expect(buildNestedNavigateUrl({ path: '/buttons', hash: 'top' })).toBe('/buttons#top');
|
|
89
|
+
});
|
|
31
90
|
});
|
|
32
91
|
describe('Type utilities', () => {
|
|
33
|
-
describe('
|
|
92
|
+
describe('TypedNestedNavigateArgs', () => {
|
|
34
93
|
it('Should make params optional for paths without parameters', () => {
|
|
35
|
-
expectTypeOf().
|
|
94
|
+
expectTypeOf().toExtend();
|
|
95
|
+
expectTypeOf().toExtend();
|
|
36
96
|
});
|
|
37
97
|
it('Should require params for parameterized paths', () => {
|
|
38
|
-
expectTypeOf().
|
|
98
|
+
expectTypeOf().toExtend();
|
|
39
99
|
});
|
|
40
100
|
it('Should require all params for multi-param paths', () => {
|
|
41
|
-
expectTypeOf().
|
|
101
|
+
expectTypeOf().toExtend();
|
|
42
102
|
});
|
|
43
103
|
});
|
|
44
104
|
describe('createNestedNavigate', () => {
|
|
@@ -50,16 +110,20 @@ describe('Type utilities', () => {
|
|
|
50
110
|
});
|
|
51
111
|
it('Should require params for parameterized routes in the tree', () => {
|
|
52
112
|
const appNavigate = createNestedNavigate();
|
|
53
|
-
expectTypeOf((appNavigate))
|
|
113
|
+
expectTypeOf((appNavigate))
|
|
114
|
+
.parameter(1)
|
|
115
|
+
.toExtend();
|
|
54
116
|
});
|
|
55
117
|
it('Should make params optional for non-parameterized routes', () => {
|
|
56
118
|
const appNavigate = createNestedNavigate();
|
|
57
|
-
expectTypeOf((appNavigate))
|
|
119
|
+
expectTypeOf((appNavigate))
|
|
120
|
+
.parameter(1)
|
|
121
|
+
.toExtend();
|
|
58
122
|
});
|
|
59
123
|
it('Should reject invalid paths', () => {
|
|
60
124
|
const appNavigate = createNestedNavigate();
|
|
61
125
|
// @ts-expect-error -- '/nonexistent' is not a valid route path
|
|
62
|
-
appNavigate(
|
|
126
|
+
appNavigate(createInjector(), { path: '/nonexistent' });
|
|
63
127
|
});
|
|
64
128
|
it('Should accept routes with typed match parameters (NestedRoute<T>)', () => {
|
|
65
129
|
const typedRoute = {
|
|
@@ -69,7 +133,33 @@ describe('Type utilities', () => {
|
|
|
69
133
|
'/stacks/:stackName': typedRoute,
|
|
70
134
|
};
|
|
71
135
|
const appNavigate = createNestedNavigate();
|
|
72
|
-
expectTypeOf((appNavigate))
|
|
136
|
+
expectTypeOf((appNavigate))
|
|
137
|
+
.parameter(1)
|
|
138
|
+
.toExtend();
|
|
139
|
+
});
|
|
140
|
+
it('Should enforce a route-declared required query shape', () => {
|
|
141
|
+
const routes = {
|
|
142
|
+
'/list': {
|
|
143
|
+
component: () => null,
|
|
144
|
+
query: (raw) => (typeof raw.page === 'number' ? { page: raw.page } : null),
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
const appNavigate = createNestedNavigate();
|
|
148
|
+
expectTypeOf((appNavigate))
|
|
149
|
+
.parameter(1)
|
|
150
|
+
.toExtend();
|
|
151
|
+
});
|
|
152
|
+
it('Should narrow hash to the declared literal tuple', () => {
|
|
153
|
+
const routes = {
|
|
154
|
+
'/tabs': {
|
|
155
|
+
component: () => null,
|
|
156
|
+
hash: ['overview', 'details'],
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
const appNavigate = createNestedNavigate();
|
|
160
|
+
expectTypeOf((appNavigate))
|
|
161
|
+
.parameter(1)
|
|
162
|
+
.toExtend();
|
|
73
163
|
});
|
|
74
164
|
});
|
|
75
165
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-navigate.spec.js","sourceRoot":"","sources":["../../src/components/nested-navigate.spec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nested-navigate.spec.js","sourceRoot":"","sources":["../../src/components/nested-navigate.spec.ts"],"names":[],"mappings":"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"}
|