@mauroandre/velojs 0.0.42 → 0.0.44

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.
@@ -127,8 +127,10 @@ Understanding the data flow helps you debug issues:
127
127
 
128
128
  **Client-side navigation (SPA):**
129
129
  1. User clicks a link
130
- 2. VeloJS compares each module's route pattern against the new URL and marks stale the ones whose **declared params** changed
130
+ 2. VeloJS marks stale the modules whose **declared params** changed — or that **were not part of the previous location** (they unmounted and are remounting now)
131
131
  3. One `?_data=1` request serves all of them
132
132
  4. Only the stale modules are written — a module the client owns locally (a filtered list, an optimistic edit) is left alone
133
133
 
134
- That last point is why a layout at `/admin/empresas` keeps a filtered list while you navigate among its children: its route declares no param, so nothing invalidates it.
134
+ The second rule is why returning to a page always shows fresh data: leaving `/` for `/leads` unmounts the Dashboard, so navigating back re-runs its loader. The first rule is why `/leads/1` → `/leads/2` refetches.
135
+
136
+ That last point is why a layout at `/admin/empresas` keeps a filtered list while you navigate among its children: it stays matched the whole time — no param changed and it never unmounted, so nothing invalidates it. (Leaving the subtree entirely and coming back *does* revalidate it — the layout remounted.)
@@ -60,7 +60,8 @@ var ctx = canvas.getContext("2d");
60
60
  var W = 0, H = 0;
61
61
 
62
62
  function resize() {
63
- W = window.innerWidth; H = window.innerHeight;
63
+ var tb = document.getElementById("topbar");
64
+ W = window.innerWidth; H = window.innerHeight - tb.offsetHeight;
64
65
  canvas.width = W * devicePixelRatio; canvas.height = H * devicePixelRatio;
65
66
  canvas.style.width = W + "px"; canvas.style.height = H + "px";
66
67
  ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);
@@ -240,26 +241,26 @@ function nodeAt(sx, sy) {
240
241
  return null;
241
242
  }
242
243
  canvas.addEventListener("mousedown", function (e) {
243
- var n = nodeAt(e.clientX, e.clientY);
244
+ var n = nodeAt(e.offsetX, e.offsetY);
244
245
  if (n && view === "modules") { dragNode = n; alpha = Math.max(alpha, 0.3); }
245
246
  else panning = true;
246
- lastX = e.clientX; lastY = e.clientY; moved = false;
247
+ lastX = e.offsetX; lastY = e.offsetY; moved = false;
247
248
  });
248
249
  canvas.addEventListener("mousemove", function (e) {
249
- var dx = e.clientX - lastX, dy = e.clientY - lastY;
250
+ var dx = e.offsetX - lastX, dy = e.offsetY - lastY;
250
251
  if (Math.abs(dx) + Math.abs(dy) > 3) moved = true;
251
- if (dragNode) { var w = toWorld(e.clientX, e.clientY); dragNode.x = w[0]; dragNode.y = w[1]; dragNode.vx = dragNode.vy = 0; }
252
+ if (dragNode) { var w = toWorld(e.offsetX, e.offsetY); dragNode.x = w[0]; dragNode.y = w[1]; dragNode.vx = dragNode.vy = 0; }
252
253
  else if (panning) { cam.x += dx; cam.y += dy; }
253
254
  else {
254
- var n = nodeAt(e.clientX, e.clientY);
255
+ var n = nodeAt(e.offsetX, e.offsetY);
255
256
  hoverHL = n ? { list: relatedNodes(n), origin: n } : null;
256
257
  canvas.style.cursor = n ? "pointer" : "grab";
257
258
  }
258
- lastX = e.clientX; lastY = e.clientY;
259
+ lastX = e.offsetX; lastY = e.offsetY;
259
260
  });
