@uniweb/runtime 0.8.11 → 0.8.14

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/runtime",
3
- "version": "0.8.11",
3
+ "version": "0.8.14",
4
4
  "description": "Minimal runtime for loading Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
@@ -35,14 +35,14 @@
35
35
  "node": ">=20.19"
36
36
  },
37
37
  "dependencies": {
38
- "@uniweb/core": "0.7.10",
39
- "@uniweb/theming": "0.1.3"
38
+ "@uniweb/theming": "0.1.3",
39
+ "@uniweb/core": "0.7.11"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@vitejs/plugin-react": "^4.5.2",
43
43
  "vite": "^7.3.1",
44
44
  "vitest": "^2.0.0",
45
- "@uniweb/build": "0.13.3"
45
+ "@uniweb/build": "0.14.4"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "react": "^18.0.0 || ^19.0.0",
@@ -5,6 +5,27 @@
5
5
  * with CSS loading in parallel.
6
6
  */
7
7
 
8
+ /**
9
+ * Resolve a foundation/extension URL so that absolute-path forms
10
+ * (`/_module/...`) anchor to the document's origin, not to the importing
11
+ * runtime's host. Pass-through for fully-absolute (https://...) and
12
+ * already-protocol-relative inputs; pass-through if there's no document
13
+ * (SSR contexts).
14
+ */
15
+ function resolveAgainstDocument(url) {
16
+ if (typeof url !== 'string' || !url) return url
17
+ if (typeof window === 'undefined' || !window.location) return url
18
+ // Already absolute (https://, http://, //)
19
+ if (/^([a-z][a-z0-9+.-]*:)?\/\//i.test(url)) return url
20
+ // Host-absolute path (/foo) — anchor to document origin so an
21
+ // import from a CDN-loaded runtime doesn't pull from the CDN host.
22
+ if (url.startsWith('/')) return window.location.origin + url
23
+ // Relative paths (foo, ./foo, ../foo) keep their natural ES-module
24
+ // resolution (against the importer). Foundations don't use this
25
+ // form today; passing through preserves any future caller's intent.
26
+ return url
27
+ }
28
+
8
29
  /**
9
30
  * Load foundation CSS from URL
10
31
  * @param {string} url - URL to foundation's CSS file
@@ -37,10 +58,22 @@ async function loadFoundationCSS(url) {
37
58
  * @returns {Promise<Object>} The loaded foundation module
38
59
  */
39
60
  export async function loadFoundation(source) {
40
- const url = typeof source === 'string' ? source : source.url
41
- // Auto-derive CSS URL from JS URL by convention: foundation.js → assets/foundation.css
42
- const cssUrl = typeof source === 'object' ? source.cssUrl
43
- : url.replace(/[^/]+\.js$/, 'assets/foundation.css')
61
+ const rawUrl = typeof source === 'string' ? source : source.url
62
+ // Auto-derive CSS URL from JS URL by convention: entry.js → assets/style.css.
63
+ // Pre-Phase-5 foundations were named foundation.js + assets/foundation.css;
64
+ // those keep working when an explicit `cssUrl` is passed in `source`.
65
+ const rawCssUrl = typeof source === 'object' ? source.cssUrl
66
+ : rawUrl.replace(/[^/]+\.js$/, 'assets/style.css')
67
+
68
+ // Phase 5: when the runtime is loaded from a different host than the
69
+ // document (e.g. runtime served from cdn.uniweb.app, page on
70
+ // www.uniweb.io), ES-module dynamic imports resolve relative paths
71
+ // against the IMPORTING script's URL — not the document's. Site-bound
72
+ // foundation URLs like `/_module/io/0.1.2/entry.js` would resolve to
73
+ // cdn.uniweb.app/_module/... and 404. Force resolution against the
74
+ // document origin so site-bound paths land on the site host.
75
+ const url = resolveAgainstDocument(rawUrl)
76
+ const cssUrl = rawCssUrl ? resolveAgainstDocument(rawCssUrl) : rawCssUrl
44
77
 
45
78
  console.log(`[Runtime] Loading foundation from: ${url}`)
46
79
 
@@ -144,6 +144,9 @@ export function useLinkInterceptor(options = {}) {
144
144
  // Check for download attribute
145
145
  if (anchor.hasAttribute('download')) return
146
146
 
147
+ // Opt out: anchors marked for full-page reload (e.g., <Link reload>)
148
+ if (anchor.hasAttribute('data-reload')) return
149
+
147
150
  // Check for target="_blank" or other non-self targets
148
151
  const target = anchor.getAttribute('target')
149
152
  if (target && target !== '_self') return