crelte 0.3.0 → 0.3.2

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.
Files changed (55) hide show
  1. package/dist/Crelte.d.ts +12 -0
  2. package/dist/Crelte.d.ts.map +1 -1
  3. package/dist/Crelte.js +12 -0
  4. package/dist/CrelteRequest.d.ts +0 -4
  5. package/dist/CrelteRequest.d.ts.map +1 -1
  6. package/dist/CrelteRequest.js +0 -4
  7. package/dist/entry/EntryRouter.d.ts +30 -0
  8. package/dist/entry/EntryRouter.d.ts.map +1 -0
  9. package/dist/entry/EntryRouter.js +45 -0
  10. package/dist/entry/index.d.ts +32 -0
  11. package/dist/entry/index.d.ts.map +1 -0
  12. package/dist/entry/index.js +31 -0
  13. package/dist/index.d.ts +2 -6
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +0 -6
  16. package/dist/init/client.d.ts +1 -1
  17. package/dist/init/client.d.ts.map +1 -1
  18. package/dist/init/client.js +4 -3
  19. package/dist/init/server.d.ts.map +1 -1
  20. package/dist/init/server.js +3 -2
  21. package/dist/init/shared.d.ts +3 -1
  22. package/dist/init/shared.d.ts.map +1 -1
  23. package/dist/init/shared.js +47 -26
  24. package/dist/routing/InnerRouter.d.ts +1 -10
  25. package/dist/routing/InnerRouter.d.ts.map +1 -1
  26. package/dist/routing/InnerRouter.js +20 -21
  27. package/dist/routing/Request.d.ts +2 -0
  28. package/dist/routing/Request.d.ts.map +1 -1
  29. package/dist/routing/Request.js +9 -0
  30. package/dist/routing/Route.d.ts +67 -1
  31. package/dist/routing/Route.d.ts.map +1 -1
  32. package/dist/routing/Route.js +98 -2
  33. package/dist/routing/Router.d.ts +49 -12
  34. package/dist/routing/Router.d.ts.map +1 -1
  35. package/dist/routing/Router.js +82 -28
  36. package/dist/routing/index.d.ts +2 -2
  37. package/dist/routing/index.d.ts.map +1 -1
  38. package/dist/utils.d.ts +2 -0
  39. package/dist/utils.d.ts.map +1 -0
  40. package/dist/utils.js +8 -0
  41. package/package.json +9 -4
  42. package/src/Crelte.ts +15 -0
  43. package/src/CrelteRequest.ts +0 -4
  44. package/src/entry/EntryRouter.ts +71 -0
  45. package/src/entry/index.ts +48 -0
  46. package/src/index.ts +2 -11
  47. package/src/init/client.ts +10 -3
  48. package/src/init/server.ts +9 -2
  49. package/src/init/shared.ts +78 -28
  50. package/src/routing/InnerRouter.ts +29 -30
  51. package/src/routing/Request.ts +11 -0
  52. package/src/routing/Route.ts +107 -2
  53. package/src/routing/Router.ts +110 -31
  54. package/src/routing/index.ts +2 -1
  55. package/src/utils.ts +10 -0
@@ -17,6 +17,18 @@ const defaultRouterOpts = {
17
17
  debugTiming: false,
18
18
  };
19
19
 
20
+ /**
21
+ * Allows to easely modify a Request
22
+ *
23
+ * If you return `false` the request will be aborted
24
+ *
25
+ * ## Example
26
+ * ```
27
+ * router.replace(req => (req.hash = ''));
28
+ * ```
29
+ */
30
+ export type UpdateRequest = (req: Request) => boolean | null | undefined | void;
31
+
20
32
  type LoadedMore = {
21
33
  changeHistory: () => void;
22
34
  };
