tina4js 1.0.2 → 1.0.4
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/dist/index.cjs.js +1 -1
- package/dist/index.es.js +13 -13
- package/package.json +1 -1
- package/readme.md +7 -0
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const y=require("./signal.cjs.js");let p=[],a=null,
|
|
1
|
+
"use strict";const y=require("./signal.cjs.js");let p=[],a=null,u="history";const c=[];let l=[],w=0;function R(t,e){const r=[];let n;t==="*"?n=".*":n=t.replace(/\{(\w+)\}/g,(f,i)=>(r.push(i),"([^/]+)"));const s=new RegExp(`^${n}$`);typeof e=="function"?p.push({pattern:t,regex:s,paramNames:r,handler:e}):p.push({pattern:t,regex:s,paramNames:r,handler:e.handler,guard:e.guard})}function v(t,e){if(u==="hash")if(e!=null&&e.replace){const r=new URL(location.href);r.hash="#"+t,history.replaceState(null,"",r.toString()),d()}else location.hash="#"+t;else e!=null&&e.replace?history.replaceState(null,"",t):history.pushState(null,"",t),d()}function d(){if(!a)return;const t=performance.now(),e=++w,r=u==="hash"?location.hash.slice(1)||"/":location.pathname;for(const n of p){const s=r.match(n.regex);if(!s)continue;const f={};if(n.paramNames.forEach((o,h)=>{f[o]=decodeURIComponent(s[h+1])}),n.guard){const o=n.guard();if(o===!1)return;if(typeof o=="string"){v(o,{replace:!0});return}}for(const o of l)o();l=[],a.innerHTML="";const i=[];y._setEffectCollector(i);const g=n.handler(f);if(g instanceof Promise)g.then(o=>{if(y._setEffectCollector(null),e!==w){for(const m of i)m();return}E(a,o),l=i;const h=performance.now()-t;for(const m of c)m({path:r,params:f,pattern:n.pattern,durationMs:h})});else{y._setEffectCollector(null),E(a,g),l=i;const o=performance.now()-t;for(const h of c)h({path:r,params:f,pattern:n.pattern,durationMs:o})}return}}function E(t,e){e instanceof DocumentFragment||e instanceof Node?t.replaceChildren(e):typeof e=="string"?t.innerHTML=e:e!=null&&t.replaceChildren(document.createTextNode(String(e)))}const _={start(t){if(a=document.querySelector(t.target),!a)throw new Error(`[tina4] Router target '${t.target}' not found in DOM`);u=t.mode??"history",window.addEventListener("popstate",d),u==="hash"&&window.addEventListener("hashchange",d),document.addEventListener("click",e=>{var s;if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return;const r=e.target.closest("a[href]");if(!r||r.origin!==location.origin||r.hasAttribute("target")||r.hasAttribute("download")||(s=r.getAttribute("rel"))!=null&&s.includes("external"))return;e.preventDefault();const n=u==="hash"?r.getAttribute("href"):r.pathname;v(n)}),d()},on(t,e){return c.push(e),()=>{const r=c.indexOf(e);r>=0&&c.splice(r,1)}}};function x(){return p.map(t=>({pattern:t.pattern,hasGuard:!!t.guard}))}function S(){for(const t of l)t();l=[],w=0,p=[],a=null,u="history",c.length=0}exports._getRoutes=x;exports._resetRouter=S;exports.navigate=v;exports.route=R;exports.router=_;
|
package/dist/index.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as y } from "./signal.es.js";
|
|
2
|
-
let p = [], a = null,
|
|
2
|
+
let p = [], a = null, u = "history";
|
|
3
3
|
const c = [];
|
|
4
|
-
let
|
|
4
|
+
let l = [], w = 0;
|
|
5
5
|
function R(t, e) {
|
|
6
6
|
const r = [];
|
|
7
7
|
let n;
|
|
@@ -16,7 +16,7 @@ function R(t, e) {
|
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
function x(t, e) {
|
|
19
|
-
if (
|
|
19
|
+
if (u === "hash")
|
|
20
20
|
if (e != null && e.replace) {
|
|
21
21
|
const r = new URL(location.href);
|
|
22
22
|
r.hash = "#" + t, history.replaceState(null, "", r.toString()), d();
|
|
@@ -27,7 +27,7 @@ function x(t, e) {
|
|
|
27
27
|
}
|
|
28
28
|
function d() {
|
|
29
29
|
if (!a) return;
|
|
30
|
-
const t = performance.now(), e = ++w, r =
|
|
30
|
+
const t = performance.now(), e = ++w, r = u === "hash" ? location.hash.slice(1) || "/" : location.pathname;
|
|
31
31
|
for (const n of p) {
|
|
32
32
|
const s = r.match(n.regex);
|
|
33
33
|
if (!s) continue;
|
|
@@ -42,8 +42,8 @@ function d() {
|
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
for (const o of
|
|
46
|
-
|
|
45
|
+
for (const o of l) o();
|
|
46
|
+
l = [], a.innerHTML = "";
|
|
47
47
|
const i = [];
|
|
48
48
|
y(i);
|
|
49
49
|
const m = n.handler(f);
|
|
@@ -53,12 +53,12 @@ function d() {
|
|
|
53
53
|
for (const g of i) g();
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
-
v(a, o),
|
|
56
|
+
v(a, o), l = i;
|
|
57
57
|
const h = performance.now() - t;
|
|
58
58
|
for (const g of c) g({ path: r, params: f, pattern: n.pattern, durationMs: h });
|
|
59
59
|
});
|
|
60
60
|
else {
|
|
61
|
-
y(null), v(a, m),
|
|
61
|
+
y(null), v(a, m), l = i;
|
|
62
62
|
const o = performance.now() - t;
|
|
63
63
|
for (const h of c) h({ path: r, params: f, pattern: n.pattern, durationMs: o });
|
|
64
64
|
}
|
|
@@ -66,19 +66,19 @@ function d() {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
function v(t, e) {
|
|
69
|
-
e instanceof DocumentFragment || e instanceof Node ? t.
|
|
69
|
+
e instanceof DocumentFragment || e instanceof Node ? t.replaceChildren(e) : typeof e == "string" ? t.innerHTML = e : e != null && t.replaceChildren(document.createTextNode(String(e)));
|
|
70
70
|
}
|
|
71
71
|
const S = {
|
|
72
72
|
start(t) {
|
|
73
73
|
if (a = document.querySelector(t.target), !a)
|
|
74
74
|
throw new Error(`[tina4] Router target '${t.target}' not found in DOM`);
|
|
75
|
-
|
|
75
|
+
u = t.mode ?? "history", window.addEventListener("popstate", d), u === "hash" && window.addEventListener("hashchange", d), document.addEventListener("click", (e) => {
|
|
76
76
|
var s;
|
|
77
77
|
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
78
78
|
const r = e.target.closest("a[href]");
|
|
79
79
|
if (!r || r.origin !== location.origin || r.hasAttribute("target") || r.hasAttribute("download") || (s = r.getAttribute("rel")) != null && s.includes("external")) return;
|
|
80
80
|
e.preventDefault();
|
|
81
|
-
const n =
|
|
81
|
+
const n = u === "hash" ? r.getAttribute("href") : r.pathname;
|
|
82
82
|
x(n);
|
|
83
83
|
}), d();
|
|
84
84
|
},
|
|
@@ -93,8 +93,8 @@ function L() {
|
|
|
93
93
|
return p.map((t) => ({ pattern: t.pattern, hasGuard: !!t.guard }));
|
|
94
94
|
}
|
|
95
95
|
function b() {
|
|
96
|
-
for (const t of
|
|
97
|
-
|
|
96
|
+
for (const t of l) t();
|
|
97
|
+
l = [], w = 0, p = [], a = null, u = "history", c.length = 0;
|
|
98
98
|
}
|
|
99
99
|
export {
|
|
100
100
|
L as _,
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -240,6 +240,13 @@ npm run dev # dev server
|
|
|
240
240
|
|
|
241
241
|
## Changelog
|
|
242
242
|
|
|
243
|
+
### 1.0.4
|
|
244
|
+
- Added router reactive effect cleanup tests (navigate away/back, stale effects, async handlers, stale async discard)
|
|
245
|
+
- Added debug overlay documentation to README and TINA4.md
|
|
246
|
+
|
|
247
|
+
### 1.0.3
|
|
248
|
+
- **Fix:** `renderContent` now uses `replaceChildren` instead of `appendChild`, preventing duplicate content when async route handlers resolve.
|
|
249
|
+
|
|
243
250
|
### 1.0.2
|
|
244
251
|
- **Fix:** Router now disposes reactive effects when navigating between routes. Previously, signal subscriptions created by `html` templates survived DOM removal via `innerHTML = ''`, causing duplicate renders when revisiting a page.
|
|
245
252
|
- **Fix:** Stale async route handlers are discarded if navigation occurs before they resolve.
|