@ktjs/router 0.13.0 → 0.14.1
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/dist/index.d.ts +24 -5
- package/dist/index.iife.js +104 -16
- package/dist/index.legacy.js +161 -51
- package/dist/index.mjs +104 -17
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { KTHTMLElement } from '@ktjs/core';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Guard level that determines which guards to apply during navigation
|
|
3
5
|
* - there are global and route-level guards
|
|
@@ -31,8 +33,12 @@ interface RawRouteConfig {
|
|
|
31
33
|
name?: string;
|
|
32
34
|
/** Optional metadata attached to the route */
|
|
33
35
|
meta?: Record<string, any>;
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
+
/** Optional component to render */
|
|
37
|
+
component: () => HTMLElement | Promise<HTMLElement>;
|
|
38
|
+
/** Route-level guard executed before entering this route. Return false to block, string/object to redirect */
|
|
39
|
+
beforeEnter?: (
|
|
40
|
+
context: RouteContext
|
|
41
|
+
) => string | NavBaseOptions | boolean | void | Promise<string | NavBaseOptions | boolean | void>;
|
|
36
42
|
/** Route-level hook executed after navigation */
|
|
37
43
|
after?: (context: RouteContext) => void | Promise<void>;
|
|
38
44
|
/** Nested child routes */
|
|
@@ -96,8 +102,11 @@ interface RouterConfig {
|
|
|
96
102
|
/** Array of route definitions */
|
|
97
103
|
routes: RawRouteConfig[];
|
|
98
104
|
|
|
99
|
-
/** Global guard executed before each navigation (except silentPush) */
|
|
100
|
-
beforeEach?: (
|
|
105
|
+
/** Global guard executed before each navigation (except silentPush). Return false to block, string/object to redirect */
|
|
106
|
+
beforeEach?: (
|
|
107
|
+
to: RouteContext,
|
|
108
|
+
from: RouteContext | null
|
|
109
|
+
) => string | NavBaseOptions | boolean | void | Promise<string | NavBaseOptions | boolean | void>;
|
|
101
110
|
|
|
102
111
|
/** Global hook executed after each navigation */
|
|
103
112
|
afterEach?: (to: RouteContext, from: RouteContext | null) => void | Promise<void>;
|
|
@@ -125,6 +134,9 @@ interface Router {
|
|
|
125
134
|
/** Navigation history */
|
|
126
135
|
history: RouteContext[];
|
|
127
136
|
|
|
137
|
+
/** Set the router view container */
|
|
138
|
+
setRouterView(view: HTMLElement): void;
|
|
139
|
+
|
|
128
140
|
/** Navigate with guards */
|
|
129
141
|
push(location: string | NavOptions): boolean | Promise<boolean>;
|
|
130
142
|
|
|
@@ -147,10 +159,17 @@ interface RouteMatch {
|
|
|
147
159
|
result: RouteConfig[];
|
|
148
160
|
}
|
|
149
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Create a router view container that automatically renders route components
|
|
164
|
+
*/
|
|
165
|
+
declare function KTRouter({ router }: {
|
|
166
|
+
router: Router;
|
|
167
|
+
}): KTHTMLElement;
|
|
168
|
+
|
|
150
169
|
/**
|
|
151
170
|
* Create a new router instance
|
|
152
171
|
*/
|
|
153
172
|
declare const createRouter: (config: RouterConfig) => Router;
|
|
154
173
|
|
|
155
|
-
export { GuardLevel, createRouter };
|
|
174
|
+
export { GuardLevel, KTRouter, createRouter };
|
|
156
175
|
export type { NavOptions, RawRouteConfig, RouteConfig, RouteContext, RouteMatch, Router, RouterConfig };
|
package/dist/index.iife.js
CHANGED
|
@@ -150,6 +150,15 @@ var __ktjs_router__ = (function (exports) {
|
|
|
150
150
|
};
|
|
151
151
|
};
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Create a router view container that automatically renders route components
|
|
155
|
+
*/
|
|
156
|
+
function KTRouter({ router }) {
|
|
157
|
+
const view = document.createElement('kt-router-view');
|
|
158
|
+
router.setRouterView(view);
|
|
159
|
+
return view;
|
|
160
|
+
}
|
|
161
|
+
|
|
153
162
|
/**
|
|
154
163
|
* Create a new router instance
|
|
155
164
|
*/
|
|
@@ -162,6 +171,7 @@ var __ktjs_router__ = (function (exports) {
|
|
|
162
171
|
const asyncGuards = config.asyncGuards ?? true;
|
|
163
172
|
// # private values
|
|
164
173
|
const routes = [];
|
|
174
|
+
let routerView = null;
|
|
165
175
|
/**
|
|
166
176
|
* Normalize routes by adding default guards
|
|
167
177
|
*/
|
|
@@ -174,6 +184,7 @@ var __ktjs_router__ = (function (exports) {
|
|
|
174
184
|
beforeEnter: route.beforeEnter ?? defaultHook,
|
|
175
185
|
after: route.after ?? defaultHook,
|
|
176
186
|
children: route.children ? normalize(route.children, path) : [],
|
|
187
|
+
component: route.component,
|
|
177
188
|
};
|
|
178
189
|
// directly push the normalized route to the list
|
|
179
190
|
// avoid flatten them again
|
|
@@ -189,49 +200,75 @@ var __ktjs_router__ = (function (exports) {
|
|
|
189
200
|
const executeGuardsSync = (to, from, guardLevel) => {
|
|
190
201
|
try {
|
|
191
202
|
if (guardLevel === 0 /* GuardLevel.None */) {
|
|
192
|
-
return true;
|
|
203
|
+
return { continue: true };
|
|
193
204
|
}
|
|
194
205
|
if (guardLevel & 1 /* GuardLevel.Global */) {
|
|
195
206
|
const result = beforeEach(to, from);
|
|
196
207
|
if (result === false) {
|
|
197
|
-
return false;
|
|
208
|
+
return { continue: false };
|
|
209
|
+
}
|
|
210
|
+
if (typeof result === 'string') {
|
|
211
|
+
return { continue: false, redirectTo: { path: result } };
|
|
212
|
+
}
|
|
213
|
+
if (result && typeof result === 'object' && !('then' in result)) {
|
|
214
|
+
return { continue: false, redirectTo: result };
|
|
198
215
|
}
|
|
199
216
|
}
|
|
200
217
|
if (guardLevel & 2 /* GuardLevel.Route */) {
|
|
201
218
|
const targetRoute = to.matched[to.matched.length - 1];
|
|
202
219
|
const result = targetRoute.beforeEnter(to);
|
|
203
220
|
if (result === false) {
|
|
204
|
-
return false;
|
|
221
|
+
return { continue: false };
|
|
222
|
+
}
|
|
223
|
+
if (typeof result === 'string') {
|
|
224
|
+
return { continue: false, redirectTo: { path: result } };
|
|
225
|
+
}
|
|
226
|
+
if (result && typeof result === 'object' && !('then' in result)) {
|
|
227
|
+
return { continue: false, redirectTo: result };
|
|
205
228
|
}
|
|
206
229
|
}
|
|
207
|
-
return true;
|
|
230
|
+
return { continue: true };
|
|
208
231
|
}
|
|
209
232
|
catch (error) {
|
|
210
233
|
onError(error);
|
|
211
|
-
return false;
|
|
234
|
+
return { continue: false };
|
|
212
235
|
}
|
|
213
236
|
};
|
|
214
237
|
const executeGuards = async (to, from, guardLevel) => {
|
|
215
238
|
try {
|
|
216
239
|
if (guardLevel === 0 /* GuardLevel.None */) {
|
|
217
|
-
return true;
|
|
240
|
+
return { continue: true };
|
|
218
241
|
}
|
|
219
242
|
if (guardLevel & 1 /* GuardLevel.Global */) {
|
|
220
243
|
const result = await beforeEach(to, from);
|
|
221
244
|
if (result === false) {
|
|
222
|
-
return false;
|
|
245
|
+
return { continue: false };
|
|
246
|
+
}
|
|
247
|
+
if (typeof result === 'string') {
|
|
248
|
+
return { continue: false, redirectTo: { path: result } };
|
|
249
|
+
}
|
|
250
|
+
if (result && typeof result === 'object') {
|
|
251
|
+
return { continue: false, redirectTo: result };
|
|
223
252
|
}
|
|
224
253
|
}
|
|
225
254
|
if (guardLevel & 2 /* GuardLevel.Route */) {
|
|
226
255
|
const targetRoute = to.matched[to.matched.length - 1];
|
|
227
|
-
const result = targetRoute.beforeEnter(to);
|
|
228
|
-
|
|
256
|
+
const result = await targetRoute.beforeEnter(to);
|
|
257
|
+
if (result === false) {
|
|
258
|
+
return { continue: false };
|
|
259
|
+
}
|
|
260
|
+
if (typeof result === 'string') {
|
|
261
|
+
return { continue: false, redirectTo: { path: result } };
|
|
262
|
+
}
|
|
263
|
+
if (result && typeof result === 'object') {
|
|
264
|
+
return { continue: false, redirectTo: result };
|
|
265
|
+
}
|
|
229
266
|
}
|
|
230
|
-
return true;
|
|
267
|
+
return { continue: true };
|
|
231
268
|
}
|
|
232
269
|
catch (error) {
|
|
233
270
|
onError(error);
|
|
234
|
-
return false;
|
|
271
|
+
return { continue: false };
|
|
235
272
|
}
|
|
236
273
|
};
|
|
237
274
|
const navigatePrepare = (options) => {
|
|
@@ -280,15 +317,25 @@ var __ktjs_router__ = (function (exports) {
|
|
|
280
317
|
fullPath,
|
|
281
318
|
};
|
|
282
319
|
};
|
|
283
|
-
const navigateSync = (options) => {
|
|
320
|
+
const navigateSync = (options, redirectCount = 0) => {
|
|
284
321
|
try {
|
|
322
|
+
// Prevent infinite redirect loop
|
|
323
|
+
if (redirectCount > 10) {
|
|
324
|
+
onError(new Error('Maximum redirect count exceeded'));
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
285
327
|
const prep = navigatePrepare(options);
|
|
286
328
|
if (!prep) {
|
|
287
329
|
return false;
|
|
288
330
|
}
|
|
289
331
|
const { guardLevel, replace, to, fullPath } = prep;
|
|
290
332
|
// Execute guards
|
|
291
|
-
|
|
333
|
+
const guardResult = executeGuardsSync(to, current, guardLevel);
|
|
334
|
+
if (!guardResult.continue) {
|
|
335
|
+
// Check if there's a redirect
|
|
336
|
+
if (guardResult.redirectTo) {
|
|
337
|
+
return navigateSync(guardResult.redirectTo, redirectCount + 1);
|
|
338
|
+
}
|
|
292
339
|
return false;
|
|
293
340
|
}
|
|
294
341
|
// Update browser history
|
|
@@ -302,6 +349,23 @@ var __ktjs_router__ = (function (exports) {
|
|
|
302
349
|
// Update current route
|
|
303
350
|
current = to;
|
|
304
351
|
history.push(to);
|
|
352
|
+
// Render component if routerView exists
|
|
353
|
+
if (routerView && to.matched.length > 0) {
|
|
354
|
+
const route = to.matched[to.matched.length - 1];
|
|
355
|
+
if (route.component) {
|
|
356
|
+
const element = route.component();
|
|
357
|
+
if (element instanceof Promise) {
|
|
358
|
+
element.then((el) => {
|
|
359
|
+
routerView.innerHTML = '';
|
|
360
|
+
routerView.appendChild(el);
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
routerView.innerHTML = '';
|
|
365
|
+
routerView.appendChild(element);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
305
369
|
// Execute after hooks
|
|
306
370
|
executeAfterHooksSync(to, history[history.length - 2] ?? null);
|
|
307
371
|
return true;
|
|
@@ -311,15 +375,24 @@ var __ktjs_router__ = (function (exports) {
|
|
|
311
375
|
return false;
|
|
312
376
|
}
|
|
313
377
|
};
|
|
314
|
-
const navigateAsync = async (options) => {
|
|
378
|
+
const navigateAsync = async (options, redirectCount = 0) => {
|
|
315
379
|
try {
|
|
380
|
+
// Prevent infinite redirect loop
|
|
381
|
+
if (redirectCount > 10) {
|
|
382
|
+
onError(new Error('Maximum redirect count exceeded'));
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
316
385
|
const prep = navigatePrepare(options);
|
|
317
386
|
if (!prep) {
|
|
318
387
|
return false;
|
|
319
388
|
}
|
|
320
389
|
const { guardLevel, replace, to, fullPath } = prep;
|
|
321
|
-
const
|
|
322
|
-
if (!
|
|
390
|
+
const guardResult = await executeGuards(to, current, guardLevel);
|
|
391
|
+
if (!guardResult.continue) {
|
|
392
|
+
// Check if there's a redirect
|
|
393
|
+
if (guardResult.redirectTo) {
|
|
394
|
+
return navigateAsync(guardResult.redirectTo, redirectCount + 1);
|
|
395
|
+
}
|
|
323
396
|
return false;
|
|
324
397
|
}
|
|
325
398
|
// ---- Guards passed ----
|
|
@@ -330,6 +403,17 @@ var __ktjs_router__ = (function (exports) {
|
|
|
330
403
|
else {
|
|
331
404
|
window.history.pushState({ path: to.path }, '', url);
|
|
332
405
|
}
|
|
406
|
+
current = to;
|
|
407
|
+
history.push(to);
|
|
408
|
+
// Render component if routerView exists
|
|
409
|
+
if (routerView && to.matched.length > 0) {
|
|
410
|
+
const route = to.matched[to.matched.length - 1];
|
|
411
|
+
if (route.component) {
|
|
412
|
+
const element = await route.component();
|
|
413
|
+
routerView.innerHTML = '';
|
|
414
|
+
routerView.appendChild(element);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
333
417
|
executeAfterHooks(to, history[history.length - 2] ?? null);
|
|
334
418
|
return true;
|
|
335
419
|
}
|
|
@@ -378,6 +462,9 @@ var __ktjs_router__ = (function (exports) {
|
|
|
378
462
|
get history() {
|
|
379
463
|
return history.concat();
|
|
380
464
|
},
|
|
465
|
+
setRouterView(view) {
|
|
466
|
+
routerView = view;
|
|
467
|
+
},
|
|
381
468
|
push(location) {
|
|
382
469
|
const options = normalizeLocation(location);
|
|
383
470
|
return navigate(options);
|
|
@@ -399,6 +486,7 @@ var __ktjs_router__ = (function (exports) {
|
|
|
399
486
|
};
|
|
400
487
|
};
|
|
401
488
|
|
|
489
|
+
exports.KTRouter = KTRouter;
|
|
402
490
|
exports.createRouter = createRouter;
|
|
403
491
|
|
|
404
492
|
return exports;
|
package/dist/index.legacy.js
CHANGED
|
@@ -67,6 +67,16 @@ var __ktjs_router__ = (function (exports) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
function __spreadArray(to, from, pack) {
|
|
71
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
72
|
+
if (ar || !(i in from)) {
|
|
73
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
74
|
+
ar[i] = from[i];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
78
|
+
}
|
|
79
|
+
|
|
70
80
|
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
71
81
|
var e = new Error(message);
|
|
72
82
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
@@ -229,6 +239,16 @@ var __ktjs_router__ = (function (exports) {
|
|
|
229
239
|
};
|
|
230
240
|
};
|
|
231
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Create a router view container that automatically renders route components
|
|
244
|
+
*/
|
|
245
|
+
function KTRouter(_a) {
|
|
246
|
+
var router = _a.router;
|
|
247
|
+
var view = document.createElement('kt-router-view');
|
|
248
|
+
router.setRouterView(view);
|
|
249
|
+
return view;
|
|
250
|
+
}
|
|
251
|
+
|
|
232
252
|
/**
|
|
233
253
|
* Create a new router instance
|
|
234
254
|
*/
|
|
@@ -242,6 +262,7 @@ var __ktjs_router__ = (function (exports) {
|
|
|
242
262
|
var asyncGuards = (_e = config.asyncGuards) !== null && _e !== void 0 ? _e : true;
|
|
243
263
|
// # private values
|
|
244
264
|
var routes = [];
|
|
265
|
+
var routerView = null;
|
|
245
266
|
/**
|
|
246
267
|
* Normalize routes by adding default guards
|
|
247
268
|
*/
|
|
@@ -256,6 +277,7 @@ var __ktjs_router__ = (function (exports) {
|
|
|
256
277
|
beforeEnter: (_c = route.beforeEnter) !== null && _c !== void 0 ? _c : defaultHook,
|
|
257
278
|
after: (_d = route.after) !== null && _d !== void 0 ? _d : defaultHook,
|
|
258
279
|
children: route.children ? normalize(route.children, path) : [],
|
|
280
|
+
component: route.component,
|
|
259
281
|
};
|
|
260
282
|
// directly push the normalized route to the list
|
|
261
283
|
// avoid flatten them again
|
|
@@ -272,26 +294,38 @@ var __ktjs_router__ = (function (exports) {
|
|
|
272
294
|
var executeGuardsSync = function (to, from, guardLevel) {
|
|
273
295
|
try {
|
|
274
296
|
if (guardLevel === 0 /* GuardLevel.None */) {
|
|
275
|
-
return true;
|
|
297
|
+
return { continue: true };
|
|
276
298
|
}
|
|
277
299
|
if (guardLevel & 1 /* GuardLevel.Global */) {
|
|
278
300
|
var result = beforeEach(to, from);
|
|
279
301
|
if (result === false) {
|
|
280
|
-
return false;
|
|
302
|
+
return { continue: false };
|
|
303
|
+
}
|
|
304
|
+
if (typeof result === 'string') {
|
|
305
|
+
return { continue: false, redirectTo: { path: result } };
|
|
306
|
+
}
|
|
307
|
+
if (result && typeof result === 'object' && !('then' in result)) {
|
|
308
|
+
return { continue: false, redirectTo: result };
|
|
281
309
|
}
|
|
282
310
|
}
|
|
283
311
|
if (guardLevel & 2 /* GuardLevel.Route */) {
|
|
284
312
|
var targetRoute = to.matched[to.matched.length - 1];
|
|
285
313
|
var result = targetRoute.beforeEnter(to);
|
|
286
314
|
if (result === false) {
|
|
287
|
-
return false;
|
|
315
|
+
return { continue: false };
|
|
316
|
+
}
|
|
317
|
+
if (typeof result === 'string') {
|
|
318
|
+
return { continue: false, redirectTo: { path: result } };
|
|
319
|
+
}
|
|
320
|
+
if (result && typeof result === 'object' && !('then' in result)) {
|
|
321
|
+
return { continue: false, redirectTo: result };
|
|
288
322
|
}
|
|
289
323
|
}
|
|
290
|
-
return true;
|
|
324
|
+
return { continue: true };
|
|
291
325
|
}
|
|
292
326
|
catch (error) {
|
|
293
327
|
onError(error);
|
|
294
|
-
return false;
|
|
328
|
+
return { continue: false };
|
|
295
329
|
}
|
|
296
330
|
};
|
|
297
331
|
var executeGuards = function (to, from, guardLevel) { return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -299,30 +333,46 @@ var __ktjs_router__ = (function (exports) {
|
|
|
299
333
|
return __generator(this, function (_a) {
|
|
300
334
|
switch (_a.label) {
|
|
301
335
|
case 0:
|
|
302
|
-
_a.trys.push([0,
|
|
336
|
+
_a.trys.push([0, 5, , 6]);
|
|
303
337
|
if (guardLevel === 0 /* GuardLevel.None */) {
|
|
304
|
-
return [2 /*return*/, true];
|
|
338
|
+
return [2 /*return*/, { continue: true }];
|
|
305
339
|
}
|
|
306
340
|
if (!(guardLevel & 1 /* GuardLevel.Global */)) return [3 /*break*/, 2];
|
|
307
341
|
return [4 /*yield*/, beforeEach(to, from)];
|
|
308
342
|
case 1:
|
|
309
343
|
result = _a.sent();
|
|
310
344
|
if (result === false) {
|
|
311
|
-
return [2 /*return*/, false];
|
|
345
|
+
return [2 /*return*/, { continue: false }];
|
|
346
|
+
}
|
|
347
|
+
if (typeof result === 'string') {
|
|
348
|
+
return [2 /*return*/, { continue: false, redirectTo: { path: result } }];
|
|
349
|
+
}
|
|
350
|
+
if (result && typeof result === 'object') {
|
|
351
|
+
return [2 /*return*/, { continue: false, redirectTo: result }];
|
|
312
352
|
}
|
|
313
353
|
_a.label = 2;
|
|
314
354
|
case 2:
|
|
315
|
-
if (guardLevel & 2 /* GuardLevel.Route */)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return [2 /*return*/, result !== false];
|
|
319
|
-
}
|
|
320
|
-
return [2 /*return*/, true];
|
|
355
|
+
if (!(guardLevel & 2 /* GuardLevel.Route */)) return [3 /*break*/, 4];
|
|
356
|
+
targetRoute = to.matched[to.matched.length - 1];
|
|
357
|
+
return [4 /*yield*/, targetRoute.beforeEnter(to)];
|
|
321
358
|
case 3:
|
|
359
|
+
result = _a.sent();
|
|
360
|
+
if (result === false) {
|
|
361
|
+
return [2 /*return*/, { continue: false }];
|
|
362
|
+
}
|
|
363
|
+
if (typeof result === 'string') {
|
|
364
|
+
return [2 /*return*/, { continue: false, redirectTo: { path: result } }];
|
|
365
|
+
}
|
|
366
|
+
if (result && typeof result === 'object') {
|
|
367
|
+
return [2 /*return*/, { continue: false, redirectTo: result }];
|
|
368
|
+
}
|
|
369
|
+
_a.label = 4;
|
|
370
|
+
case 4: return [2 /*return*/, { continue: true }];
|
|
371
|
+
case 5:
|
|
322
372
|
error_1 = _a.sent();
|
|
323
373
|
onError(error_1);
|
|
324
|
-
return [2 /*return*/, false];
|
|
325
|
-
case
|
|
374
|
+
return [2 /*return*/, { continue: false }];
|
|
375
|
+
case 6: return [2 /*return*/];
|
|
326
376
|
}
|
|
327
377
|
});
|
|
328
378
|
}); };
|
|
@@ -373,16 +423,27 @@ var __ktjs_router__ = (function (exports) {
|
|
|
373
423
|
fullPath: fullPath,
|
|
374
424
|
};
|
|
375
425
|
};
|
|
376
|
-
var navigateSync = function (options) {
|
|
426
|
+
var navigateSync = function (options, redirectCount) {
|
|
377
427
|
var _a;
|
|
428
|
+
if (redirectCount === void 0) { redirectCount = 0; }
|
|
378
429
|
try {
|
|
430
|
+
// Prevent infinite redirect loop
|
|
431
|
+
if (redirectCount > 10) {
|
|
432
|
+
onError(new Error('Maximum redirect count exceeded'));
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
379
435
|
var prep = navigatePrepare(options);
|
|
380
436
|
if (!prep) {
|
|
381
437
|
return false;
|
|
382
438
|
}
|
|
383
439
|
var guardLevel = prep.guardLevel, replace = prep.replace, to = prep.to, fullPath = prep.fullPath;
|
|
384
440
|
// Execute guards
|
|
385
|
-
|
|
441
|
+
var guardResult = executeGuardsSync(to, current, guardLevel);
|
|
442
|
+
if (!guardResult.continue) {
|
|
443
|
+
// Check if there's a redirect
|
|
444
|
+
if (guardResult.redirectTo) {
|
|
445
|
+
return navigateSync(guardResult.redirectTo, redirectCount + 1);
|
|
446
|
+
}
|
|
386
447
|
return false;
|
|
387
448
|
}
|
|
388
449
|
// Update browser history
|
|
@@ -396,6 +457,23 @@ var __ktjs_router__ = (function (exports) {
|
|
|
396
457
|
// Update current route
|
|
397
458
|
current = to;
|
|
398
459
|
history.push(to);
|
|
460
|
+
// Render component if routerView exists
|
|
461
|
+
if (routerView && to.matched.length > 0) {
|
|
462
|
+
var route = to.matched[to.matched.length - 1];
|
|
463
|
+
if (route.component) {
|
|
464
|
+
var element = route.component();
|
|
465
|
+
if (element instanceof Promise) {
|
|
466
|
+
element.then(function (el) {
|
|
467
|
+
routerView.innerHTML = '';
|
|
468
|
+
routerView.appendChild(el);
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
routerView.innerHTML = '';
|
|
473
|
+
routerView.appendChild(element);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
399
477
|
// Execute after hooks
|
|
400
478
|
executeAfterHooksSync(to, (_a = history[history.length - 2]) !== null && _a !== void 0 ? _a : null);
|
|
401
479
|
return true;
|
|
@@ -405,41 +483,69 @@ var __ktjs_router__ = (function (exports) {
|
|
|
405
483
|
return false;
|
|
406
484
|
}
|
|
407
485
|
};
|
|
408
|
-
var navigateAsync = function (
|
|
409
|
-
var
|
|
410
|
-
var
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
486
|
+
var navigateAsync = function (options_1) {
|
|
487
|
+
var args_1 = [];
|
|
488
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
489
|
+
args_1[_i - 1] = arguments[_i];
|
|
490
|
+
}
|
|
491
|
+
return __awaiter(void 0, __spreadArray([options_1], args_1, true), void 0, function (options, redirectCount) {
|
|
492
|
+
var prep, guardLevel, replace, to, fullPath, guardResult, url, route, element, error_2;
|
|
493
|
+
var _a;
|
|
494
|
+
if (redirectCount === void 0) { redirectCount = 0; }
|
|
495
|
+
return __generator(this, function (_b) {
|
|
496
|
+
switch (_b.label) {
|
|
497
|
+
case 0:
|
|
498
|
+
_b.trys.push([0, 4, , 5]);
|
|
499
|
+
// Prevent infinite redirect loop
|
|
500
|
+
if (redirectCount > 10) {
|
|
501
|
+
onError(new Error('Maximum redirect count exceeded'));
|
|
502
|
+
return [2 /*return*/, false];
|
|
503
|
+
}
|
|
504
|
+
prep = navigatePrepare(options);
|
|
505
|
+
if (!prep) {
|
|
506
|
+
return [2 /*return*/, false];
|
|
507
|
+
}
|
|
508
|
+
guardLevel = prep.guardLevel, replace = prep.replace, to = prep.to, fullPath = prep.fullPath;
|
|
509
|
+
return [4 /*yield*/, executeGuards(to, current, guardLevel)];
|
|
510
|
+
case 1:
|
|
511
|
+
guardResult = _b.sent();
|
|
512
|
+
if (!guardResult.continue) {
|
|
513
|
+
// Check if there's a redirect
|
|
514
|
+
if (guardResult.redirectTo) {
|
|
515
|
+
return [2 /*return*/, navigateAsync(guardResult.redirectTo, redirectCount + 1)];
|
|
516
|
+
}
|
|
517
|
+
return [2 /*return*/, false];
|
|
518
|
+
}
|
|
519
|
+
url = fullPath;
|
|
520
|
+
if (replace) {
|
|
521
|
+
window.history.replaceState({ path: to.path }, '', url);
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
window.history.pushState({ path: to.path }, '', url);
|
|
525
|
+
}
|
|
526
|
+
current = to;
|
|
527
|
+
history.push(to);
|
|
528
|
+
if (!(routerView && to.matched.length > 0)) return [3 /*break*/, 3];
|
|
529
|
+
route = to.matched[to.matched.length - 1];
|
|
530
|
+
if (!route.component) return [3 /*break*/, 3];
|
|
531
|
+
return [4 /*yield*/, route.component()];
|
|
532
|
+
case 2:
|
|
533
|
+
element = _b.sent();
|
|
534
|
+
routerView.innerHTML = '';
|
|
535
|
+
routerView.appendChild(element);
|
|
536
|
+
_b.label = 3;
|
|
537
|
+
case 3:
|
|
538
|
+
executeAfterHooks(to, (_a = history[history.length - 2]) !== null && _a !== void 0 ? _a : null);
|
|
539
|
+
return [2 /*return*/, true];
|
|
540
|
+
case 4:
|
|
541
|
+
error_2 = _b.sent();
|
|
542
|
+
onError(error_2);
|
|
424
543
|
return [2 /*return*/, false];
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
window.history.replaceState({ path: to.path }, '', url);
|
|
429
|
-
}
|
|
430
|
-
else {
|
|
431
|
-
window.history.pushState({ path: to.path }, '', url);
|
|
432
|
-
}
|
|
433
|
-
executeAfterHooks(to, (_a = history[history.length - 2]) !== null && _a !== void 0 ? _a : null);
|
|
434
|
-
return [2 /*return*/, true];
|
|
435
|
-
case 2:
|
|
436
|
-
error_2 = _b.sent();
|
|
437
|
-
onError(error_2);
|
|
438
|
-
return [2 /*return*/, false];
|
|
439
|
-
case 3: return [2 /*return*/];
|
|
440
|
-
}
|
|
544
|
+
case 5: return [2 /*return*/];
|
|
545
|
+
}
|
|
546
|
+
});
|
|
441
547
|
});
|
|
442
|
-
}
|
|
548
|
+
};
|
|
443
549
|
var navigate = asyncGuards ? navigateSync : navigateAsync;
|
|
444
550
|
var executeAfterHooksSync = function (to, from) {
|
|
445
551
|
var targetRoute = to.matched[to.matched.length - 1];
|
|
@@ -492,6 +598,9 @@ var __ktjs_router__ = (function (exports) {
|
|
|
492
598
|
get history() {
|
|
493
599
|
return history.concat();
|
|
494
600
|
},
|
|
601
|
+
setRouterView: function (view) {
|
|
602
|
+
routerView = view;
|
|
603
|
+
},
|
|
495
604
|
push: function (location) {
|
|
496
605
|
var options = normalizeLocation(location);
|
|
497
606
|
return navigate(options);
|
|
@@ -513,6 +622,7 @@ var __ktjs_router__ = (function (exports) {
|
|
|
513
622
|
};
|
|
514
623
|
};
|
|
515
624
|
|
|
625
|
+
exports.KTRouter = KTRouter;
|
|
516
626
|
exports.createRouter = createRouter;
|
|
517
627
|
|
|
518
628
|
return exports;
|
package/dist/index.mjs
CHANGED
|
@@ -147,6 +147,15 @@ const createMatcher = (routes) => {
|
|
|
147
147
|
};
|
|
148
148
|
};
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Create a router view container that automatically renders route components
|
|
152
|
+
*/
|
|
153
|
+
function KTRouter({ router }) {
|
|
154
|
+
const view = document.createElement('kt-router-view');
|
|
155
|
+
router.setRouterView(view);
|
|
156
|
+
return view;
|
|
157
|
+
}
|
|
158
|
+
|
|
150
159
|
/**
|
|
151
160
|
* Create a new router instance
|
|
152
161
|
*/
|
|
@@ -159,6 +168,7 @@ const createRouter = (config) => {
|
|
|
159
168
|
const asyncGuards = config.asyncGuards ?? true;
|
|
160
169
|
// # private values
|
|
161
170
|
const routes = [];
|
|
171
|
+
let routerView = null;
|
|
162
172
|
/**
|
|
163
173
|
* Normalize routes by adding default guards
|
|
164
174
|
*/
|
|
@@ -171,6 +181,7 @@ const createRouter = (config) => {
|
|
|
171
181
|
beforeEnter: route.beforeEnter ?? defaultHook,
|
|
172
182
|
after: route.after ?? defaultHook,
|
|
173
183
|
children: route.children ? normalize(route.children, path) : [],
|
|
184
|
+
component: route.component,
|
|
174
185
|
};
|
|
175
186
|
// directly push the normalized route to the list
|
|
176
187
|
// avoid flatten them again
|
|
@@ -186,49 +197,75 @@ const createRouter = (config) => {
|
|
|
186
197
|
const executeGuardsSync = (to, from, guardLevel) => {
|
|
187
198
|
try {
|
|
188
199
|
if (guardLevel === 0 /* GuardLevel.None */) {
|
|
189
|
-
return true;
|
|
200
|
+
return { continue: true };
|
|
190
201
|
}
|
|
191
202
|
if (guardLevel & 1 /* GuardLevel.Global */) {
|
|
192
203
|
const result = beforeEach(to, from);
|
|
193
204
|
if (result === false) {
|
|
194
|
-
return false;
|
|
205
|
+
return { continue: false };
|
|
206
|
+
}
|
|
207
|
+
if (typeof result === 'string') {
|
|
208
|
+
return { continue: false, redirectTo: { path: result } };
|
|
209
|
+
}
|
|
210
|
+
if (result && typeof result === 'object' && !('then' in result)) {
|
|
211
|
+
return { continue: false, redirectTo: result };
|
|
195
212
|
}
|
|
196
213
|
}
|
|
197
214
|
if (guardLevel & 2 /* GuardLevel.Route */) {
|
|
198
215
|
const targetRoute = to.matched[to.matched.length - 1];
|
|
199
216
|
const result = targetRoute.beforeEnter(to);
|
|
200
217
|
if (result === false) {
|
|
201
|
-
return false;
|
|
218
|
+
return { continue: false };
|
|
219
|
+
}
|
|
220
|
+
if (typeof result === 'string') {
|
|
221
|
+
return { continue: false, redirectTo: { path: result } };
|
|
222
|
+
}
|
|
223
|
+
if (result && typeof result === 'object' && !('then' in result)) {
|
|
224
|
+
return { continue: false, redirectTo: result };
|
|
202
225
|
}
|
|
203
226
|
}
|
|
204
|
-
return true;
|
|
227
|
+
return { continue: true };
|
|
205
228
|
}
|
|
206
229
|
catch (error) {
|
|
207
230
|
onError(error);
|
|
208
|
-
return false;
|
|
231
|
+
return { continue: false };
|
|
209
232
|
}
|
|
210
233
|
};
|
|
211
234
|
const executeGuards = async (to, from, guardLevel) => {
|
|
212
235
|
try {
|
|
213
236
|
if (guardLevel === 0 /* GuardLevel.None */) {
|
|
214
|
-
return true;
|
|
237
|
+
return { continue: true };
|
|
215
238
|
}
|
|
216
239
|
if (guardLevel & 1 /* GuardLevel.Global */) {
|
|
217
240
|
const result = await beforeEach(to, from);
|
|
218
241
|
if (result === false) {
|
|
219
|
-
return false;
|
|
242
|
+
return { continue: false };
|
|
243
|
+
}
|
|
244
|
+
if (typeof result === 'string') {
|
|
245
|
+
return { continue: false, redirectTo: { path: result } };
|
|
246
|
+
}
|
|
247
|
+
if (result && typeof result === 'object') {
|
|
248
|
+
return { continue: false, redirectTo: result };
|
|
220
249
|
}
|
|
221
250
|
}
|
|
222
251
|
if (guardLevel & 2 /* GuardLevel.Route */) {
|
|
223
252
|
const targetRoute = to.matched[to.matched.length - 1];
|
|
224
|
-
const result = targetRoute.beforeEnter(to);
|
|
225
|
-
|
|
253
|
+
const result = await targetRoute.beforeEnter(to);
|
|
254
|
+
if (result === false) {
|
|
255
|
+
return { continue: false };
|
|
256
|
+
}
|
|
257
|
+
if (typeof result === 'string') {
|
|
258
|
+
return { continue: false, redirectTo: { path: result } };
|
|
259
|
+
}
|
|
260
|
+
if (result && typeof result === 'object') {
|
|
261
|
+
return { continue: false, redirectTo: result };
|
|
262
|
+
}
|
|
226
263
|
}
|
|
227
|
-
return true;
|
|
264
|
+
return { continue: true };
|
|
228
265
|
}
|
|
229
266
|
catch (error) {
|
|
230
267
|
onError(error);
|
|
231
|
-
return false;
|
|
268
|
+
return { continue: false };
|
|
232
269
|
}
|
|
233
270
|
};
|
|
234
271
|
const navigatePrepare = (options) => {
|
|
@@ -277,15 +314,25 @@ const createRouter = (config) => {
|
|
|
277
314
|
fullPath,
|
|
278
315
|
};
|
|
279
316
|
};
|
|
280
|
-
const navigateSync = (options) => {
|
|
317
|
+
const navigateSync = (options, redirectCount = 0) => {
|
|
281
318
|
try {
|
|
319
|
+
// Prevent infinite redirect loop
|
|
320
|
+
if (redirectCount > 10) {
|
|
321
|
+
onError(new Error('Maximum redirect count exceeded'));
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
282
324
|
const prep = navigatePrepare(options);
|
|
283
325
|
if (!prep) {
|
|
284
326
|
return false;
|
|
285
327
|
}
|
|
286
328
|
const { guardLevel, replace, to, fullPath } = prep;
|
|
287
329
|
// Execute guards
|
|
288
|
-
|
|
330
|
+
const guardResult = executeGuardsSync(to, current, guardLevel);
|
|
331
|
+
if (!guardResult.continue) {
|
|
332
|
+
// Check if there's a redirect
|
|
333
|
+
if (guardResult.redirectTo) {
|
|
334
|
+
return navigateSync(guardResult.redirectTo, redirectCount + 1);
|
|
335
|
+
}
|
|
289
336
|
return false;
|
|
290
337
|
}
|
|
291
338
|
// Update browser history
|
|
@@ -299,6 +346,23 @@ const createRouter = (config) => {
|
|
|
299
346
|
// Update current route
|
|
300
347
|
current = to;
|
|
301
348
|
history.push(to);
|
|
349
|
+
// Render component if routerView exists
|
|
350
|
+
if (routerView && to.matched.length > 0) {
|
|
351
|
+
const route = to.matched[to.matched.length - 1];
|
|
352
|
+
if (route.component) {
|
|
353
|
+
const element = route.component();
|
|
354
|
+
if (element instanceof Promise) {
|
|
355
|
+
element.then((el) => {
|
|
356
|
+
routerView.innerHTML = '';
|
|
357
|
+
routerView.appendChild(el);
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
routerView.innerHTML = '';
|
|
362
|
+
routerView.appendChild(element);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
302
366
|
// Execute after hooks
|
|
303
367
|
executeAfterHooksSync(to, history[history.length - 2] ?? null);
|
|
304
368
|
return true;
|
|
@@ -308,15 +372,24 @@ const createRouter = (config) => {
|
|
|
308
372
|
return false;
|
|
309
373
|
}
|
|
310
374
|
};
|
|
311
|
-
const navigateAsync = async (options) => {
|
|
375
|
+
const navigateAsync = async (options, redirectCount = 0) => {
|
|
312
376
|
try {
|
|
377
|
+
// Prevent infinite redirect loop
|
|
378
|
+
if (redirectCount > 10) {
|
|
379
|
+
onError(new Error('Maximum redirect count exceeded'));
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
313
382
|
const prep = navigatePrepare(options);
|
|
314
383
|
if (!prep) {
|
|
315
384
|
return false;
|
|
316
385
|
}
|
|
317
386
|
const { guardLevel, replace, to, fullPath } = prep;
|
|
318
|
-
const
|
|
319
|
-
if (!
|
|
387
|
+
const guardResult = await executeGuards(to, current, guardLevel);
|
|
388
|
+
if (!guardResult.continue) {
|
|
389
|
+
// Check if there's a redirect
|
|
390
|
+
if (guardResult.redirectTo) {
|
|
391
|
+
return navigateAsync(guardResult.redirectTo, redirectCount + 1);
|
|
392
|
+
}
|
|
320
393
|
return false;
|
|
321
394
|
}
|
|
322
395
|
// ---- Guards passed ----
|
|
@@ -327,6 +400,17 @@ const createRouter = (config) => {
|
|
|
327
400
|
else {
|
|
328
401
|
window.history.pushState({ path: to.path }, '', url);
|
|
329
402
|
}
|
|
403
|
+
current = to;
|
|
404
|
+
history.push(to);
|
|
405
|
+
// Render component if routerView exists
|
|
406
|
+
if (routerView && to.matched.length > 0) {
|
|
407
|
+
const route = to.matched[to.matched.length - 1];
|
|
408
|
+
if (route.component) {
|
|
409
|
+
const element = await route.component();
|
|
410
|
+
routerView.innerHTML = '';
|
|
411
|
+
routerView.appendChild(element);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
330
414
|
executeAfterHooks(to, history[history.length - 2] ?? null);
|
|
331
415
|
return true;
|
|
332
416
|
}
|
|
@@ -375,6 +459,9 @@ const createRouter = (config) => {
|
|
|
375
459
|
get history() {
|
|
376
460
|
return history.concat();
|
|
377
461
|
},
|
|
462
|
+
setRouterView(view) {
|
|
463
|
+
routerView = view;
|
|
464
|
+
},
|
|
378
465
|
push(location) {
|
|
379
466
|
const options = normalizeLocation(location);
|
|
380
467
|
return navigate(options);
|
|
@@ -396,4 +483,4 @@ const createRouter = (config) => {
|
|
|
396
483
|
};
|
|
397
484
|
};
|
|
398
485
|
|
|
399
|
-
export { createRouter };
|
|
486
|
+
export { KTRouter, createRouter };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ktjs/router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "Router for kt.js - client-side routing with navigation guards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"directory": "packages/router"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ktjs/core": "0.
|
|
34
|
+
"@ktjs/core": "0.14.3"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "rollup -c rollup.config.mjs",
|