@webjsdev/core 0.7.50 → 0.7.53

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 (64) hide show
  1. package/dist/webjs-core-browser.js +5 -5
  2. package/dist/webjs-core-browser.js.map +3 -3
  3. package/dist/webjs-core-testing.js +20 -20
  4. package/dist/webjs-core-testing.js.map +3 -3
  5. package/dist/webjs-core.js +7 -7
  6. package/dist/webjs-core.js.map +3 -3
  7. package/index-browser.js +1 -1
  8. package/index.d.ts +3 -3
  9. package/index.js +1 -1
  10. package/package.json +1 -1
  11. package/src/component/lifecycle.js +1481 -0
  12. package/src/component/reactive.js +171 -0
  13. package/src/component/server-element.js +248 -0
  14. package/src/component.js +2 -1896
  15. package/src/css.d.ts +9 -0
  16. package/src/escape.d.ts +2 -0
  17. package/src/html.d.ts +9 -0
  18. package/src/render-client/parts.js +2039 -0
  19. package/src/render-client/reconciler.js +388 -0
  20. package/src/render-client/template-compiler.js +525 -0
  21. package/src/render-client.js +1 -2938
  22. package/src/render-server/attrs.js +160 -0
  23. package/src/render-server/dsd.js +445 -0
  24. package/src/render-server/html-scan.js +402 -0
  25. package/src/render-server/slots.js +213 -0
  26. package/src/render-server/stream.js +163 -0
  27. package/src/render-server/template-renderer.js +938 -0
  28. package/src/render-server/text.js +163 -0
  29. package/src/render-server.js +6 -2405
  30. package/src/repeat.d.ts +15 -0
  31. package/src/rich-fetch.d.ts +4 -0
  32. package/src/router-client/anchors.js +44 -0
  33. package/src/router-client/boundaries.js +221 -0
  34. package/src/router-client/constants.js +206 -0
  35. package/src/router-client/diagnostics.js +377 -0
  36. package/src/router-client/dom-differ.js +709 -0
  37. package/src/router-client/dom-parse.js +150 -0
  38. package/src/router-client/events.js +182 -0
  39. package/src/router-client/fetch-apply.js +432 -0
  40. package/src/router-client/form-encoder.js +135 -0
  41. package/src/router-client/frames.js +329 -0
  42. package/src/router-client/head-merge.js +344 -0
  43. package/src/router-client/nav-error.js +105 -0
  44. package/src/router-client/navigator.js +952 -0
  45. package/src/router-client/prefetch.js +831 -0
  46. package/src/router-client/scroll.js +308 -0
  47. package/src/router-client/snapshot-cache.js +113 -0
  48. package/src/router-client/state.js +155 -0
  49. package/src/router-client/stream.js +206 -0
  50. package/src/router-client/swap.js +454 -0
  51. package/src/router-client/upgrade.js +261 -0
  52. package/src/router-client/view-transition.js +223 -0
  53. package/src/router-client.d.ts +11 -2
  54. package/src/router-client.js +78 -5345
  55. package/src/slot/assignment.js +304 -0
  56. package/src/slot/interception.js +558 -0
  57. package/src/slot/polyfills.js +365 -0
  58. package/src/slot/project.js +432 -0
  59. package/src/slot/sensors.js +303 -0
  60. package/src/slot/state.js +245 -0
  61. package/src/slot/symbols.js +85 -0
  62. package/src/slot.js +7 -2199
  63. package/src/suspense.d.ts +9 -0
  64. package/src/websocket-client.d.ts +22 -0
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Client router: nav-error.
3
+ *
4
+ * Moved verbatim out of the pre-split `router-client.js`; that barrel holds
5
+ * the router's full contract and the public entry points.
6
+ *
7
+ * @module
8
+ */
9
+ import { collectBoundaries } from './boundaries.js';
10
+ import { reportFallback } from './diagnostics.js';
11
+ import { hardNavigate } from './state.js';
12
+
13
+ /**
14
+ * Render the minimal default in-place error surface into the deepest
15
+ * shared layout children slot, so the SPA shell (outer chrome, nav,
16
+ * scroll, focus, client state) survives a failed navigation instead of
17
+ * being destroyed by a full reload. Returns true when it rendered into a
18
+ * slot, false when no shared layout marker exists (a cross-document nav).
19
+ * On a false return the caller may fall back to a hard load as a last
20
+ * resort.
21
+ *
22
+ * @param {number | null} status HTTP status of the failed response, or null for a transport/parse failure.
23
+ * @returns {boolean}
24
+ */
25
+ function renderInPlaceNavError(status) {
26
+ if (typeof document === 'undefined' || !document.body) return false;
27
+ const here = collectBoundaries(document.body);
28
+ if (!here) return false; // poisoned live tree: let the caller hard-load
29
+ // The deepest boundary is the same swap target a normal partial swap writes
30
+ // to (longest path wins), so the outer chrome / nav are preserved.
31
+ /** @type {{ start: Comment, end: Comment } | undefined} */
32
+ let deepest;
33
+ let deepestPathLen = -1;
34
+ for (const [path, slot] of here) {
35
+ if (path.length > deepestPathLen) { deepestPathLen = path.length; deepest = slot; }
36
+ }
37
+ if (!deepest) return false;
38
+ const liveParent = deepest.start.parentNode;
39
+ if (!liveParent || deepest.start.parentNode !== deepest.end.parentNode) return false;
40
+
41
+ const alert = document.createElement('div');
42
+ alert.setAttribute('role', 'alert');
43
+ alert.setAttribute('data-webjs-nav-error', '');
44
+ const msg = status
45
+ ? `This page could not be loaded. (status ${status})`
46
+ : 'This page could not be loaded.';
47
+ alert.textContent = msg;
48
+
49
+ // Replace the slot contents with the alert.
50
+ const range = document.createRange();
51
+ range.setStartAfter(deepest.start);
52
+ range.setEndBefore(deepest.end);
53
+ range.deleteContents();
54
+ liveParent.insertBefore(alert, deepest.end);
55
+ return true;
56
+ }
57
+
58
+ /**
59
+ * Shared fallback for a non-HTML error response or a transport/parse
60
+ * failure during a client navigation. Dispatches a cancelable
61
+ * `webjs:navigation-error` event on `document` (matching the
62
+ * `webjs:frame-missing` / `webjs:prefetch` dispatch convention) so the
63
+ * app can recover in place. If the app calls `preventDefault()`, the
64
+ * router does NOTHING further and leaves the current page exactly as it
65
+ * is. Otherwise it renders a minimal in-place `role="alert"` surface into
66
+ * the deepest layout children slot (the SPA shell survives), and only
67
+ * hard-navigates as a last resort when no in-place target exists.
68
+ *
69
+ * Never call this for an AbortError: a superseding nav is a normal
70
+ * supersede, not an error, and must not surface a navigation-error.
71
+ *
72
+ * @param {string} href The URL that failed to navigate to.
73
+ * @param {number | null} status HTTP status when a response arrived, else null.
74
+ * @param {Error | null} error The Error for a transport/parse failure, else null.
75
+ */
76
+ export function handleNavigationError(href, status, error) {
77
+ const evt = new CustomEvent('webjs:navigation-error', {
78
+ bubbles: true,
79
+ cancelable: true,
80
+ detail: { url: href, status: status == null ? null : status, error: error || null },
81
+ });
82
+ // Guard the dispatch: a throwing app listener must not wedge the nav engine.
83
+ if (typeof document !== 'undefined') {
84
+ try { document.dispatchEvent(evt); } catch { /* a buggy listener cannot break recovery */ }
85
+ }
86
+ // The app owns recovery: leave the page untouched (shell, scroll, focus,
87
+ // client state all preserved). No reload, no render.
88
+ if (evt.defaultPrevented) return;
89
+ // Default: render a minimal in-place error surface so the SPA is not
90
+ // destroyed and the user is not sent to a second failing round-trip.
91
+ if (renderInPlaceNavError(status)) return;
92
+ // Last resort only: no shared layout marker to render into (a genuine
93
+ // cross-document nav). Fall back to a hard load so an unrecoverable case
94
+ // is not a silent dead-end. This is the exception, reached only after
95
+ // the event was not cancelled AND no in-place target exists.
96
+ //
97
+ // Report it like every other degradation (#1114): this IS a click turning
98
+ // into a document load, so an app watching `webjs:navigation-fallback` to
99
+ // count full loads must see it. The preceding `webjs:navigation-error`
100
+ // carries no `cause` / `willReload`, so it is not a substitute.
101
+ if (typeof location !== 'undefined') {
102
+ reportFallback('navigation-error-unrecoverable', href);
103
+ hardNavigate(href);
104
+ }
105
+ }