crelte 0.4.8 → 0.5.0-alpha.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 (110) hide show
  1. package/dist/Crelte.d.ts +7 -6
  2. package/dist/Crelte.d.ts.map +1 -1
  3. package/dist/Crelte.js +5 -13
  4. package/dist/CrelteRequest.d.ts +9 -0
  5. package/dist/CrelteRequest.d.ts.map +1 -1
  6. package/dist/CrelteRequest.js +16 -2
  7. package/dist/blocks/Blocks.svelte +2 -2
  8. package/dist/blocks/Blocks.svelte.d.ts +3 -19
  9. package/dist/blocks/Blocks.svelte.d.ts.map +1 -1
  10. package/dist/cookies/ClientCookies.d.ts +0 -1
  11. package/dist/cookies/ClientCookies.d.ts.map +1 -1
  12. package/dist/cookies/ClientCookies.js +0 -1
  13. package/dist/cookies/ServerCookies.d.ts +1 -2
  14. package/dist/cookies/ServerCookies.d.ts.map +1 -1
  15. package/dist/cookies/ServerCookies.js +2 -6
  16. package/dist/cookies/index.d.ts +0 -2
  17. package/dist/cookies/index.d.ts.map +1 -1
  18. package/dist/graphql/GraphQl.d.ts +2 -2
  19. package/dist/graphql/GraphQl.d.ts.map +1 -1
  20. package/dist/index.d.ts +9 -3
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +14 -6
  23. package/dist/init/InternalApp.d.ts +30 -0
  24. package/dist/init/InternalApp.d.ts.map +1 -0
  25. package/dist/init/InternalApp.js +71 -0
  26. package/dist/init/client.d.ts +0 -5
  27. package/dist/init/client.d.ts.map +1 -1
  28. package/dist/init/client.js +88 -75
  29. package/dist/init/crelte-vite-plugin.d.ts +5 -0
  30. package/dist/init/server.d.ts +0 -5
  31. package/dist/init/server.d.ts.map +1 -1
  32. package/dist/init/server.js +49 -20
  33. package/dist/init/shared.d.ts +7 -18
  34. package/dist/init/shared.d.ts.map +1 -1
  35. package/dist/init/shared.js +97 -154
  36. package/dist/init/svelteComponents.d.ts +3 -0
  37. package/dist/init/svelteComponents.d.ts.map +1 -0
  38. package/dist/init/svelteComponents.js +7 -0
  39. package/dist/loadData/Globals.d.ts +40 -33
  40. package/dist/loadData/Globals.d.ts.map +1 -1
  41. package/dist/loadData/Globals.js +99 -88
  42. package/dist/loadData/index.d.ts +3 -2
  43. package/dist/loadData/index.d.ts.map +1 -1
  44. package/dist/loadData/index.js +2 -0
  45. package/dist/plugins/Events.d.ts +11 -13
  46. package/dist/plugins/Events.d.ts.map +1 -1
  47. package/dist/plugins/Events.js +10 -3
  48. package/dist/routing/BaseRoute.d.ts +255 -0
  49. package/dist/routing/BaseRoute.d.ts.map +1 -0
  50. package/dist/routing/BaseRoute.js +349 -0
  51. package/dist/routing/BaseRouter.d.ts +210 -0
  52. package/dist/routing/BaseRouter.d.ts.map +1 -0
  53. package/dist/routing/BaseRouter.js +444 -0
  54. package/dist/routing/ClientRouter.d.ts +32 -0
  55. package/dist/routing/ClientRouter.d.ts.map +1 -0
  56. package/dist/routing/ClientRouter.js +259 -0
  57. package/dist/routing/LoadRunner.d.ts +39 -0
  58. package/dist/routing/LoadRunner.d.ts.map +1 -0
  59. package/dist/routing/{PageLoader.js → LoadRunner.js} +32 -20
  60. package/dist/routing/Request.d.ts +35 -3
  61. package/dist/routing/Request.d.ts.map +1 -1
  62. package/dist/routing/Request.js +64 -5
  63. package/dist/routing/Route.d.ts +24 -223
  64. package/dist/routing/Route.d.ts.map +1 -1
  65. package/dist/routing/Route.js +26 -315
  66. package/dist/routing/Router.d.ts +49 -73
  67. package/dist/routing/Router.d.ts.map +1 -1
  68. package/dist/routing/Router.js +85 -251
  69. package/dist/routing/ServerRouter.d.ts +23 -0
  70. package/dist/routing/ServerRouter.d.ts.map +1 -0
  71. package/dist/routing/ServerRouter.js +57 -0
  72. package/dist/routing/utils.d.ts +5 -0
  73. package/dist/routing/utils.d.ts.map +1 -1
  74. package/dist/routing/utils.js +39 -0
  75. package/dist/utils.d.ts +1 -0
  76. package/dist/utils.d.ts.map +1 -1
  77. package/dist/utils.js +3 -0
  78. package/package.json +7 -6
  79. package/src/Crelte.ts +12 -18
  80. package/src/CrelteRequest.ts +21 -2
  81. package/src/cookies/ClientCookies.ts +0 -2
  82. package/src/cookies/ServerCookies.ts +2 -7
  83. package/src/cookies/index.ts +0 -3
  84. package/src/graphql/GraphQl.ts +2 -1
  85. package/src/index.ts +17 -9
  86. package/src/init/InternalApp.ts +134 -0
  87. package/src/init/client.ts +104 -93
  88. package/src/init/crelte-vite-plugin.d.ts +5 -0
  89. package/src/init/server.ts +67 -35
  90. package/src/init/shared.ts +107 -227
  91. package/src/init/svelteComponents.ts +12 -0
  92. package/src/loadData/Globals.ts +121 -102
  93. package/src/loadData/index.ts +3 -2
  94. package/src/plugins/Events.ts +40 -42
  95. package/src/routing/BaseRoute.ts +422 -0
  96. package/src/routing/BaseRouter.ts +528 -0
  97. package/src/routing/ClientRouter.ts +329 -0
  98. package/src/routing/{PageLoader.ts → LoadRunner.ts} +43 -30
  99. package/src/routing/Request.ts +97 -12
  100. package/src/routing/Route.ts +56 -376
  101. package/src/routing/Router.ts +100 -359
  102. package/src/routing/ServerRouter.ts +78 -0
  103. package/src/routing/utils.ts +53 -0
  104. package/src/utils.ts +4 -0
  105. package/dist/routing/InnerRouter.d.ts +0 -113
  106. package/dist/routing/InnerRouter.d.ts.map +0 -1
  107. package/dist/routing/InnerRouter.js +0 -417
  108. package/dist/routing/PageLoader.d.ts +0 -36
  109. package/dist/routing/PageLoader.d.ts.map +0 -1
  110. package/src/routing/InnerRouter.ts +0 -498
