@ktjs/router 0.14.4 → 0.14.7

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 CHANGED
@@ -153,8 +153,6 @@ interface Router {
153
153
 
154
154
  /** Navigate forward in history */
155
155
  forward(): void;
156
-
157
- initCurrentRoute(): void;
158
156
  }
159
157
 
160
158
  interface RouteMatch {
@@ -172,10 +172,10 @@ var __ktjs_router__ = (function (exports) {
172
172
  const baseUrl = config.baseUrl ?? '';
173
173
  // # private values
174
174
  const routes = [];
175
+ const history = [];
175
176
  let routerView = null;
176
- /**
177
- * Normalize routes by adding default guards
178
- */
177
+ let current = null;
178
+ // # methods
179
179
  const normalize = (rawRoutes, parentPath) => rawRoutes.map((route) => {
180
180
  const path = normalizePath(parentPath, route.path);
181
181
  const normalized = {
@@ -192,38 +192,6 @@ var __ktjs_router__ = (function (exports) {
192
192
  routes.push(normalized);
193
193
  return normalized;
194
194
  });
195
- // Normalize routes with default guards
196
- normalize(config.routes, '/');
197
- const { findByName, match } = createMatcher(routes);
198
- /**
199
- * Initialize current route from URL
200
- */
201
- const initCurrentRoute = () => {
202
- const hash = window.location.hash.slice(1); // Remove '#'
203
- if (!hash) {
204
- return (current = null);
205
- }
206
- // Parse path and query
207
- const [path, queryString] = hash.split('?');
208
- const normalizedPath = normalizePath(path);
209
- // Match route
210
- const matched = match(normalizedPath);
211
- if (!matched) {
212
- return (current = null);
213
- }
214
- // Build route context
215
- return (current = {
216
- path: normalizedPath,
217
- name: matched.route.name,
218
- params: matched.params,
219
- query: queryString ? parseQuery(queryString) : {},
220
- meta: matched.route.meta ?? {},
221
- matched: matched.result,
222
- });
223
- };
224
- let current = null;
225
- const history = current ? [current] : [];
226
- // # methods
227
195
  const executeGuardsSync = (to, from, guardLevel) => {
228
196
  try {
229
197
  if (guardLevel === 0 /* GuardLevel.None */) {
@@ -365,17 +333,28 @@ var __ktjs_router__ = (function (exports) {
365
333
  }
366
334
  return false;
367
335
  }
368
- // Update browser history
336
+ // Update browser history depending on mode
369
337
  const url = fullPath;
338
+ const hashUrl = '#' + fullPath;
370
339
  if (replace) {
371
- window.history.replaceState({ path: to.path }, '', url);
340
+ window.location.replace(hashUrl);
372
341
  }
373
342
  else {
374
- window.history.pushState({ path: to.path }, '', url);
343
+ window.location.hash = fullPath;
375
344
  }
376
- // Update current route
345
+ // Update current route in memory
377
346
  current = to;
378
- history.push(to);
347
+ if (replace) {
348
+ if (history.length > 0) {
349
+ history[history.length - 1] = to;
350
+ }
351
+ else {
352
+ history.push(to);
353
+ }
354
+ }
355
+ else {
356
+ history.push(to);
357
+ }
379
358
  // Render component if routerView exists
380
359
  if (routerView && to.matched.length > 0) {
381
360
  const route = to.matched[to.matched.length - 1];
@@ -423,15 +402,25 @@ var __ktjs_router__ = (function (exports) {
423
402
  return false;
424
403
  }
425
404
  // ---- Guards passed ----
426
- const url = fullPath;
405
+ const hashUrl = '#' + fullPath;
427
406
  if (replace) {
428
- window.history.replaceState({ path: to.path }, '', url);
407
+ window.location.replace(hashUrl);
429
408
  }
430
409
  else {
431
- window.history.pushState({ path: to.path }, '', url);
410
+ window.location.hash = fullPath;
432
411
  }
433
412
  current = to;
434
- history.push(to);
413
+ if (replace) {
414
+ if (history.length > 0) {
415
+ history[history.length - 1] = to;
416
+ }
417
+ else {
418
+ history.push(to);
419
+ }
420
+ }
421
+ else {
422
+ history.push(to);
423
+ }
435
424
  // Render component if routerView exists
436
425
  if (routerView && to.matched.length > 0) {
437
426
  const route = to.matched[to.matched.length - 1];
@@ -464,23 +453,63 @@ var __ktjs_router__ = (function (exports) {
464
453
  * Normalize navigation argument
465
454
  */
466
455
  const normalizeLocation = (loc) => {
467
- if (typeof loc === 'string') {
468
- // Parse path and query
469
- const [path, queryString] = loc.split('?');
470
- return {
471
- path,
472
- query: queryString ? parseQuery(queryString) : undefined,
473
- };
456
+ if (typeof loc !== 'string') {
457
+ return loc;
474
458
  }
475
- return loc;
459
+ const [path, queryString] = loc.split('?');
460
+ return {
461
+ path,
462
+ query: queryString ? parseQuery(queryString) : undefined,
463
+ };
476
464
  };
477
465
  // # register events
478
- // Listen to browser back/forward
479
- window.addEventListener('popstate', (event) => {
480
- if (event.state?.path) {
481
- navigate({ path: event.state.path, guardLevel: 1 /* GuardLevel.Global */, replace: true });
466
+ // hash mode: listen to hashchange
467
+ window.addEventListener('hashchange', () => {
468
+ const hash = window.location.hash.slice(1);
469
+ const [path] = hash.split('?');
470
+ const normalizedPath = normalizePath(path);
471
+ if (current && current.path === normalizedPath) {
472
+ return;
473
+ }
474
+ // render route for new hash without adding extra history entry
475
+ const matched = match(normalizedPath);
476
+ if (!matched) {
477
+ onNotFound(normalizedPath);
478
+ return;
482
479
  }
480
+ const queryString = window.location.hash.slice(1).split('?')[1];
481
+ const to = {
482
+ path: normalizedPath,
483
+ name: matched.route.name,
484
+ params: matched.params,
485
+ query: queryString ? parseQuery(queryString) : {},
486
+ meta: matched.route.meta ?? {},
487
+ matched: matched.result,
488
+ };
489
+ // apply without modifying browser history
490
+ current = to;
491
+ history.push(to);
492
+ if (routerView && to.matched.length > 0) {
493
+ const route = to.matched[to.matched.length - 1];
494
+ if (route.component) {
495
+ const element = route.component();
496
+ if (element instanceof Promise) {
497
+ element.then((el) => {
498
+ routerView.innerHTML = '';
499
+ routerView.appendChild(el);
500
+ });
501
+ }
502
+ else {
503
+ routerView.innerHTML = '';
504
+ routerView.appendChild(element);
505
+ }
506
+ }
507
+ }
508
+ executeAfterHooksSync(to, history[history.length - 2] ?? null);
483
509
  });
510
+ // # initialize
511
+ normalize(config.routes, '/');
512
+ const { findByName, match } = createMatcher(routes);
484
513
  // Router instance
485
514
  return {
486
515
  get current() {
@@ -510,7 +539,6 @@ var __ktjs_router__ = (function (exports) {
510
539
  forward() {
511
540
  window.history.forward();
512
541
  },
513
- initCurrentRoute,
514
542
  };
515
543
  };
516
544
 
@@ -263,10 +263,10 @@ var __ktjs_router__ = (function (exports) {
263
263
  var baseUrl = (_f = config.baseUrl) !== null && _f !== void 0 ? _f : '';
264
264
  // # private values
265
265
  var routes = [];
266
+ var history = [];
266
267
  var routerView = null;
267
- /**
268
- * Normalize routes by adding default guards
269
- */
268
+ var current = null;
269
+ // # methods
270
270
  var normalize = function (rawRoutes, parentPath) {
271
271
  return rawRoutes.map(function (route) {
272
272
  var _a, _b, _c, _d;
@@ -286,39 +286,6 @@ var __ktjs_router__ = (function (exports) {
286
286
  return normalized;
287
287
  });
288
288
  };
289
- // Normalize routes with default guards
290
- normalize(config.routes, '/');
291
- var _g = createMatcher(routes), findByName = _g.findByName, match = _g.match;
292
- /**
293
- * Initialize current route from URL
294
- */
295
- var initCurrentRoute = function () {
296
- var _a;
297
- var hash = window.location.hash.slice(1); // Remove '#'
298
- if (!hash) {
299
- return (current = null);
300
- }
301
- // Parse path and query
302
- var _b = hash.split('?'), path = _b[0], queryString = _b[1];
303
- var normalizedPath = normalizePath(path);
304
- // Match route
305
- var matched = match(normalizedPath);
306
- if (!matched) {
307
- return (current = null);
308
- }
309
- // Build route context
310
- return (current = {
311
- path: normalizedPath,
312
- name: matched.route.name,
313
- params: matched.params,
314
- query: queryString ? parseQuery(queryString) : {},
315
- meta: (_a = matched.route.meta) !== null && _a !== void 0 ? _a : {},
316
- matched: matched.result,
317
- });
318
- };
319
- var current = null;
320
- var history = current ? [current] : [];
321
- // # methods
322
289
  var executeGuardsSync = function (to, from, guardLevel) {
323
290
  try {
324
291
  if (guardLevel === 0 /* GuardLevel.None */) {
@@ -474,17 +441,28 @@ var __ktjs_router__ = (function (exports) {
474
441
  }
475
442
  return false;
476
443
  }
477
- // Update browser history
444
+ // Update browser history depending on mode
478
445
  var url = fullPath;
446
+ var hashUrl = '#' + fullPath;
479
447
  if (replace) {
480
- window.history.replaceState({ path: to.path }, '', url);
448
+ window.location.replace(hashUrl);
481
449
  }
482
450
  else {
483
- window.history.pushState({ path: to.path }, '', url);
451
+ window.location.hash = fullPath;
484
452
  }
485
- // Update current route
453
+ // Update current route in memory
486
454
  current = to;
487
- history.push(to);
455
+ if (replace) {
456
+ if (history.length > 0) {
457
+ history[history.length - 1] = to;
458
+ }
459
+ else {
460
+ history.push(to);
461
+ }
462
+ }
463
+ else {
464
+ history.push(to);
465
+ }
488
466
  // Render component if routerView exists
489
467
  if (routerView && to.matched.length > 0) {
490
468
  var route = to.matched[to.matched.length - 1];
@@ -517,7 +495,7 @@ var __ktjs_router__ = (function (exports) {
517
495
  args_1[_i - 1] = arguments[_i];
518
496
  }
519
497
  return __awaiter(void 0, __spreadArray([options_1], args_1, true), void 0, function (options, redirectCount) {
520
- var prep, guardLevel, replace, to, fullPath, guardResult, url, route, element, error_2;
498
+ var prep, guardLevel, replace, to, fullPath, guardResult, hashUrl, route, element, error_2;
521
499
  var _a;
522
500
  if (redirectCount === void 0) { redirectCount = 0; }
523
501
  return __generator(this, function (_b) {
@@ -544,15 +522,25 @@ var __ktjs_router__ = (function (exports) {
544
522
  }
545
523
  return [2 /*return*/, false];
546
524
  }
547
- url = fullPath;
525
+ hashUrl = '#' + fullPath;
548
526
  if (replace) {
549
- window.history.replaceState({ path: to.path }, '', url);
527
+ window.location.replace(hashUrl);
550
528
  }
551
529
  else {
552
- window.history.pushState({ path: to.path }, '', url);
530
+ window.location.hash = fullPath;
553
531
  }
554
532
  current = to;
555
- history.push(to);
533
+ if (replace) {
534
+ if (history.length > 0) {
535
+ history[history.length - 1] = to;
536
+ }
537
+ else {
538
+ history.push(to);
539
+ }
540
+ }
541
+ else {
542
+ history.push(to);
543
+ }
556
544
  if (!(routerView && to.matched.length > 0)) return [3 /*break*/, 3];
557
545
  route = to.matched[to.matched.length - 1];
558
546
  if (!route.component) return [3 /*break*/, 3];
@@ -600,24 +588,64 @@ var __ktjs_router__ = (function (exports) {
600
588
  * Normalize navigation argument
601
589
  */
602
590
  var normalizeLocation = function (loc) {
603
- if (typeof loc === 'string') {
604
- // Parse path and query
605
- var _a = loc.split('?'), path = _a[0], queryString = _a[1];
606
- return {
607
- path: path,
608
- query: queryString ? parseQuery(queryString) : undefined,
609
- };
591
+ if (typeof loc !== 'string') {
592
+ return loc;
610
593
  }
611
- return loc;
594
+ var _a = loc.split('?'), path = _a[0], queryString = _a[1];
595
+ return {
596
+ path: path,
597
+ query: queryString ? parseQuery(queryString) : undefined,
598
+ };
612
599
  };
613
600
  // # register events
614
- // Listen to browser back/forward
615
- window.addEventListener('popstate', function (event) {
616
- var _a;
617
- if ((_a = event.state) === null || _a === void 0 ? void 0 : _a.path) {
618
- navigate({ path: event.state.path, guardLevel: 1 /* GuardLevel.Global */, replace: true });
601
+ // hash mode: listen to hashchange
602
+ window.addEventListener('hashchange', function () {
603
+ var _a, _b;
604
+ var hash = window.location.hash.slice(1);
605
+ var path = hash.split('?')[0];
606
+ var normalizedPath = normalizePath(path);
607
+ if (current && current.path === normalizedPath) {
608
+ return;
609
+ }
610
+ // render route for new hash without adding extra history entry
611
+ var matched = match(normalizedPath);
612
+ if (!matched) {
613
+ onNotFound(normalizedPath);
614
+ return;
619
615
  }
616
+ var queryString = window.location.hash.slice(1).split('?')[1];
617
+ var to = {
618
+ path: normalizedPath,
619
+ name: matched.route.name,
620
+ params: matched.params,
621
+ query: queryString ? parseQuery(queryString) : {},
622
+ meta: (_a = matched.route.meta) !== null && _a !== void 0 ? _a : {},
623
+ matched: matched.result,
624
+ };
625
+ // apply without modifying browser history
626
+ current = to;
627
+ history.push(to);
628
+ if (routerView && to.matched.length > 0) {
629
+ var route = to.matched[to.matched.length - 1];
630
+ if (route.component) {
631
+ var element = route.component();
632
+ if (element instanceof Promise) {
633
+ element.then(function (el) {
634
+ routerView.innerHTML = '';
635
+ routerView.appendChild(el);
636
+ });
637
+ }
638
+ else {
639
+ routerView.innerHTML = '';
640
+ routerView.appendChild(element);
641
+ }
642
+ }
643
+ }
644
+ executeAfterHooksSync(to, (_b = history[history.length - 2]) !== null && _b !== void 0 ? _b : null);
620
645
  });
646
+ // # initialize
647
+ normalize(config.routes, '/');
648
+ var _g = createMatcher(routes), findByName = _g.findByName, match = _g.match;
621
649
  // Router instance
622
650
  return {
623
651
  get current() {
@@ -647,7 +675,6 @@ var __ktjs_router__ = (function (exports) {
647
675
  forward: function () {
648
676
  window.history.forward();
649
677
  },
650
- initCurrentRoute: initCurrentRoute,
651
678
  };
652
679
  };
653
680
 
package/dist/index.mjs CHANGED
@@ -169,10 +169,10 @@ const createRouter = (config) => {
169
169
  const baseUrl = config.baseUrl ?? '';
170
170
  // # private values
171
171
  const routes = [];
172
+ const history = [];
172
173
  let routerView = null;
173
- /**
174
- * Normalize routes by adding default guards
175
- */
174
+ let current = null;
175
+ // # methods
176
176
  const normalize = (rawRoutes, parentPath) => rawRoutes.map((route) => {
177
177
  const path = normalizePath(parentPath, route.path);
178
178
  const normalized = {
@@ -189,38 +189,6 @@ const createRouter = (config) => {
189
189
  routes.push(normalized);
190
190
  return normalized;
191
191
  });
192
- // Normalize routes with default guards
193
- normalize(config.routes, '/');
194
- const { findByName, match } = createMatcher(routes);
195
- /**
196
- * Initialize current route from URL
197
- */
198
- const initCurrentRoute = () => {
199
- const hash = window.location.hash.slice(1); // Remove '#'
200
- if (!hash) {
201
- return (current = null);
202
- }
203
- // Parse path and query
204
- const [path, queryString] = hash.split('?');
205
- const normalizedPath = normalizePath(path);
206
- // Match route
207
- const matched = match(normalizedPath);
208
- if (!matched) {
209
- return (current = null);
210
- }
211
- // Build route context
212
- return (current = {
213
- path: normalizedPath,
214
- name: matched.route.name,
215
- params: matched.params,
216
- query: queryString ? parseQuery(queryString) : {},
217
- meta: matched.route.meta ?? {},
218
- matched: matched.result,
219
- });
220
- };
221
- let current = null;
222
- const history = current ? [current] : [];
223
- // # methods
224
192
  const executeGuardsSync = (to, from, guardLevel) => {
225
193
  try {
226
194
  if (guardLevel === 0 /* GuardLevel.None */) {
@@ -362,17 +330,28 @@ const createRouter = (config) => {
362
330
  }
363
331
  return false;
364
332
  }
365
- // Update browser history
333
+ // Update browser history depending on mode
366
334
  const url = fullPath;
335
+ const hashUrl = '#' + fullPath;
367
336
  if (replace) {
368
- window.history.replaceState({ path: to.path }, '', url);
337
+ window.location.replace(hashUrl);
369
338
  }
370
339
  else {
371
- window.history.pushState({ path: to.path }, '', url);
340
+ window.location.hash = fullPath;
372
341
  }
373
- // Update current route
342
+ // Update current route in memory
374
343
  current = to;
375
- history.push(to);
344
+ if (replace) {
345
+ if (history.length > 0) {
346
+ history[history.length - 1] = to;
347
+ }
348
+ else {
349
+ history.push(to);
350
+ }
351
+ }
352
+ else {
353
+ history.push(to);
354
+ }
376
355
  // Render component if routerView exists
377
356
  if (routerView && to.matched.length > 0) {
378
357
  const route = to.matched[to.matched.length - 1];
@@ -420,15 +399,25 @@ const createRouter = (config) => {
420
399
  return false;
421
400
  }
422
401
  // ---- Guards passed ----
423
- const url = fullPath;
402
+ const hashUrl = '#' + fullPath;
424
403
  if (replace) {
425
- window.history.replaceState({ path: to.path }, '', url);
404
+ window.location.replace(hashUrl);
426
405
  }
427
406
  else {
428
- window.history.pushState({ path: to.path }, '', url);
407
+ window.location.hash = fullPath;
429
408
  }
430
409
  current = to;
431
- history.push(to);
410
+ if (replace) {
411
+ if (history.length > 0) {
412
+ history[history.length - 1] = to;
413
+ }
414
+ else {
415
+ history.push(to);
416
+ }
417
+ }
418
+ else {
419
+ history.push(to);
420
+ }
432
421
  // Render component if routerView exists
433
422
  if (routerView && to.matched.length > 0) {
434
423
  const route = to.matched[to.matched.length - 1];
@@ -461,23 +450,63 @@ const createRouter = (config) => {
461
450
  * Normalize navigation argument
462
451
  */
463
452
  const normalizeLocation = (loc) => {
464
- if (typeof loc === 'string') {
465
- // Parse path and query
466
- const [path, queryString] = loc.split('?');
467
- return {
468
- path,
469
- query: queryString ? parseQuery(queryString) : undefined,
470
- };
453
+ if (typeof loc !== 'string') {
454
+ return loc;
471
455
  }
472
- return loc;
456
+ const [path, queryString] = loc.split('?');
457
+ return {
458
+ path,
459
+ query: queryString ? parseQuery(queryString) : undefined,
460
+ };
473
461
  };
474
462
  // # register events
475
- // Listen to browser back/forward
476
- window.addEventListener('popstate', (event) => {
477
- if (event.state?.path) {
478
- navigate({ path: event.state.path, guardLevel: 1 /* GuardLevel.Global */, replace: true });
463
+ // hash mode: listen to hashchange
464
+ window.addEventListener('hashchange', () => {
465
+ const hash = window.location.hash.slice(1);
466
+ const [path] = hash.split('?');
467
+ const normalizedPath = normalizePath(path);
468
+ if (current && current.path === normalizedPath) {
469
+ return;
470
+ }
471
+ // render route for new hash without adding extra history entry
472
+ const matched = match(normalizedPath);
473
+ if (!matched) {
474
+ onNotFound(normalizedPath);
475
+ return;
479
476
  }
477
+ const queryString = window.location.hash.slice(1).split('?')[1];
478
+ const to = {
479
+ path: normalizedPath,
480
+ name: matched.route.name,
481
+ params: matched.params,
482
+ query: queryString ? parseQuery(queryString) : {},
483
+ meta: matched.route.meta ?? {},
484
+ matched: matched.result,
485
+ };
486
+ // apply without modifying browser history
487
+ current = to;
488
+ history.push(to);
489
+ if (routerView && to.matched.length > 0) {
490
+ const route = to.matched[to.matched.length - 1];
491
+ if (route.component) {
492
+ const element = route.component();
493
+ if (element instanceof Promise) {
494
+ element.then((el) => {
495
+ routerView.innerHTML = '';
496
+ routerView.appendChild(el);
497
+ });
498
+ }
499
+ else {
500
+ routerView.innerHTML = '';
501
+ routerView.appendChild(element);
502
+ }
503
+ }
504
+ }
505
+ executeAfterHooksSync(to, history[history.length - 2] ?? null);
480
506
  });
507
+ // # initialize
508
+ normalize(config.routes, '/');
509
+ const { findByName, match } = createMatcher(routes);
481
510
  // Router instance
482
511
  return {
483
512
  get current() {
@@ -507,7 +536,6 @@ const createRouter = (config) => {
507
536
  forward() {
508
537
  window.history.forward();
509
538
  },
510
- initCurrentRoute,
511
539
  };
512
540
  };
513
541
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/router",
3
- "version": "0.14.4",
3
+ "version": "0.14.7",
4
4
  "description": "Router for kt.js - client-side routing with navigation guards",
5
5
  "type": "module",
6
6
  "module": "./dist/index.mjs",