260
261
  canvas.addEventListener("mouseup", function (e) {
261
262
  if (!moved) {
262
- var n = nodeAt(e.clientX, e.clientY);
263
+ var n = nodeAt(e.offsetX, e.offsetY);
263
264
  if (n) {
264
265
  pinnedHL = { list: relatedNodes(n), origin: n };
265
266
  var id = view === "modules" ? n.id : n.data.moduleId;
@@ -274,9 +275,9 @@ canvas.addEventListener("mouseup", function (e) {
274
275
  canvas.addEventListener("wheel", function (e) {
275
276
  e.preventDefault();
276
277
  var k = Math.exp(-e.deltaY * 0.0012);
277
- var w = toWorld(e.clientX, e.clientY);
278
+ var w = toWorld(e.offsetX, e.offsetY);
278
279
  cam.k *= k;
279
- cam.x = e.clientX - w[0] * cam.k; cam.y = e.clientY - w[1] * cam.k;
280
+ cam.x = e.offsetX - w[0] * cam.k; cam.y = e.offsetY - w[1] * cam.k;
280
281
  }, { passive: false });
281
282
 
282
283
  // ---------- rendering ----------
@@ -389,8 +390,8 @@ fetch("/graph.json").then(function (r) { return r.json(); }).then(function (g) {
389
390
  <\/script>
390
391
  </body>
391
392
  </html>`;
392
- async function f(o) {
393
- const i = l.join(o, ".velojs", "graph.json"), a = r.createServer((n, e) => {
393
+ async function m(a) {
394
+ const i = l.join(a, ".velojs", "graph.json"), o = r.createServer((n, e) => {
394
395
  if (n.url === "/graph.json") {
395
396
  let t;
396
397
  try {
@@ -405,12 +406,12 @@ async function f(o) {
405
406
  e.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }), e.end(s);
406
407
  });
407
408
  return await new Promise((n) => {
408
- a.listen(0, "127.0.0.1", () => {
409
- const e = a.address(), t = typeof e == "object" && e ? e.port : 0;
409
+ o.listen(0, "127.0.0.1", () => {
410
+ const e = o.address(), t = typeof e == "object" && e ? e.port : 0;
410
411
  n(`http://127.0.0.1:${t}`);
411
412
  });
412
413
  });
413
414
  }
414
415
  export {
415
- f as serveGraphViewer
416
+ m as serveGraphViewer
416
417
  };
@@ -7,9 +7,12 @@
7
7
  * no module-scope mirror to keep in sync.
8
8
  *
9
9
  * Invalidation follows the route tree: an entry is stale when the params its own
10
- * route declares have changed. That is what the server already does — a loader
11
- * re-runs when a request arrives with different params — so the client stops
12
- * making the author restate it in `useLoader([params.id])`.
10
+ * route declares have changed — or when the module was not part of the previous
11
+ * location's matched chain (it unmounted and is now remounting). The first rule
12
+ * mirrors the server (a loader re-runs when a request arrives with different
13
+ * params); the second mirrors user expectation (returning to a page shows fresh
14
+ * data). A layout keeps its data while navigating among its children because it
15
+ * stays matched the whole time — its client-owned state survives.
13
16
  *
14
17
  * Deliberately NOT invalidated by:
15
18
  * - a query-string change: `routes.tsx` declares path params, never `?x=`, so
@@ -32,14 +35,16 @@ export declare function registerRoutePatterns(routes: AppRoutes): void;
32
35
  /**
33
36
  * Extract the params a pattern declares from a pathname. Layout patterns are
34
37
  * prefixes of the URL (`/x/:id` covers `/x/1/tab`), mirroring how the client
35
- * router matches them, so the match is prefix-tolerant.
38
+ * router matches them, so the match is prefix-tolerant. Leaf patterns (routes
39
+ * without children) match exactly, mirroring wouter's exact `<Route>` for them.
36
40
  *
37
41
  * Returns null when the pattern does not cover the pathname at all.
38
42
  */
39
- export declare function extractParams(pattern: string, pathname: string): Record<string, string> | null;
43
+ export declare function extractParams(pattern: string, pathname: string, exact?: boolean): Record<string, string> | null;
40
44
  /**
41
45
  * Called on every client navigation. Refetches exactly the entries whose
42
- * declared params changed, in one coalesced request.
46
+ * declared params changed OR that were not matched at the previous location
47
+ * (they unmounted and are remounting now), in one coalesced request.
43
48
  */
44
49
  export declare function syncLocation(pathname: string): void;
45
50
  /** Explicit refresh. Never coalesced: a caller asking after a mutation must not
@@ -1,103 +1,119 @@
1
- import { signal as f } from "@preact/signals";
2
- const p = f(!1), c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), _ = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new WeakSet();
3
- let u = !1;
4
- function S(t) {
5
- y();
1
+ import { signal as d } from "@preact/signals";
2
+ const S = d(!1), c = /* @__PURE__ */ new Map(), _ = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Map();
3
+ let u = /* @__PURE__ */ new Set();
4
+ const l = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new WeakSet();
5
+ let w = !1;
6
+ function E(t) {
7
+ v();
6
8
  let e = c.get(t);
7
- return e || (e = f(null), c.set(t, e)), e;
9
+ return e || (e = d(null), c.set(t, e)), e;
8
10
  }
9
- function w(t) {
10
- let e = l.get(t);
11
- return e || (e = f(!1), l.set(t, e)), e;
11
+ function g(t) {
12
+ let e = _.get(t);
13
+ return e || (e = d(!1), _.set(t, e)), e;
12
14
  }
13
- function y() {
14
- if (u || typeof window > "u") return;
15
- u = !0;
15
+ function v() {
16
+ if (w || typeof window > "u") return;
17
+ w = !0;
16
18
  const t = window.__PAGE_DATA__;
17
19
  if (t)
18
20
  for (const e of Object.keys(t)) {
19
21
  if (e.startsWith("__")) continue;
20
22
  let n = c.get(e);
21
- n || (n = f(null), c.set(e, n)), n.value = t[e];
23
+ n || (n = d(null), c.set(e, n)), n.value = t[e];
22
24
  }
23
25
  }
24
- function O(t) {
25
- if (h.has(t)) return;
26
- h.add(t);
26
+ function x(t) {
27
+ if (y.has(t)) return;
28
+ y.add(t);
27
29
  const e = (n) => {
28
30
  for (const o of n) {
29
31
  const i = o.module?.metadata;
30
- i?.moduleId && i.fullPath !== void 0 && d.set(i.moduleId, i.fullPath), o.children && e(o.children);
32
+ i?.moduleId && i.fullPath !== void 0 && (f.set(i.moduleId, i.fullPath), (!o.children || o.children.length === 0) && h.add(i.moduleId)), o.children && e(o.children);
31
33
  }
32
34
  };
33
35
  if (e(t), typeof window < "u") {
34
- y();
35
- for (const n of c.keys()) v(n, window.location.pathname);
36
+ v();
37
+ for (const n of c.keys()) M(n, window.location.pathname);
38
+ u = L(window.location.pathname);
36
39
  }
37
40
  }
38
- const k = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
39
- function E(t, e) {
40
- const n = [], o = t.split("/").map((r) => r.startsWith(":") ? (n.push(r.slice(1)), "([^/]+)") : k(r)).join("/"), i = e.match(new RegExp(`^${o}(?:/.*)?$`));
41
- if (!i) return null;
42
- const a = {};
43
- return n.forEach((r, L) => {
44
- a[r] = i[L + 1];
45
- }), a;
41
+ const P = (t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
42
+ function m(t, e, n = !1) {
43
+ const o = [], i = t.split("/").map((s) => s.startsWith(":") ? (o.push(s.slice(1)), "([^/]+)") : P(s)).join("/"), a = e.match(
44
+ new RegExp(n ? `^${i}/?$` : `^${i}(?:/.*)?$`)
45
+ );
46
+ if (!a) return null;
47
+ const r = {};
48
+ return o.forEach((s, A) => {
49
+ r[s] = a[A + 1];
50
+ }), r;
46
51
  }
47
- function g(t, e) {
48
- const n = d.get(t);
52
+ function O(t, e) {
53
+ const n = f.get(t);
54
+ return n === void 0 ? !1 : m(n, e, h.has(t)) !== null;
55
+ }
56
+ function L(t) {
57
+ const e = /* @__PURE__ */ new Set();
58
+ for (const n of f.keys())
59
+ O(n, t) && e.add(n);
60
+ return e;
61
+ }
62
+ function k(t, e) {
63
+ const n = f.get(t);
49
64
  if (n === void 0) return null;
50
- const o = E(n, e);
65
+ const o = m(n, e, h.has(t));
51
66
  return o === null ? null : JSON.stringify(o);
52
67
  }
53
- function v(t, e) {
54
- const n = g(t, e);
55
- n !== null && _.set(t, n);
68
+ function M(t, e) {
69
+ const n = k(t, e);
70
+ n !== null && p.set(t, n);
56
71
  }
57
- function P(t) {
72
+ function H(t) {
58
73
  if (typeof __VELO_STATIC__ < "u" && __VELO_STATIC__) return `${t === "/" ? "" : t}/index.json`;
59
74
  const n = new URLSearchParams(window.location.search);
60
75
  return n.set("_data", "1"), `${t}?${n.toString()}`;
61
76
  }
62
- async function m(t, e, n) {
77
+ async function $(t, e, n) {
63
78
  if (typeof window > "u" || t.length === 0) return;
64
- const o = P(e);
65
- for (const a of t) w(a).value = !0;
66
- let i = n ? s.get(o) : void 0;
67
- i || (i = fetch(o, { cache: "no-cache" }).then((a) => a.json()), n && (s.set(o, i), i.catch(() => {
68
- }).then(() => s.delete(o))));
79
+ const o = H(e);
80
+ for (const a of t) g(a).value = !0;
81
+ let i = n ? l.get(o) : void 0;
82
+ i || (i = fetch(o, { cache: "no-cache" }).then((a) => a.json()), n && (l.set(o, i), i.catch(() => {
83
+ }).then(() => l.delete(o))));
69
84
  try {
70
85
  const a = await i;
71
- typeof __VELO_BUILD_HASH__ < "u" && a.__buildHash && a.__buildHash !== __VELO_BUILD_HASH__ && (p.value = !0);
86
+ typeof __VELO_BUILD_HASH__ < "u" && a.__buildHash && a.__buildHash !== __VELO_BUILD_HASH__ && (S.value = !0);
72
87
  for (const r of t)
73
- r in a && (S(r).value = a[r], v(r, e));
88
+ r in a && (E(r).value = a[r], M(r, e));
74
89
  } catch {
75
90
  } finally {
76
- for (const a of t) w(a).value = !1;
91
+ for (const a of t) g(a).value = !1;
77
92
  }
78
93
  }
79
- function $(t) {
94
+ function T(t) {
80
95
  if (typeof window > "u") return;
81
- const e = [];
82
- for (const n of c.keys()) {
83
- const o = g(n, t);
84
- o !== null && _.get(n) !== o && e.push(n);
96
+ const e = [], n = L(t);
97
+ for (const o of c.keys()) {
98
+ if (!n.has(o)) continue;
99
+ const i = k(o, t);
100
+ p.get(o) === i && u.has(o) || e.push(o);
85
101
  }
86
- m(e, t, !0);
102
+ u = n, $(e, t, !0);
87
103
  }
88
- function H(t) {
89
- typeof window > "u" || m([t], window.location.pathname, !1);
104
+ function U(t) {
105
+ typeof window > "u" || $([t], window.location.pathname, !1);
90
106
  }
91
- function M() {
92
- c.clear(), l.clear(), d.clear(), _.clear(), s.clear(), u = !1, p.value = !1;
107
+ function D() {
108
+ c.clear(), _.clear(), f.clear(), h.clear(), p.clear(), u = /* @__PURE__ */ new Set(), l.clear(), w = !1, S.value = !1;
93
109
  }
94
110
  export {
95
- M as __resetLoaderStore,
96
- p as __veloUpdatePending,
97
- E as extractParams,
98
- S as loaderEntry,
99
- w as loaderLoading,
100
- H as refetchModule,
101
- O as registerRoutePatterns,
102
- $ as syncLocation
111
+ D as __resetLoaderStore,
112
+ S as __veloUpdatePending,
113
+ m as extractParams,
114
+ E as loaderEntry,
115
+ g as loaderLoading,
116
+ U as refetchModule,
117
+ x as registerRoutePatterns,
118
+ T as syncLocation
103
119
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mauroandre/velojs",
3
- "version": "0.0.42",
3
+ "version": "0.0.44",
4
4
  "type": "module",
5
5
  "description": "Fullstack web framework built on Hono + Preact with Vite-powered AST transforms",
6
6
  "keywords": [