@@ -1,498 +0,0 @@
1
- import Site, { SiteFromGraphQl, siteFromUrl } from './Site.js';
2
- import History from './History.js';
3
- import { ClientHistory, ServerHistory } from './History.js';
4
- import Request, { isRequest, RequestOptions } from './Request.js';
5
- import Route from './Route.js';
6
-
7
- export type InnerRouterOpts = {
8
- preloadOnMouseOver: boolean;
9
- };
10
-
11
- /**
12
- * Manages event listeners or functions.
13
- */
14
- export default class InnerRouter {
15
- sites: Site[];
16
- /**
17
- * The current route
18
- *
19
- * ## Null
20
- * It might be null on the first targetToRequest, open, and routeFromUrl call
21
- */
22
- route: Route | null;
23
- history: History;
24
- preloadOnMouseOver: boolean;
25
- /**
26
- * @param changeHistory returns a function you need to call when you are ready to
27
- update the window history (note do not call this after another onRoute call was made)
28
- */
29
- onRoute: (route: Request, changeHistory: () => void) => void;
30
- onPreload: (route: Request) => void;
31
-
32
- private scrollDebounceTimeout: any | null;
33
-
34
- /**
35
- * Creates a new Router
36
- *
37
- * @param sites - sites needs to be from craft-graphql-sites plugin
38
- * @param opts - Options for the router
39
- */
40
- constructor(sites: SiteFromGraphQl[], opts: InnerRouterOpts) {
41
- this.sites = sites.map(s => new Site(s));
42
-
43
- this.route = null;
44
- // @ts-ignore
45
- this.history = import.meta.env.SSR
46
- ? new ServerHistory()
47
- : new ClientHistory();
48
- this.preloadOnMouseOver = opts.preloadOnMouseOver;
49
-
50
- // this.preloadListeners = new Listeners();
51
-
52
- this.onRoute = () => {};
53
- this.onPreload = () => {};
54
-
55
- this.scrollDebounceTimeout = null;
56
- }
57
-
58
- /**
59
- * Initializes the router when running on the client.
60
- */
61
- initClient() {
62
- this.listen();
63
-
64
- // let's first try to load from the state
65
- const req = this.targetToRequest(window.location.href);
66
- req._fillFromState(window.history.state);
67
-
68
- req.origin = 'init';
69
- window.history.scrollRestoration = 'manual';
70
-
71
- // we set it now instead of waiting for the onRoute call
72
- // because the window.history is already set
73
- this.route = req.toRoute();
74
- this.onRoute(req, () => {});
75
- }
76
-
77
- /**
78
- * Initializes the router when running on the server.
79
- */
80
- initServer() {}
81
-
82
- /**
83
- * Get a site and if possible use the accept lang header.
84
- *
85
- * @param acceptLang Accept Language header.
86
- */
87
- siteByAcceptLang(acceptLang: string | null = null): Site {
88
- if (!acceptLang) return this.defaultSite();
89
-
90
- const directives = acceptLang
91
- .split(',')
92
- .map(d => d.trim())
93
- .filter(d => !!d);
94
-
95
- // let's expect that weights are correctly ordered
96
- const languages = directives
97
- .map(d => {
98
- const lang = d.split(';');
99
- return lang[0].trim();
100
- })
101
- .filter(d => !!d);
102
-
103
- // find a site which matches the language
104
- // first try to match the full language
105
- for (const lang of languages) {
106
- const site = this.sites.find(s => s.language === lang);
107
- if (site) return site;
108
- }
109
-
110
- // if we don't find any language which matches
111
- // try to match languages without the -
112
- for (let lang of languages) {
113
- lang = lang.split('-')[0];
114
- const site = this.sites.find(s => {
115
- const sLang = s.language.split('-')[0];
116
- return sLang === lang;
117
- });
118
- if (site) return site;
119
- }
120
-
121
- // we did not find a match then just return the first site
122
- return this.defaultSite();
123
- }
124
-
125
- /**
126
- * Get the default site
127
- */
128
- defaultSite(): Site {
129
- return this.sites.find(s => s.primary) ?? this.sites[0];
130
- }
131
-
132
- /**
133
- * Tries to get a site by it's id
134
- */
135
- siteById(id: number): Site | null {
136
- return this.sites.find(s => s.id === id) ?? null;
137
- }
138
-
139
- // keep this doc in sync with Router.targetToRequest
140
- /**
141
- * Resolve a url or Route and convert it to a Request
142
- *
143
- * @param target
144
- * @param opts, any option present will override the value in target
145
- * @return Returns null if the url does not match our host (the protocol get's ignored)
146
- */
147
- targetToRequest(
148
- target: string | URL | Route | Request,
149
- opts: RequestOptions = {},
150
- ): Request {
151
- if (typeof target === 'string') {
152
- if (target.startsWith('/')) {
153
- // todo should we use the language matching or throw if the route does not
154
- // exists
155
- const site = this.route?.site ?? this.defaultSite();
156
- target = new URL(site.uri + target, site.url);
157
- } else if (!target) {
158
- throw new Error('the url is not allowed to be empty');
159
- } else {
160
- target = new URL(target);
161
- }
162
- }
163
-
164
- if (target instanceof URL) {
165
- target = this.routeFromUrl(target);
166
- }
167
-
168
- if (!isRequest(target)) {
169
- return Request.fromRoute(target, opts);
170
- }
171
-
172
- target._updateOpts(opts);
173
- return target;
174
- }
175
-
176
- /**
177
- * Resolve a url and convert it to a Route
178
- *
179
- * @param url
180
- * @return Returns null if the url does not match our host (the protocol get's ignored)
181
- */
182
- routeFromUrl(fullUrl: URL): Route {
183
- // strip stuff we dont need from url
184
- const route = new Route(fullUrl, null!);
185
- const url = route.url;
186
-
187
- const site = siteFromUrl(url, this.sites);
188
-
189
- // todo should we throw if we can't find a site
190
- // or use the site which matches the language
191
- route.site = site ?? this.defaultSite();
192
-
193
- return route;
194
- }
195
-
196
- listen() {
197
- window.addEventListener('click', async e => {
198
- // @ts-ignore
199
- const link = e.target.closest('a');
200
- const openInNewTab = e.metaKey || e.ctrlKey || e.shiftKey;
201
- const saveLink = e.altKey;
202
- if (!link || !link.href || openInNewTab || saveLink) return;
203
- if (link.target.toLowerCase() === '_blank') return;
204
- if (!link.href.startsWith('http')) return;
205
-
206
- e.preventDefault();
207
-
208
- const req = this.targetToRequest(link.href, { origin: 'click' });
209
- const routeEq =
210
- this.route && this.route.eqUrl(req) && this.route.eqSearch(req);
211
-
212
- // this means the route is the same maybe with a different hash
213
- // so it is not necessary to load the data again
214
- if (routeEq) {
215
- req.disableLoadData = true;
216
- }
217
-
218
- this.open(req);
219
- });
220
-
221
- if (this.preloadOnMouseOver) {
222
- let currentMouseOver: any = null;
223
- window.addEventListener('mouseover', e => {
224
- // @ts-ignore
225
- const link = e.target.closest('a');
226
-
227
- if (currentMouseOver && link === currentMouseOver) return;
228
- if (link && link.target.toLowerCase() === '_blank') return;
229
-
230
- if (
231
- link &&
232
- !link.hasAttribute('data-no-preload') &&
233
- link.href
234
- ) {
235
- this.preload(link.href);
236
- }
237
-
238
- currentMouseOver = link;
239
- });
240
- }
241
-
242
- // store the scrollY position every 200ms
243
- // we can't do this at the time of the open call since the pop event
244
- // has already changed to a new history state so we can't update our
245
- // current/previous state
246
- // eslint-disable-next-line no-constant-condition
247
- if (true) {
248
- window.addEventListener('scroll', () => {
249
- const current = this.route;
250
- if (!current) return;
251
-
252
- // store the scroll position
253
- current.scrollY = window.scrollY;
254
-
255
- if (this.scrollDebounceTimeout) return;
256
-
257
- // this might cause `Attempt to use history.replaceState() more than
258
- // 100 times per 30 seconds` in safari
259
- // since we wait a moment we should almost ever be fine
260
- this.scrollDebounceTimeout = setTimeout(() => {
261
- if (!this.route || !current.eq(this.route)) return;
262
-
263
- // use the latest state
264
- this.history.replaceState(this.route._toState());
265
-
266
- if (current.inLivePreview()) {
267
- sessionStorage.setItem(
268
- 'live-preview-scroll',
269
- // use the latest scrollY
270
- this.route.scrollY + '',
271
- );
272
- }
273
-
274
- this.scrollDebounceTimeout = null;
275
- }, 280);
276
- });
277
- }
278
-
279
- window.addEventListener('popstate', async e => {
280
- if (!e.state?.route) return;
281
-
282
- const req = this.targetToRequest(window.location.href);
283
- req._fillFromState(e.state);
284
- req.origin = 'pop';
285
-
286
- // we set it now instead of waiting for the onRoute call
287
- // because the window.history was already modified
288
- this.route = req.toRoute();
289
- this.onRoute(req, () => {});
290
- });
291
- }
292
-
293
- /**
294
- * Open a new route
295
- *
296
- * @param route a route object or an url or uri, never input the same route object again
297
- * @param pushState if true pushed the state to the window.history
298
- *
299
- * ## Important
300
- * Make sure a req always has the correct origin,
301
- * `push` and `replace` will cause this function to throw an error
302
- */
303
- open(req: Request) {
304
- if (['push', 'replace'].includes(req.origin)) {
305
- throw new Error('Do not use open with push or replace');
306
- }
307
-
308
- const current = this.route;
309
- // store scrollY
310
- if (current) {
311
- // if the scrollY would still be updated we clear the timeout
312
- // since we should have the latest scrollY
313
- if (this.scrollDebounceTimeout) {
314
- clearTimeout(this.scrollDebounceTimeout);
315
- this.scrollDebounceTimeout = null;
316
- }
317
-
318
- // store the scroll position
319
- const scrollY = this.history.scrollY();
320
- if (typeof scrollY === 'number') {
321
- current.scrollY = scrollY;
322
- this.history.replaceState(current._toState());
323
- }
324
- }
325
-
326
- // if the domain of the current site is different than the domain of the
327
- // new site we need to do a window.location.href call
328
- if (
329
- (current && current.url.origin !== req.url.origin) ||
330
- // @ts-ignore
331
- import.meta.env.SSR
332
- ) {
333
- this.history.open(req);
334
- return;
335
- }
336
-
337
- req.index = (current?.index ?? 0) + 1;
338
- this.onRoute(req, () => {
339
- const url = req.url;
340
- this.history.pushState(
341
- req._toState(),
342
- url.pathname + url.search + url.hash,
343
- );
344
- this.route = req.toRoute();
345
- });
346
- }
347
-
348
- /**
349
- * This pushes a new route to the history
350
- *
351
- * @param req, never input the same route object again
352
- *
353
- * ## Important
354
- * Make sure the route has the correct origin
355
- */
356
- push(req: Request) {
357
- const url = req.url;
358
- // todo a push should also store the previous scrollY
359
-
360
- let nReq = req;
361
- if (req.scrollY === null) {
362
- // if there is no scrollY stored we store the current scrollY
363
- // since a push does not cause a scroll top
364
- // todo: probably should refactor something probably
365
- // should not be here
366
- nReq = req.clone();
367
- nReq.scrollY = this.history.scrollY();
368
- }
369
-
370
- this.onRoute(req, () => {
371
- this.history.pushState(
372
- req._toState(),
373
- url.pathname + url.search + url.hash,
374
- );
375
- this.route = req.toRoute();
376
- });
377
- }
378
-
379
- /**
380
- * This replaces the current route
381
- *
382
- * @param req, never input the same route object again
383
- *
384
- * ## Important
385
- * Make sure the route has the correct origin
386
- */
387
- replace(req: Request) {
388
- const url = req.url;
389
-
390
- let nReq = req;
391
- if (req.scrollY === null) {
392
- // if there is no scrollY stored we store the current scrollY
393
- // since a replace does not cause a scrollTo and we wan't
394
- // history back to work as intended
395
- // todo: probably should refactor something probably
396
- // should not be here
397
- nReq = req.clone();
398
- nReq.scrollY = this.history.scrollY();
399
- }
400
-
401
- this.onRoute(req, () => {
402
- this.history.replaceState(
403
- req._toState(),
404
- url.pathname + url.search + url.hash,
405
- );
406
- this.route = req.toRoute();
407
- });
408
- }
409
-
410
- /**
411
- * Preload a url
412
- *
413
- * This will only work if the origin of the url matches the current site
414
- *
415
- * @param url
416
- */
417
- preload(target: string | URL | Route | Request) {
418
- const req = this.targetToRequest(target);
419
- const current = this.route;
420
-
421
- // if the origin matches, the route will be able to be load
422
- // so let's preload it
423
- if (current && current.url.origin === req.url.origin) {
424
- this.onPreload(req);
425
- }
426
- }
427
-
428
- domReady(req: Request) {
429
- if (req.disableScroll) return;
430
-
431
- // scroll to target
432
- let scrollTo:
433
- | { top: number; behavior: ScrollBehavior }
434
- | { intoView: HTMLElement; behavior: ScrollBehavior }
435
- | null = null;
436
-
437
- // if the route is a live preview init and we have a scrollY stored
438
- // scroll to that
439
- if (req.inLivePreview()) {
440
- const scrollY = sessionStorage.getItem('live-preview-scroll');
441
- if (scrollY) {
442
- scrollTo = {
443
- top: parseInt(scrollY),
444
- behavior: 'instant',
445
- };
446
- }
447
- // if we have a hash and the route was not visited
448
- } else if (
449
- req.hash &&
450
- ((req.origin === 'init' && typeof req.scrollY !== 'number') ||
451
- req.origin === 'click')
452
- ) {
453
- const el = document.getElementById(req.hash.substring(1));
454
- if (el) {
455
- scrollTo = {
456
- intoView: el,
457
- behavior: 'smooth',
458
- };
459
- }
460
- }
461
-
462
- // restore scroll position
463
- if (
464
- !scrollTo &&
465
- req.origin !== 'click' &&
466
- typeof req.scrollY === 'number'
467
- ) {
468
- scrollTo = {
469
- top: req.scrollY,
470
- behavior: 'instant',
471
- };
472
- }
473
-
474
- // make sure push and replace don't cause a scroll if it is not intended
475
- if (!scrollTo && (req.origin === 'push' || req.origin === 'replace'))
476
- return;
477
-
478
- // scroll to the top if nothing else matches
479
- if (!scrollTo) {
480
- scrollTo = {
481
- top: 0,
482
- behavior: 'instant',
483
- };
484
- }
485
-
486
- if ('top' in scrollTo) {
487
- window.scrollTo({
488
- top: scrollTo.top,
489
- behavior: scrollTo.behavior,
490
- });
491
- } else {
492
- scrollTo.intoView.scrollIntoView({
493
- behavior: scrollTo.behavior,
494
- block: 'start',
495
- });
496
- }
497
- }
498
- }