crelte 0.3.1 → 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.
@@ -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
 
@@ -228,7 +246,17 @@ export default class Router {
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
  *
@@ -240,15 +268,16 @@ export default class Router {
240
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
282
  }
254
283
 
@@ -261,16 +290,26 @@ export default class Router {
261
290
  }
262
291
 
263
292
  /**
264
- * This replaces the state of the route without triggering an event
293
+ * This replaces the state of the route without triggering a new pageload
265
294
  *
266
295
  * You can use this when using some filters for example a search filter
267
296
  *
268
297
  * ## Note
269
298
  * This will always set the origin to 'replace'
270
- * And will clear the scrollY value if you not provide a new one via the `opts`
271
- * 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`
272
301
  *
273
- * ## 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
274
313
  * ```
275
314
  * import { getRouter } from 'crelte';
276
315
  *
@@ -278,18 +317,20 @@ export default class Router {
278
317
  *
279
318
  * const search = 'foo';
280
319
  * const route = router.route.get();
281
- * route.setSearchParam('search', search ? search : null);
282
- * router.replaceState(route);
320
+ * route.setSearchParam('search', search);
321
+ * router.replace(route);
283
322
  * ```
284
323
  */
285
- replace(route: Route | Request, opts: RequestOptions = {}) {
286
- // cancel previous request
287
- this.pageLoader.discard();
288
- 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, {
289
328
  origin: 'replace',
290
329
  scrollY: opts.scrollY ?? undefined,
291
330
  disableLoadData: opts.disableLoadData ?? true,
292
331
  });
332
+ if (!req) return;
333
+
293
334
  this.inner.replace(req);
294
335
  }
295
336
 
@@ -434,6 +475,7 @@ export default class Router {
434
475
  return resp;
435
476
  }
436
477
 
478
+ // gets called by the InnerRouter when a new route is requested
437
479
  private _onRoute(req: Request, changeHistory: () => void) {
438
480
  this.destroyRequest();
439
481
 
@@ -450,6 +492,7 @@ export default class Router {
450
492
  if (!req.disableLoadData) {
451
493
  this.pageLoader.load(req, { changeHistory });
452
494
  } else {
495
+ this.pageLoader.discard();
453
496
  this._onNothingLoaded(req, { changeHistory });
454
497
  }
455
498
  }
@@ -465,6 +508,7 @@ export default class Router {
465
508
  this.pageLoader.preload(req);
466
509
  }
467
510
 
511
+ // gets called by the pageLoader when teh loadData completes
468
512
  private async _onLoaded(
469
513
  resp: LoadResponse,
470
514
  req: Request,
@@ -474,7 +518,7 @@ export default class Router {
474
518
  if (await req._renderBarrier.ready()) return;
475
519
 
476
520
  // when the data is loaded let's update the route of the inner
477
- // this is will only happen if no other route has been requested
521
+ // this will only happen if no other route has been requested
478
522
  // in the meantime
479
523
  more.changeHistory();
480
524
 
@@ -487,6 +531,7 @@ export default class Router {
487
531
  });
488
532
  }
489
533
 
534
+ // this gets called if loadData is not called
490
535
  private async _onNothingLoaded(req: Request, more: LoadedMore) {
491
536
  // check if the render was cancelled
492
537
  if (await req._renderBarrier.ready()) return;
@@ -505,9 +550,46 @@ export default class Router {
505
550
  });
506
551
  }
507
552
 
553
+ // this is called by the pageLoader if we get a progress update
508
554
  private _onProgress(loading: boolean, progress?: number): void {
509
555
  if (this._loading.get() !== loading) this._loading.set(loading);
510
556
 
511
557
  if (typeof progress === 'number') this._loadingProgress.set(progress);
512
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
+ }
513
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,