@tyndall/core 0.0.1 → 0.0.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.
@@ -1,59 +1,111 @@
1
+ import { ROUTE_DATA_SCRIPT_ID } from "./route-data.js";
1
2
  export const CLIENT_ROUTER_BOOTSTRAP_PATH = "/_hyper/client-bootstrap.js";
2
3
  export const renderClientRouterBootstrap = (options) => {
3
4
  const navigationMode = JSON.stringify(options.navigationMode);
4
5
  const clientRenderMode = JSON.stringify(options.clientRenderMode);
5
6
  const prefetchPath = JSON.stringify(options.prefetchPath ?? "/__hyper/prefetch");
6
7
  const linkInterceptionMode = JSON.stringify(options.linkInterceptionMode ?? "marked");
7
- return `(() => {
8
- if (typeof window === "undefined") return;
9
- if (window.__HYPER_CLIENT_BOOTSTRAP__) return;
8
+ const scrollRestoration = JSON.stringify(options.scrollRestoration !== false);
9
+ const routeDataScriptId = JSON.stringify(ROUTE_DATA_SCRIPT_ID);
10
+ return `(function () {
11
+ if (typeof window === "undefined") { return; }
12
+ if (window.__HYPER_CLIENT_BOOTSTRAP__) { return; }
10
13
  window.__HYPER_CLIENT_BOOTSTRAP__ = true;
11
14
 
12
- const navigationMode = ${navigationMode};
13
- const clientRenderMode = ${clientRenderMode};
14
- const prefetchPath = ${prefetchPath};
15
- const linkInterceptionMode = ${linkInterceptionMode};
15
+ var navigationMode = ${navigationMode};
16
+ var clientRenderMode = ${clientRenderMode};
17
+ var prefetchPath = ${prefetchPath};
18
+ var linkInterceptionMode = ${linkInterceptionMode};
19
+ var scrollRestoration = ${scrollRestoration};
20
+ var ROUTE_DATA_SCRIPT_ID = ${routeDataScriptId};
16
21
 
17
22
  if (navigationMode !== "client") {
18
23
  return;
19
24
  }
20
25
 
21
- const NAVIGATION_HEADER = "x-hyper-navigation";
22
- const NAVIGATION_MODE = "csr";
23
- const MANAGED_HEAD_ATTR = "data-hyper-head";
24
- const ROUTE_PAYLOAD_EVENT = "hyper:route-payload-applied";
26
+ var NAVIGATION_HEADER = "x-hyper-navigation";
27
+ var NAVIGATION_MODE = "csr";
28
+ var MANAGED_HEAD_ATTR = "data-hyper-head";
29
+ var ROUTE_PAYLOAD_EVENT = "hyper:route-payload-applied";
30
+ var ROUTE_DATA_EVENT = "hyper:route-data-applied";
31
+ var ROUTE_REDIRECT_KIND = "hyper-route-redirect";
25
32
 
26
- const isRecord = (value) =>
27
- typeof value === "object" && value !== null && !Array.isArray(value);
33
+ var isRecord = function (value) {
34
+ return typeof value === "object" && value !== null && !Array.isArray(value);
35
+ };
36
+
37
+ var parseJsonPayload = function (value) {
38
+ if (typeof value !== "string" || value.length === 0) {
39
+ return {};
40
+ }
41
+ try {
42
+ return JSON.parse(value);
43
+ } catch (error) {
44
+ return {};
45
+ }
46
+ };
47
+
48
+ var resolveNavigationGuard = function () {
49
+ var guard = window.__HYPER_NAVIGATION_GUARD__;
50
+ return typeof guard === "function" ? guard : null;
51
+ };
52
+
53
+ var shouldAllowNavigation = function (href, replace, type) {
54
+ var guard = resolveNavigationGuard();
55
+ if (!guard) {
56
+ return true;
57
+ }
58
+ try {
59
+ return guard({ href: href, replace: Boolean(replace), type: type });
60
+ } catch (error) {
61
+ return true;
62
+ }
63
+ };
28
64
 
29
- const findAnchor = (target) => {
30
- if (!target || typeof target.closest !== "function") {
65
+ var findAnchor = function (target) {
66
+ if (!target) {
31
67
  return null;
32
68
  }
33
- return target.closest("a[href]");
69
+ if (typeof target.closest === "function") {
70
+ return target.closest("a[href]");
71
+ }
72
+ var node = target;
73
+ while (node && node.nodeType === 1) {
74
+ if (
75
+ node.tagName &&
76
+ node.tagName.toLowerCase() === "a" &&
77
+ node.getAttribute &&
78
+ node.getAttribute("href")
79
+ ) {
80
+ return node;
81
+ }
82
+ node = node.parentNode;
83
+ }
84
+ return null;
34
85
  };
35
86
 
36
- const isModifiedClick = (event) =>
37
- event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
87
+ var isModifiedClick = function (event) {
88
+ return event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
89
+ };
38
90
 
39
- const shouldInterceptAnchor = (anchor) => {
40
- if (!anchor) return false;
41
- if (anchor.getAttribute("data-hyper-link") === "false") return false;
42
- if (linkInterceptionMode === "all") return true;
91
+ var shouldInterceptAnchor = function (anchor) {
92
+ if (!anchor) { return false; }
93
+ if (anchor.getAttribute("data-hyper-link") === "false") { return false; }
94
+ if (linkInterceptionMode === "all") { return true; }
43
95
  return anchor.hasAttribute("data-hyper-link");
44
96
  };
45
97
 
46
- const canHandleAnchor = (anchor, event) => {
47
- if (!anchor) return false;
48
- if (event && event.button !== 0) return false;
49
- if (event && isModifiedClick(event)) return false;
50
- if (anchor.hasAttribute("download")) return false;
51
- if (anchor.getAttribute("target")) return false;
52
- if (anchor.getAttribute("rel") === "external") return false;
53
- if (!shouldInterceptAnchor(anchor)) return false;
54
-
55
- const url = new URL(anchor.href, window.location.href);
56
- if (url.origin !== window.location.origin) return false;
98
+ var canHandleAnchor = function (anchor, event) {
99
+ if (!anchor) { return false; }
100
+ if (event && event.button !== 0) { return false; }
101
+ if (event && isModifiedClick(event)) { return false; }
102
+ if (anchor.hasAttribute("download")) { return false; }
103
+ if (anchor.getAttribute("target")) { return false; }
104
+ if (anchor.getAttribute("rel") === "external") { return false; }
105
+ if (!shouldInterceptAnchor(anchor)) { return false; }
106
+
107
+ var url = new URL(anchor.href, window.location.href);
108
+ if (url.origin !== window.location.origin) { return false; }
57
109
  if (
58
110
  url.hash &&
59
111
  url.pathname === window.location.pathname &&
@@ -64,45 +116,137 @@ export const renderClientRouterBootstrap = (options) => {
64
116
  return true;
65
117
  };
66
118
 
67
- const removeManagedHead = () => {
68
- const managed = document.head.querySelectorAll("[" + MANAGED_HEAD_ATTR + "]");
69
- for (const node of managed) {
70
- node.remove();
119
+ var scrollPositions =
120
+ window.__HYPER_SCROLL_POSITIONS__ && typeof window.__HYPER_SCROLL_POSITIONS__ === "object"
121
+ ? window.__HYPER_SCROLL_POSITIONS__
122
+ : {};
123
+ window.__HYPER_SCROLL_POSITIONS__ = scrollPositions;
124
+
125
+ var toScrollKey = function (url) {
126
+ return url.pathname + url.search;
127
+ };
128
+
129
+ var saveScrollPosition = function (href) {
130
+ if (!scrollRestoration) { return; }
131
+ if (!href || typeof href !== "string") { return; }
132
+ try {
133
+ var url = new URL(href, window.location.href);
134
+ var key = toScrollKey(url);
135
+ scrollPositions[key] = {
136
+ x: window.scrollX || window.pageXOffset || 0,
137
+ y: window.scrollY || window.pageYOffset || 0
138
+ };
139
+ } catch (error) {
140
+ // Ignore malformed hrefs for scroll tracking.
71
141
  }
72
142
  };
73
143
 
74
- const appendHeadNode = (tagName, attrs) => {
75
- const node = document.createElement(tagName);
76
- for (const [key, value] of Object.entries(attrs)) {
77
- if (value === undefined || value === null) continue;
144
+ var scrollToHash = function (url) {
145
+ if (!url.hash) { return false; }
146
+ var id = url.hash.slice(1);
147
+ if (!id) { return false; }
148
+ var node = document.getElementById(id);
149
+ if (node && typeof node.scrollIntoView === "function") {
150
+ node.scrollIntoView();
151
+ return true;
152
+ }
153
+ return false;
154
+ };
155
+
156
+ var restoreScrollPosition = function (url, fromHistory) {
157
+ if (!scrollRestoration) { return; }
158
+ if (scrollToHash(url)) {
159
+ return;
160
+ }
161
+ var key = toScrollKey(url);
162
+ if (fromHistory && scrollPositions[key]) {
163
+ var position = scrollPositions[key];
164
+ if (position && typeof position === "object") {
165
+ var x = typeof position.x === "number" ? position.x : 0;
166
+ var y = typeof position.y === "number" ? position.y : 0;
167
+ window.scrollTo(x, y);
168
+ return;
169
+ }
170
+ }
171
+ window.scrollTo(0, 0);
172
+ };
173
+
174
+ if (scrollRestoration && window.history && "scrollRestoration" in window.history) {
175
+ try {
176
+ window.history.scrollRestoration = "manual";
177
+ } catch (error) {
178
+ // Ignore environments that block scrollRestoration assignment.
179
+ }
180
+ }
181
+
182
+ var currentHref = window.location.href;
183
+ var initialRouteDataScript = document.getElementById(ROUTE_DATA_SCRIPT_ID);
184
+ if (initialRouteDataScript && !window.__HYPER_ROUTE_DATA__) {
185
+ window.__HYPER_ROUTE_DATA__ = parseJsonPayload(initialRouteDataScript.textContent);
186
+ }
187
+
188
+ var removeManagedHead = function () {
189
+ if (!document.head) {
190
+ return;
191
+ }
192
+ var managed = document.head.querySelectorAll("[" + MANAGED_HEAD_ATTR + "]");
193
+ for (var index = 0; index < managed.length; index += 1) {
194
+ var node = managed[index];
195
+ if (!node) {
196
+ continue;
197
+ }
198
+ if (typeof node.remove === "function") {
199
+ node.remove();
200
+ } else if (node.parentNode) {
201
+ node.parentNode.removeChild(node);
202
+ }
203
+ }
204
+ };
205
+
206
+ var appendHeadNode = function (tagName, attrs) {
207
+ if (!document.head) {
208
+ return;
209
+ }
210
+ var node = document.createElement(tagName);
211
+ for (var key in attrs) {
212
+ if (!Object.prototype.hasOwnProperty.call(attrs, key)) {
213
+ continue;
214
+ }
215
+ var value = attrs[key];
216
+ if (value === undefined || value === null) {
217
+ continue;
218
+ }
78
219
  node.setAttribute(key, String(value));
79
220
  }
80
221
  node.setAttribute(MANAGED_HEAD_ATTR, "true");
81
222
  document.head.appendChild(node);
82
223
  };
83
224
 
84
- const applyHead = (head) => {
85
- if (!isRecord(head)) return;
225
+ var applyHead = function (head) {
226
+ if (!isRecord(head)) { return; }
86
227
  if (typeof head.title === "string") {
87
228
  document.title = head.title;
88
229
  }
89
230
  removeManagedHead();
90
231
  if (Array.isArray(head.meta)) {
91
- for (const meta of head.meta) {
232
+ for (var index = 0; index < head.meta.length; index += 1) {
233
+ var meta = head.meta[index];
92
234
  if (isRecord(meta)) {
93
235
  appendHeadNode("meta", meta);
94
236
  }
95
237
  }
96
238
  }
97
239
  if (Array.isArray(head.link)) {
98
- for (const link of head.link) {
240
+ for (var linkIndex = 0; linkIndex < head.link.length; linkIndex += 1) {
241
+ var link = head.link[linkIndex];
99
242
  if (isRecord(link)) {
100
243
  appendHeadNode("link", link);
101
244
  }
102
245
  }
103
246
  }
104
247
  if (Array.isArray(head.script)) {
105
- for (const script of head.script) {
248
+ for (var scriptIndex = 0; scriptIndex < head.script.length; scriptIndex += 1) {
249
+ var script = head.script[scriptIndex];
106
250
  if (isRecord(script)) {
107
251
  appendHeadNode("script", script);
108
252
  }
@@ -110,18 +254,52 @@ export const renderClientRouterBootstrap = (options) => {
110
254
  }
111
255
  };
112
256
 
113
- const isRoutePayload = (value) => {
114
- if (!isRecord(value)) return false;
115
- if (value.kind !== "hyper-route-payload") return false;
116
- if (typeof value.routeId !== "string") return false;
117
- if (typeof value.appHtml !== "string") return false;
118
- if (typeof value.propsPayload !== "string") return false;
257
+ var isRoutePayload = function (value) {
258
+ if (!isRecord(value)) { return false; }
259
+ if (value.kind !== "hyper-route-payload") { return false; }
260
+ if (typeof value.routeId !== "string") { return false; }
261
+ if (typeof value.appHtml !== "string") { return false; }
262
+ if (typeof value.propsPayload !== "string") { return false; }
263
+ if (
264
+ value.routeDataPayload !== undefined &&
265
+ value.routeDataPayload !== null &&
266
+ typeof value.routeDataPayload !== "string"
267
+ ) {
268
+ return false;
269
+ }
119
270
  return true;
120
271
  };
121
272
 
122
- const applyPayload = (payload) => {
123
- const app = document.getElementById("app");
124
- const hasMountedClientApp =
273
+ var isRouteRedirect = function (value) {
274
+ if (!isRecord(value)) { return false; }
275
+ if (value.kind !== ROUTE_REDIRECT_KIND) { return false; }
276
+ if (typeof value.destination !== "string") { return false; }
277
+ return true;
278
+ };
279
+
280
+ var applyRouteDataPayload = function (payload, routeId) {
281
+ var routeDataPayload =
282
+ typeof payload.routeDataPayload === "string" ? payload.routeDataPayload : "{}";
283
+ var routeDataScript = document.getElementById(ROUTE_DATA_SCRIPT_ID);
284
+ if (routeDataScript) {
285
+ routeDataScript.textContent = routeDataPayload;
286
+ }
287
+ var routeData = parseJsonPayload(routeDataPayload);
288
+ window.__HYPER_ROUTE_DATA__ = routeData;
289
+ try {
290
+ window.dispatchEvent(
291
+ new CustomEvent(ROUTE_DATA_EVENT, {
292
+ detail: { routeId: routeId, routeData: routeData }
293
+ })
294
+ );
295
+ } catch (error) {
296
+ // Keep navigation resilient even when CustomEvent is unavailable.
297
+ }
298
+ };
299
+
300
+ var applyPayload = function (payload) {
301
+ var app = document.getElementById("app");
302
+ var hasMountedClientApp =
125
303
  payload.hydration !== "islands" && Boolean(window.__HYPER_CLIENT_APP_MOUNTED__);
126
304
  if (app) {
127
305
  if (!hasMountedClientApp) {
@@ -139,11 +317,12 @@ export const renderClientRouterBootstrap = (options) => {
139
317
  }
140
318
  }
141
319
 
142
- const propsScript = document.getElementById("__HYPER_PROPS__");
320
+ var propsScript = document.getElementById("__HYPER_PROPS__");
143
321
  if (propsScript) {
144
322
  propsScript.textContent = payload.propsPayload;
145
323
  }
146
324
 
325
+ applyRouteDataPayload(payload, payload.routeId);
147
326
  applyHead(payload.head);
148
327
  window.__HYPER_ROUTE_ID__ = payload.routeId;
149
328
  window.__HYPER_HYDRATED__ = false;
@@ -151,77 +330,105 @@ export const renderClientRouterBootstrap = (options) => {
151
330
  try {
152
331
  window.dispatchEvent(
153
332
  new CustomEvent(ROUTE_PAYLOAD_EVENT, {
154
- detail: { routeId: payload.routeId },
155
- }),
333
+ detail: { routeId: payload.routeId }
334
+ })
156
335
  );
157
- } catch {
336
+ } catch (error) {
158
337
  // Keep navigation resilient even when CustomEvent is unavailable.
159
338
  }
160
339
  };
161
340
 
162
- const resolveModuleMap = () => {
163
- const raw = window.__HYPER_CLIENT_ROUTE_MODULES__;
341
+ var resolveModuleMap = function () {
342
+ var raw = window.__HYPER_CLIENT_ROUTE_MODULES__;
164
343
  return isRecord(raw) ? raw : null;
165
344
  };
166
345
 
167
- const tryModuleRender = async (url) => {
168
- if (clientRenderMode !== "module") return false;
169
- const moduleMap = resolveModuleMap();
170
- if (!moduleMap) return false;
171
- const loader = moduleMap[url.pathname];
172
- if (typeof loader !== "function") return false;
346
+ var tryModuleRender = function (url) {
347
+ if (clientRenderMode !== "module") { return Promise.resolve(false); }
348
+ var moduleMap = resolveModuleMap();
349
+ if (!moduleMap) { return Promise.resolve(false); }
350
+ var loader = moduleMap[url.pathname];
351
+ if (typeof loader !== "function") { return Promise.resolve(false); }
173
352
  try {
174
- const loaded = await loader();
175
- const renderFn =
176
- (isRecord(loaded) && typeof loaded.render === "function" && loaded.render) ||
177
- (isRecord(loaded) && typeof loaded.default === "function" && loaded.default) ||
178
- (typeof loaded === "function" && loaded);
179
- if (typeof renderFn !== "function") return false;
180
- const rendered = await renderFn({
181
- href: url.toString(),
182
- pathname: url.pathname,
183
- routeId: url.pathname,
184
- params: {},
185
- query: {},
186
- });
187
- if (!isRecord(rendered) || typeof rendered.appHtml !== "string") {
188
- return false;
189
- }
190
- applyPayload({
191
- kind: "hyper-route-payload",
192
- routeId: typeof rendered.routeId === "string" ? rendered.routeId : url.pathname,
193
- appHtml: rendered.appHtml,
194
- propsPayload:
195
- typeof rendered.propsPayload === "string" ? rendered.propsPayload : "{}",
196
- head: rendered.head,
197
- hydration: rendered.hydration,
198
- });
199
- return true;
200
- } catch {
201
- return false;
353
+ return Promise.resolve(loader())
354
+ .then(function (loaded) {
355
+ var renderFn =
356
+ (isRecord(loaded) && typeof loaded.render === "function" && loaded.render) ||
357
+ (isRecord(loaded) && typeof loaded.default === "function" && loaded.default) ||
358
+ (typeof loaded === "function" && loaded);
359
+ if (typeof renderFn !== "function") { return false; }
360
+ return Promise.resolve(renderFn({
361
+ href: url.toString(),
362
+ pathname: url.pathname,
363
+ routeId: url.pathname,
364
+ params: {},
365
+ query: {}
366
+ })).then(function (rendered) {
367
+ if (!isRecord(rendered) || typeof rendered.appHtml !== "string") {
368
+ return false;
369
+ }
370
+ var routeDataPayload = "{}";
371
+ if (typeof rendered.routeDataPayload === "string") {
372
+ routeDataPayload = rendered.routeDataPayload;
373
+ } else if (isRecord(rendered.routeData)) {
374
+ try {
375
+ routeDataPayload = JSON.stringify(rendered.routeData);
376
+ } catch (error) {
377
+ routeDataPayload = "{}";
378
+ }
379
+ }
380
+ applyPayload({
381
+ kind: "hyper-route-payload",
382
+ routeId: typeof rendered.routeId === "string" ? rendered.routeId : url.pathname,
383
+ appHtml: rendered.appHtml,
384
+ propsPayload:
385
+ typeof rendered.propsPayload === "string" ? rendered.propsPayload : "{}",
386
+ routeDataPayload: routeDataPayload,
387
+ head: rendered.head,
388
+ hydration: rendered.hydration
389
+ });
390
+ return true;
391
+ });
392
+ })
393
+ .catch(function () {
394
+ return false;
395
+ });
396
+ } catch (error) {
397
+ return Promise.resolve(false);
202
398
  }
203
399
  };
204
400
 
205
- const fetchPayload = async (url) => {
401
+ var fetchPayload = function (url) {
206
402
  try {
207
- const response = await fetch(url.toString(), {
403
+ var headers = { accept: "application/json" };
404
+ headers[NAVIGATION_HEADER] = NAVIGATION_MODE;
405
+ return fetch(url.toString(), {
208
406
  method: "GET",
209
- headers: {
210
- [NAVIGATION_HEADER]: NAVIGATION_MODE,
211
- accept: "application/json",
212
- },
213
- });
214
- if (!response.ok) return null;
215
- const contentType = response.headers.get("content-type") || "";
216
- if (!contentType.includes("application/json")) return null;
217
- const json = await response.json();
218
- return isRoutePayload(json) ? json : null;
219
- } catch {
220
- return null;
407
+ headers: headers
408
+ })
409
+ .then(function (response) {
410
+ if (!response || !response.ok) { return null; }
411
+ var contentType = response.headers.get("content-type") || "";
412
+ if (contentType.indexOf("application/json") === -1) { return null; }
413
+ return response.json().then(function (json) {
414
+ if (isRoutePayload(json)) {
415
+ return { kind: "payload", payload: json };
416
+ }
417
+ if (isRouteRedirect(json)) {
418
+ return { kind: "redirect", payload: json };
419
+ }
420
+ return null;
421
+ });
422
+ })
423
+ .catch(function () {
424
+ return null;
425
+ });
426
+ } catch (error) {
427
+ return Promise.resolve(null);
221
428
  }
222
429
  };
223
430
 
224
- const updateHistory = (url, replace) => {
431
+ var updateHistory = function (url, replace) {
225
432
  if (replace) {
226
433
  window.history.replaceState(null, "", url.toString());
227
434
  return;
@@ -229,8 +436,8 @@ export const renderClientRouterBootstrap = (options) => {
229
436
  window.history.pushState(null, "", url.toString());
230
437
  };
231
438
 
232
- const navigateByUrl = (url, replace) => {
233
- const href = url.toString();
439
+ var navigateByUrl = function (url, replace) {
440
+ var href = url.toString();
234
441
  if (replace) {
235
442
  window.location.replace(href);
236
443
  return;
@@ -238,81 +445,147 @@ export const renderClientRouterBootstrap = (options) => {
238
445
  window.location.assign(href);
239
446
  };
240
447
 
241
- const navigate = async (href, options = {}) => {
242
- const url = new URL(href, window.location.href);
243
- if (await tryModuleRender(url)) {
244
- if (!options.skipHistory) {
245
- updateHistory(url, Boolean(options.replace));
246
- }
247
- return true;
448
+ var navigate = function (href, options) {
449
+ options = options || {};
450
+ var url;
451
+ try {
452
+ url = new URL(href, window.location.href);
453
+ } catch (error) {
454
+ return Promise.resolve(false);
248
455
  }
249
- const payload = await fetchPayload(url);
250
- if (payload) {
251
- applyPayload(payload);
252
- if (!options.skipHistory) {
253
- updateHistory(url, Boolean(options.replace));
254
- }
255
- return true;
456
+ if (!shouldAllowNavigation(url.toString(), Boolean(options.replace), options.type || "navigate")) {
457
+ return Promise.resolve(false);
256
458
  }
257
- if (!options.disableUrlFallback) {
258
- navigateByUrl(url, Boolean(options.replace));
459
+ if (!options.skipScrollSave) {
460
+ saveScrollPosition(currentHref);
259
461
  }
260
- return false;
462
+ return tryModuleRender(url).then(function (handled) {
463
+ if (handled) {
464
+ if (!options.skipHistory) {
465
+ updateHistory(url, Boolean(options.replace));
466
+ }
467
+ currentHref = url.toString();
468
+ if (!options.skipScrollRestore) {
469
+ restoreScrollPosition(url, Boolean(options.fromHistory));
470
+ }
471
+ return true;
472
+ }
473
+ return fetchPayload(url).then(function (payload) {
474
+ if (payload && payload.kind === "redirect") {
475
+ var destination = payload.payload.destination;
476
+ if (destination) {
477
+ return navigate(destination, {
478
+ replace: Boolean(payload.payload.replace),
479
+ skipHistory: false,
480
+ disableUrlFallback: false,
481
+ skipScrollSave: true,
482
+ type: "redirect"
483
+ });
484
+ }
485
+ }
486
+ if (payload && payload.kind === "payload") {
487
+ applyPayload(payload.payload);
488
+ if (!options.skipHistory) {
489
+ updateHistory(url, Boolean(options.replace));
490
+ }
491
+ currentHref = url.toString();
492
+ if (!options.skipScrollRestore) {
493
+ restoreScrollPosition(url, Boolean(options.fromHistory));
494
+ }
495
+ return true;
496
+ }
497
+ if (!options.disableUrlFallback) {
498
+ navigateByUrl(url, Boolean(options.replace));
499
+ }
500
+ return false;
501
+ });
502
+ });
503
+ };
504
+
505
+ var softReload = function () {
506
+ return navigate(window.location.href, {
507
+ replace: true,
508
+ skipHistory: true,
509
+ disableUrlFallback: true,
510
+ skipScrollSave: true,
511
+ skipScrollRestore: true,
512
+ type: "softReload"
513
+ }).then(function (ok) {
514
+ if (!ok && typeof window.location.reload === "function") {
515
+ window.location.reload();
516
+ }
517
+ return ok;
518
+ });
261
519
  };
262
520
 
263
- const prefetch = async (href) => {
521
+ window.__HYPER_SOFT_RELOAD__ = softReload;
522
+
523
+ var prefetch = function (href) {
264
524
  try {
265
- const url = new URL(href, window.location.href);
266
- const prefetchUrl = new URL(prefetchPath, window.location.origin);
525
+ var url = new URL(href, window.location.href);
526
+ var prefetchUrl = new URL(prefetchPath, window.location.origin);
267
527
  prefetchUrl.searchParams.set("path", url.pathname + url.search);
268
- await fetch(prefetchUrl.toString(), { method: "POST" });
269
- } catch {
528
+ return fetch(prefetchUrl.toString(), { method: "POST" }).catch(function () {});
529
+ } catch (error) {
270
530
  // Best-effort prefetch only.
271
531
  }
532
+ return Promise.resolve();
272
533
  };
273
534
 
274
535
  document.addEventListener(
275
536
  "click",
276
- (event) => {
277
- const anchor = findAnchor(event.target);
537
+ function (event) {
538
+ var anchor = findAnchor(event.target);
278
539
  if (!canHandleAnchor(anchor, event)) {
279
540
  return;
280
541
  }
281
- event.preventDefault();
282
- void navigate(anchor.href);
542
+ if (event.preventDefault) {
543
+ event.preventDefault();
544
+ } else {
545
+ event.returnValue = false;
546
+ }
547
+ navigate(anchor.href, { type: "click" });
283
548
  },
284
- true,
549
+ true
285
550
  );
286
551
 
287
552
  document.addEventListener(
288
553
  "mouseover",
289
- (event) => {
290
- const anchor = findAnchor(event.target);
554
+ function (event) {
555
+ var anchor = findAnchor(event.target);
291
556
  if (!anchor || !shouldInterceptAnchor(anchor)) {
292
557
  return;
293
558
  }
294
- void prefetch(anchor.href);
559
+ prefetch(anchor.href);
295
560
  },
296
- true,
561
+ true
297
562
  );
298
563
 
299
564
  document.addEventListener(
300
565
  "focusin",
301
- (event) => {
302
- const anchor = findAnchor(event.target);
566
+ function (event) {
567
+ var anchor = findAnchor(event.target);
303
568
  if (!anchor || !shouldInterceptAnchor(anchor)) {
304
569
  return;
305
570
  }
306
- void prefetch(anchor.href);
571
+ prefetch(anchor.href);
307
572
  },
308
- true,
573
+ true
309
574
  );
310
575
 
311
- window.addEventListener("popstate", () => {
312
- void navigate(window.location.href, {
576
+ window.addEventListener("popstate", function () {
577
+ var previousHref = currentHref;
578
+ var nextHref = window.location.href;
579
+ if (previousHref && previousHref !== nextHref) {
580
+ saveScrollPosition(previousHref);
581
+ }
582
+ navigate(nextHref, {
313
583
  replace: true,
314
584
  skipHistory: true,
315
585
  disableUrlFallback: false,
586
+ fromHistory: true,
587
+ skipScrollSave: true,
588
+ type: "popstate"
316
589
  });
317
590
  });
318
591
  })();`;