@@ -122,6 +134,8 @@ export default class Router {
122
134
 
123
135
  this._onRequest = new Listeners();
124
136
 
137
+ // these functions are exposed to the init "module"
138
+ // but should not be used by anybody else
125
139
  this._internal = {
126
140
  onLoaded: () => {},
127
141
  onNothingLoaded: () => {},
@@ -209,11 +223,15 @@ export default class Router {
209
223
  * // the following page will be opened https://example.com/de/foo/bar
210
224
  * ```
211
225
  */
212
- open(target: string | URL | Route | Request, opts: RequestOptions = {}) {
213
- const req = this.inner.targetToRequest(target, {
214
- ...opts,
226
+ open(
227
+ target: string | URL | Route | Request | UpdateRequest,
228
+ opts: RequestOptions = {},
229
+ ) {
230
+ const req = this.targetOrUpdateToRequest(target, opts, {
215
231
  origin: 'manual',
216
232
  });
233
+ if (!req) return;
234
+
217
235
  this.inner.open(req);
218
236
  }
219
237
 
@@ -221,14 +239,24 @@ export default class Router {
221
239
  * This pushes the new route without triggering a new pageload
222
240
  *
223
241
  * You can use this when using pagination for example change the route object
224
- * (search argument) and then call pushState
242
+ * (search argument) and then call push
225
243
  *
226
244
  * ## Note
227
245
  * This will always set the origin to 'push'
228
246
  * And will clear the scrollY value if you not provide a new one via the `opts`
229
247
  * This will disableLoadData by default if you not provide an override via the `opts`
230
248
  *
231
- * ## Example
249
+ * ## Example using the update function
250
+ * ```
251
+ * import { getRouter } from 'crelte';
252
+ *
253
+ * const router = getRouter();
254
+ *
255
+ * const page = 1;
256
+ * router.push(req => req.setSearchParam('page', page || null));
257
+ * ```
258
+ *
259
+ * ## Example using the route object
232
260
  * ```
233
261
  * import { getRouter } from 'crelte';
234
262
  *
@@ -237,21 +265,20 @@ export default class Router {
237
265
  * const page = 1;
238
266
  * const route = router.route.get();
239
267
  * route.setSearchParam('page', page > 0 ? page : null);
240
- * router.pushState(route);
268
+ * router.push(route);
241
269
  * ```
242
270
  */
243
- push(route: Route | Request, opts: RequestOptions = {}) {
244
- // cancel previous request
245
- this.pageLoader.discard();
246
- const req = this.inner.targetToRequest(route, {
247
- ...opts,
271
+ push(route: Route | Request | UpdateRequest, opts: RequestOptions = {}) {
272
+ // theoretically string and URL also work but we might
273
+ // change that in the future
274
+ const req = this.targetOrUpdateToRequest(route, opts, {
248
275
  origin: 'push',
249
276
  scrollY: opts.scrollY ?? undefined,
250
277
  disableLoadData: opts.disableLoadData ?? true,
251
278
  });
279
+ if (!req) return;
280
+
252
281
  this.inner.push(req);
253
- this.destroyRequest();
254
- this.setNewRoute(route);
255
282
  }
256
283
 
257
284
  /**
@@ -263,16 +290,26 @@ export default class Router {
263
290
  }
264
291
 
265
292
  /**
266
- * This replaces the state of the route without triggering an event
293
+ * This replaces the state of the route without triggering a new pageload
267
294
  *
268
295
  * You can use this when using some filters for example a search filter
269
296
  *
270
297
  * ## Note
271
298
  * This will always set the origin to 'replace'
272
- * And will clear the scrollY value if you not provide a new one via the `opts`
273
- * This will disableLoadData by default if you not provide an override via the `opts`
299
+ * And will clear the scrollY value if you don't provide a new one via the `opts`
300
+ * This will disableLoadData by default if you don't provide an override via the `opts`
274
301
  *
275
- * ## Example
302
+ * ## Example using the update function
303
+ * ```
304
+ * import { getRouter } from 'crelte';
305
+ *
306
+ * const router = getRouter();
307
+ *
308
+ * const search = 'foo';
309
+ * router.replace(req => req.setSearchParam('search', search));
310
+ * ```
311
+ *
312
+ * ## Example using the route object
276
313
  * ```
277
314
  * import { getRouter } from 'crelte';
278
315
  *
@@ -280,21 +317,21 @@ export default class Router {
280
317
  *
281
318
  * const search = 'foo';
282
319
  * const route = router.route.get();
283
- * route.setSearchParam('search', search ? search : null);
284
- * router.replaceState(route);
320
+ * route.setSearchParam('search', search);
321
+ * router.replace(route);
285
322
  * ```
286
323
  */
287
- replace(route: Route | Request, opts: RequestOptions = {}) {
288
- // cancel previous request
289
- this.pageLoader.discard();
290
- const req = this.inner.targetToRequest(route, {
324
+ replace(route: Route | Request | UpdateRequest, opts: RequestOptions = {}) {
325
+ // theoretically string and URL also work but we might
326
+ // change that in the future
327
+ const req = this.targetOrUpdateToRequest(route, opts, {
291
328
  origin: 'replace',
292
329
  scrollY: opts.scrollY ?? undefined,
293
330
  disableLoadData: opts.disableLoadData ?? true,
294
331
  });
332
+ if (!req) return;
333
+
295
334
  this.inner.replace(req);
296
- this.destroyRequest();
297
- this.setNewRoute(req);
298
335
  }
299
336
 
300
337
  /**
@@ -401,12 +438,12 @@ export default class Router {
401
438
  };
402
439
  });
403
440
 
404
- const route = this.inner.targetToRequest(url);
405
- route.origin = 'init';
441
+ const req = this.inner.targetToRequest(url);
442
+ req.origin = 'init';
406
443
 
407
444
  // let's see if the url matches any route and site
408
445
  // if not let's redirect to the site which matches the acceptLang
409
- if (!route.siteMatches()) {
446
+ if (!req.siteMatches()) {
410
447
  const site = this.inner.siteByAcceptLang(acceptLang);
411
448
 
412
449
  return {
@@ -417,14 +454,15 @@ export default class Router {
417
454
  };
418
455
  }
419
456
 
420
- this.inner.setRoute(route);
457
+ this.inner.route = req.toRoute();
458
+ this.inner.onRoute(req, () => {});
421
459
 
422
460
  const resp = await prom;
423
461
 
424
462
  const hist = this.inner.history as ServerHistory;
425
463
  if (hist.url || hist.req) {
426
464
  const nReq = this.inner.targetToRequest(hist.req ?? hist.url!);
427
- if (!route.eq(nReq)) {
465
+ if (!req.eq(nReq)) {
428
466
  return {
429
467
  success: true,
430
468
  redirect: true,
@@ -437,6 +475,7 @@ export default class Router {
437
475
  return resp;
438
476
  }
439
477
 
478
+ // gets called by the InnerRouter when a new route is requested
440
479
  private _onRoute(req: Request, changeHistory: () => void) {
441
480
  this.destroyRequest();
442
481
 
@@ -453,6 +492,7 @@ export default class Router {
453
492
  if (!req.disableLoadData) {
454
493
  this.pageLoader.load(req, { changeHistory });
455
494
  } else {
495
+ this.pageLoader.discard();
456
496
  this._onNothingLoaded(req, { changeHistory });
457
497
  }
458
498
  }
@@ -468,6 +508,7 @@ export default class Router {
468
508
  this.pageLoader.preload(req);
469
509
  }
470
510
 
511
+ // gets called by the pageLoader when teh loadData completes
471
512
  private async _onLoaded(
472
513
  resp: LoadResponse,
473
514
  req: Request,
@@ -477,7 +518,7 @@ export default class Router {
477
518
  if (await req._renderBarrier.ready()) return;
478
519
 
479
520
  // when the data is loaded let's update the route of the inner
480
- // this is will only happen if no other route has been requested
521
+ // this will only happen if no other route has been requested
481
522
  // in the meantime
482
523
  more.changeHistory();
483
524
 
@@ -490,6 +531,7 @@ export default class Router {
490
531
  });
491
532
  }
492
533
 
534
+ // this gets called if loadData is not called
493
535
  private async _onNothingLoaded(req: Request, more: LoadedMore) {
494
536
  // check if the render was cancelled
495
537
  if (await req._renderBarrier.ready()) return;
@@ -508,9 +550,46 @@ export default class Router {
508
550
  });
509
551
  }
510
552
 
553
+ // this is called by the pageLoader if we get a progress update
511
554
  private _onProgress(loading: boolean, progress?: number): void {
512
555
  if (this._loading.get() !== loading) this._loading.set(loading);
513
556
 
514
557
  if (typeof progress === 'number') this._loadingProgress.set(progress);
515
558
  }
559
+
560
+ /**
561
+ * Transforms a target to a request
562
+ *
563
+ * returns null if the request was canceled by the update request
564
+ */
565
+ private targetOrUpdateToRequest(
566
+ target: string | URL | Route | Request | UpdateRequest,
567
+ opts: RequestOptions = {},
568
+ forcedOpts: RequestOptions = {},
569
+ ): Request | null {
570
+ // we have an update request
571
+ if (typeof target === 'function') {
572
+ const route = this.route.get();
573
+ if (!route) {
574
+ throw new Error(
575
+ 'route to update missing in first loadData call',
576
+ );
577
+ }
578
+
579
+ // first get a req
580
+ const req = this.inner.targetToRequest(route, opts);
581
+ // check if the request was canceled by the update request
582
+ if (target(req) === false) return null;
583
+
584
+ // now we add the forcedOpts
585
+ req._updateOpts(forcedOpts);
586
+
587
+ return req;
588
+ }
589
+
590
+ return this.inner.targetToRequest(target, {
591
+ ...opts,
592
+ ...forcedOpts,
593
+ });
594
+ }
516
595
  }
@@ -1,10 +1,11 @@
1
- import Router from './Router.js';
1
+ import Router, { type UpdateRequest } from './Router.js';
2
2
  import Route, { type RouteOptions } from './Route.js';
3
3
  import Request, { type RequestOptions, type DelayRender } from './Request.js';
4
4
  import Site from './Site.js';
5
5
 
6
6
  export {
7
7
  Router,
8
+ UpdateRequest,
8
9
  Route,
9
10
  RouteOptions,
10
11
  Site,
package/src/utils.ts ADDED
@@ -0,0 +1,10 @@
1
+ // This are internal utils. Consider adding them to crelte-std instead
2
+
3
+ // this tries to do a structuredClone and else just uses JSON
4
+ export function objClone(obj: any): any {
5
+ if (typeof structuredClone === 'function') {
6
+ return structuredClone(obj);
7
+ }
8
+
9
+ return JSON.parse(JSON.stringify(obj));
10
+ }