@elurjs/core 3.6.2 → 3.7.0-beta.0

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 (211) hide show
  1. package/dist/lib/async.cjs +1 -1
  2. package/dist/lib/async.js +1 -1
  3. package/dist/lib/component.cjs +1 -2
  4. package/dist/lib/component.js +2 -66
  5. package/dist/lib/context.cjs +1 -1
  6. package/dist/lib/context.js +35 -23
  7. package/dist/lib/devtools.cjs +1 -1
  8. package/dist/lib/devtools.js +1 -1
  9. package/dist/lib/elur/async.cjs +1 -1
  10. package/dist/lib/elur/async.cjs.map +1 -1
  11. package/dist/lib/elur/async.js +1 -1
  12. package/dist/lib/elur/component.cjs +1 -2
  13. package/dist/lib/elur/component.d.cts +1 -17
  14. package/dist/lib/elur/component.d.ts +1 -17
  15. package/dist/lib/elur/component.js +2 -66
  16. package/dist/lib/elur/context.cjs +1 -1
  17. package/dist/lib/elur/context.cjs.map +1 -1
  18. package/dist/lib/elur/context.d.cts +5 -0
  19. package/dist/lib/elur/context.d.ts +5 -0
  20. package/dist/lib/elur/context.js +35 -23
  21. package/dist/lib/elur/context.js.map +1 -1
  22. package/dist/lib/elur/devtools.cjs +1 -1
  23. package/dist/lib/elur/devtools.cjs.map +1 -1
  24. package/dist/lib/elur/devtools.js +1 -1
  25. package/dist/lib/elur/form.cjs +1 -1
  26. package/dist/lib/elur/form.cjs.map +1 -1
  27. package/dist/lib/elur/form.js +1 -1
  28. package/dist/lib/elur/hydrate/index.cjs +1 -2
  29. package/dist/lib/elur/hydrate/index.d.cts +1 -13
  30. package/dist/lib/elur/hydrate/index.d.ts +1 -13
  31. package/dist/lib/elur/hydrate/index.js +2 -410
  32. package/dist/lib/elur/lifecycle.cjs +1 -1
  33. package/dist/lib/elur/lifecycle.cjs.map +1 -1
  34. package/dist/lib/elur/lifecycle.d.cts +27 -0
  35. package/dist/lib/elur/lifecycle.d.ts +27 -0
  36. package/dist/lib/elur/lifecycle.js +4 -0
  37. package/dist/lib/elur/lifecycle.js.map +1 -1
  38. package/dist/lib/elur/next/component.d.cts +281 -0
  39. package/dist/lib/elur/next/component.d.ts +281 -0
  40. package/dist/lib/elur/next/dom-write.d.cts +18 -0
  41. package/dist/lib/elur/next/dom-write.d.ts +18 -0
  42. package/dist/lib/elur/next/hydrate.d.cts +14 -0
  43. package/dist/lib/elur/next/hydrate.d.ts +14 -0
  44. package/dist/lib/elur/next/keyed-diff.d.cts +46 -0
  45. package/dist/lib/elur/next/keyed-diff.d.ts +46 -0
  46. package/dist/lib/elur/next/mount-helpers.d.cts +25 -0
  47. package/dist/lib/elur/next/mount-helpers.d.ts +25 -0
  48. package/dist/lib/elur/next/mount.d.cts +29 -0
  49. package/dist/lib/elur/next/mount.d.ts +29 -0
  50. package/dist/lib/elur/next/node-binding.d.cts +6 -0
  51. package/dist/lib/elur/next/node-binding.d.ts +6 -0
  52. package/dist/lib/elur/next/reactivity.d.cts +193 -0
  53. package/dist/lib/elur/next/reactivity.d.ts +193 -0
  54. package/dist/lib/elur/next-2/component.cjs +2 -0
  55. package/dist/lib/elur/next-2/component.cjs.map +1 -0
  56. package/dist/lib/elur/next-2/component.d.cts +283 -0
  57. package/dist/lib/elur/next-2/component.d.ts +283 -0
  58. package/dist/lib/elur/next-2/component.js +340 -0
  59. package/dist/lib/elur/next-2/component.js.map +1 -0
  60. package/dist/lib/elur/next-2/dom-write.cjs +2 -0
  61. package/dist/lib/elur/next-2/dom-write.cjs.map +1 -0
  62. package/dist/lib/elur/next-2/dom-write.d.cts +18 -0
  63. package/dist/lib/elur/next-2/dom-write.d.ts +18 -0
  64. package/dist/lib/elur/next-2/dom-write.js +31 -0
  65. package/dist/lib/elur/next-2/dom-write.js.map +1 -0
  66. package/dist/lib/elur/next-2/hydrate.cjs +2 -0
  67. package/dist/lib/elur/next-2/hydrate.cjs.map +1 -0
  68. package/dist/lib/elur/next-2/hydrate.d.cts +30 -0
  69. package/dist/lib/elur/next-2/hydrate.d.ts +30 -0
  70. package/dist/lib/elur/next-2/hydrate.js +449 -0
  71. package/dist/lib/elur/next-2/hydrate.js.map +1 -0
  72. package/dist/lib/elur/next-2/keyed-diff.cjs +2 -0
  73. package/dist/lib/elur/next-2/keyed-diff.cjs.map +1 -0
  74. package/dist/lib/elur/next-2/keyed-diff.d.cts +79 -0
  75. package/dist/lib/elur/next-2/keyed-diff.d.ts +79 -0
  76. package/dist/lib/elur/next-2/keyed-diff.js +208 -0
  77. package/dist/lib/elur/next-2/keyed-diff.js.map +1 -0
  78. package/dist/lib/elur/next-2/mount-helpers.cjs +2 -0
  79. package/dist/lib/elur/next-2/mount-helpers.cjs.map +1 -0
  80. package/dist/lib/elur/next-2/mount-helpers.d.cts +25 -0
  81. package/dist/lib/elur/next-2/mount-helpers.d.ts +25 -0
  82. package/dist/lib/elur/next-2/mount-helpers.js +87 -0
  83. package/dist/lib/elur/next-2/mount-helpers.js.map +1 -0
  84. package/dist/lib/elur/next-2/mount.cjs +2 -0
  85. package/dist/lib/elur/next-2/mount.cjs.map +1 -0
  86. package/dist/lib/elur/next-2/mount.d.cts +29 -0
  87. package/dist/lib/elur/next-2/mount.d.ts +29 -0
  88. package/dist/lib/elur/next-2/mount.js +34 -0
  89. package/dist/lib/elur/next-2/mount.js.map +1 -0
  90. package/dist/lib/elur/next-2/node-binding.cjs +2 -0
  91. package/dist/lib/elur/next-2/node-binding.cjs.map +1 -0
  92. package/dist/lib/elur/next-2/node-binding.d.cts +6 -0
  93. package/dist/lib/elur/next-2/node-binding.d.ts +6 -0
  94. package/dist/lib/elur/next-2/node-binding.js +130 -0
  95. package/dist/lib/elur/next-2/node-binding.js.map +1 -0
  96. package/dist/lib/elur/next-2/reactivity.cjs +2 -0
  97. package/dist/lib/elur/next-2/reactivity.cjs.map +1 -0
  98. package/dist/lib/elur/next-2/reactivity.d.cts +220 -0
  99. package/dist/lib/elur/next-2/reactivity.d.ts +220 -0
  100. package/dist/lib/elur/next-2/reactivity.js +614 -0
  101. package/dist/lib/elur/next-2/reactivity.js.map +1 -0
  102. package/dist/lib/elur/next-2/scheduler.cjs +2 -0
  103. package/dist/lib/elur/next-2/scheduler.cjs.map +1 -0
  104. package/dist/lib/elur/next-2/scheduler.d.cts +23 -0
  105. package/dist/lib/elur/next-2/scheduler.d.ts +23 -0
  106. package/dist/lib/elur/next-2/scheduler.js +26 -0
  107. package/dist/lib/elur/next-2/scheduler.js.map +1 -0
  108. package/dist/lib/elur/plugins.cjs +1 -1
  109. package/dist/lib/elur/plugins.cjs.map +1 -1
  110. package/dist/lib/elur/plugins.js +1 -1
  111. package/dist/lib/elur/reactivity.cjs +1 -2
  112. package/dist/lib/elur/reactivity.d.cts +1 -67
  113. package/dist/lib/elur/reactivity.d.ts +1 -67
  114. package/dist/lib/elur/reactivity.js +2 -218
  115. package/dist/lib/elur/router.cjs +1 -1
  116. package/dist/lib/elur/router.cjs.map +1 -1
  117. package/dist/lib/elur/router.js +1 -1
  118. package/dist/lib/elur/server/index.cjs +1 -1
  119. package/dist/lib/elur/server/index.cjs.map +1 -1
  120. package/dist/lib/elur/server/index.js +175 -107
  121. package/dist/lib/elur/server/index.js.map +1 -1
  122. package/dist/lib/elur/store.cjs +1 -1
  123. package/dist/lib/elur/store.cjs.map +1 -1
  124. package/dist/lib/elur/store.js +1 -1
  125. package/dist/lib/elur/template/bindings.cjs +1 -1
  126. package/dist/lib/elur/template/bindings.cjs.map +1 -1
  127. package/dist/lib/elur/template/bindings.js +98 -84
  128. package/dist/lib/elur/template/bindings.js.map +1 -1
  129. package/dist/lib/elur/template/dom-write.d.cts +1 -5
  130. package/dist/lib/elur/template/dom-write.d.ts +1 -5
  131. package/dist/lib/elur/template/error-boundary.cjs +1 -1
  132. package/dist/lib/elur/template/error-boundary.cjs.map +1 -1
  133. package/dist/lib/elur/template/error-boundary.js +56 -50
  134. package/dist/lib/elur/template/error-boundary.js.map +1 -1
  135. package/dist/lib/elur/template/html.cjs +1 -1
  136. package/dist/lib/elur/template/html.cjs.map +1 -1
  137. package/dist/lib/elur/template/html.js +40 -37
  138. package/dist/lib/elur/template/html.js.map +1 -1
  139. package/dist/lib/elur/template/index.cjs +1 -1
  140. package/dist/lib/elur/template/index.d.cts +2 -1
  141. package/dist/lib/elur/template/index.d.ts +2 -1
  142. package/dist/lib/elur/template/index.js +13 -12
  143. package/dist/lib/elur/template/keyed-diff.d.cts +1 -32
  144. package/dist/lib/elur/template/keyed-diff.d.ts +1 -32
  145. package/dist/lib/elur/template/keyed.cjs +1 -1
  146. package/dist/lib/elur/template/keyed.cjs.map +1 -1
  147. package/dist/lib/elur/template/keyed.d.cts +10 -2
  148. package/dist/lib/elur/template/keyed.d.ts +10 -2
  149. package/dist/lib/elur/template/keyed.js +12 -1
  150. package/dist/lib/elur/template/keyed.js.map +1 -1
  151. package/dist/lib/elur/template/mount-helpers.d.cts +1 -29
  152. package/dist/lib/elur/template/mount-helpers.d.ts +1 -29
  153. package/dist/lib/elur/template/node-binding.d.cts +1 -6
  154. package/dist/lib/elur/template/node-binding.d.ts +1 -6
  155. package/dist/lib/elur/template/portal.cjs +1 -1
  156. package/dist/lib/elur/template/portal.cjs.map +1 -1
  157. package/dist/lib/elur/template/portal.js +1 -1
  158. package/dist/lib/elur/template/transitions.cjs +1 -1
  159. package/dist/lib/elur/template/transitions.cjs.map +1 -1
  160. package/dist/lib/elur/template/transitions.js +2 -2
  161. package/dist/lib/elur/template/types.cjs +1 -1
  162. package/dist/lib/elur/template/types.cjs.map +1 -1
  163. package/dist/lib/elur/template/types.d.cts +55 -0
  164. package/dist/lib/elur/template/types.d.ts +55 -0
  165. package/dist/lib/elur/template/types.js +5 -1
  166. package/dist/lib/elur/template/types.js.map +1 -1
  167. package/dist/lib/elur.cjs +1 -1
  168. package/dist/lib/elur.js +2 -2
  169. package/dist/lib/form.cjs +1 -1
  170. package/dist/lib/form.js +1 -1
  171. package/dist/lib/hydrate.cjs +1 -2
  172. package/dist/lib/hydrate.js +2 -410
  173. package/dist/lib/index.cjs +1 -1
  174. package/dist/lib/index.js +2 -2
  175. package/dist/lib/lifecycle.cjs +1 -1
  176. package/dist/lib/lifecycle.js +4 -0
  177. package/dist/lib/plugins.cjs +1 -1
  178. package/dist/lib/plugins.js +1 -1
  179. package/dist/lib/router.cjs +1 -1
  180. package/dist/lib/router.js +1 -1
  181. package/dist/lib/server.cjs +1 -1
  182. package/dist/lib/server.js +175 -107
  183. package/dist/lib/signals.cjs +1 -2
  184. package/dist/lib/signals.js +2 -218
  185. package/dist/lib/store.cjs +1 -1
  186. package/dist/lib/store.js +1 -1
  187. package/dist/lib/template.cjs +1 -1
  188. package/dist/lib/template.js +13 -12
  189. package/package.json +7 -9
  190. package/dist/lib/elur/component.cjs.map +0 -1
  191. package/dist/lib/elur/component.js.map +0 -1
  192. package/dist/lib/elur/hydrate/index.cjs.map +0 -1
  193. package/dist/lib/elur/hydrate/index.js.map +0 -1
  194. package/dist/lib/elur/reactivity.cjs.map +0 -1
  195. package/dist/lib/elur/reactivity.js.map +0 -1
  196. package/dist/lib/elur/template/dom-write.cjs +0 -2
  197. package/dist/lib/elur/template/dom-write.cjs.map +0 -1
  198. package/dist/lib/elur/template/dom-write.js +0 -16
  199. package/dist/lib/elur/template/dom-write.js.map +0 -1
  200. package/dist/lib/elur/template/keyed-diff.cjs +0 -2
  201. package/dist/lib/elur/template/keyed-diff.cjs.map +0 -1
  202. package/dist/lib/elur/template/keyed-diff.js +0 -100
  203. package/dist/lib/elur/template/keyed-diff.js.map +0 -1
  204. package/dist/lib/elur/template/mount-helpers.cjs +0 -2
  205. package/dist/lib/elur/template/mount-helpers.cjs.map +0 -1
  206. package/dist/lib/elur/template/mount-helpers.js +0 -132
  207. package/dist/lib/elur/template/mount-helpers.js.map +0 -1
  208. package/dist/lib/elur/template/node-binding.cjs +0 -2
  209. package/dist/lib/elur/template/node-binding.cjs.map +0 -1
  210. package/dist/lib/elur/template/node-binding.js +0 -95
  211. package/dist/lib/elur/template/node-binding.js.map +0 -1
@@ -1,38 +1,39 @@
1
- import { effect as e } from "../../signals.js";
2
- import { queueDOMWrite as t } from "./dom-write.js";
3
- import { activateNodeBinding as n } from "./node-binding.js";
4
- import { isExecutableAttrName as r, isUrlAttrName as i, sanitizeUrl as a } from "./sanitize.js";
1
+ import { Signal as e, _bindSignal as t, effect as n } from "../next-2/reactivity.js";
2
+ import { isDerivedBinding as r } from "./types.js";
3
+ import { queueDOMWrite as i } from "../next-2/dom-write.js";
4
+ import { activateNodeBinding as a } from "../next-2/node-binding.js";
5
+ import { isExecutableAttrName as o, isUrlAttrName as s, sanitizeUrl as c } from "./sanitize.js";
5
6
  //#region src/elur/template/bindings.ts
6
- function o(e, t) {
7
+ function l(e, t) {
7
8
  t ? e.style.display === "none" && (e.style.display = "") : e.style.display !== "none" && (e.style.display = "none");
8
9
  }
9
- function s(e) {
10
+ function u(e) {
10
11
  let t = e.lastIndexOf(">"), n = e.lastIndexOf("<");
11
12
  if (n <= t) return { type: "node" };
12
- let a = e.slice(n + 1), o = a.lastIndexOf("=");
13
- if (o === -1) return { type: "node" };
14
- let s = a.endsWith("\"") || a.endsWith("'") || a[a.length - 1] === "\"" || a[a.length - 1] === "'", c = o - 1;
15
- for (; c >= 0 && /\S/.test(a[c]);) c--;
13
+ let r = e.slice(n + 1), i = r.lastIndexOf("=");
14
+ if (i === -1) return { type: "node" };
15
+ let a = r.endsWith("\"") || r.endsWith("'") || r[r.length - 1] === "\"" || r[r.length - 1] === "'", c = i - 1;
16
+ for (; c >= 0 && /\S/.test(r[c]);) c--;
16
17
  c++;
17
- let l = a.slice(c, o);
18
+ let l = r.slice(c, i);
18
19
  if (l[0] === "@") {
19
20
  let e = l.slice(1).split(".");
20
21
  return {
21
22
  type: "event",
22
23
  eventName: e[0],
23
24
  modifiers: e.slice(1),
24
- hadOpenQuote: s
25
+ hadOpenQuote: a
25
26
  };
26
27
  }
27
28
  return {
28
29
  type: "attr",
29
30
  attrName: l,
30
- hadOpenQuote: s,
31
- url: i(l),
32
- executable: r(l)
31
+ hadOpenQuote: a,
32
+ url: s(l),
33
+ executable: o(l)
33
34
  };
34
35
  }
35
- var c = {
36
+ var d = {
36
37
  enter: "Enter",
37
38
  escape: "Escape",
38
39
  space: " ",
@@ -43,7 +44,7 @@ var c = {
43
44
  down: "ArrowDown",
44
45
  left: "ArrowLeft",
45
46
  right: "ArrowRight"
46
- }, l = new Set([
47
+ }, f = new Set([
47
48
  "click",
48
49
  "dblclick",
49
50
  "mousedown",
@@ -53,8 +54,8 @@ var c = {
53
54
  "input",
54
55
  "change",
55
56
  "submit"
56
- ]), u = /* @__PURE__ */ new Set();
57
- function d(e, t, n) {
57
+ ]), p = /* @__PURE__ */ new Set();
58
+ function m(e, t, n) {
58
59
  let r = e.target, i = e.stopPropagation, a = !1;
59
60
  for (e.stopPropagation = () => {
60
61
  a = !0, i.call(e);
@@ -70,7 +71,7 @@ function d(e, t, n) {
70
71
  if ("key" in e) {
71
72
  let n = e, i = !0;
72
73
  for (let e of t) {
73
- let t = c[e];
74
+ let t = d[e];
74
75
  if (t !== void 0 && n.key !== t) {
75
76
  i = !1;
76
77
  break;
@@ -92,29 +93,29 @@ function d(e, t, n) {
92
93
  }
93
94
  e.stopPropagation = i;
94
95
  }
95
- var f = /* @__PURE__ */ new Map();
96
- function p(e) {
97
- if (!u.has(e)) {
98
- let t = `__elur_${e}`, n = `__elur_${e}_mods`, r = (e) => d(e, t, n);
99
- f.set(e, r), document.addEventListener(e, r), u.add(e);
96
+ var h = /* @__PURE__ */ new Map();
97
+ function g(e) {
98
+ if (!p.has(e)) {
99
+ let t = `__elur_${e}`, n = `__elur_${e}_mods`, r = (e) => m(e, t, n);
100
+ h.set(e, r), document.addEventListener(e, r), p.add(e);
100
101
  }
101
102
  }
102
- function m(e, t, n, r) {
103
- p(t);
103
+ function _(e, t, n, r) {
104
+ g(t);
104
105
  let i = `__elur_${t}`, a = `__elur_${t}_mods`;
105
106
  e[i] = r, n.length > 0 && (e[a] = n);
106
107
  }
107
- function h(e, t, n, r) {
108
- m(e, t, n, r);
108
+ function v(e, t, n, r) {
109
+ _(e, t, n, r);
109
110
  let i = `__elur_${t}`, a = `__elur_${t}_mods`;
110
111
  return () => {
111
112
  e[i] = null, e[a] = null;
112
113
  };
113
114
  }
114
- function g(e) {
115
- return l.has(e);
115
+ function y(e) {
116
+ return f.has(e);
116
117
  }
117
- function _(e, t, n, r) {
118
+ function b(e, t, n, r) {
118
119
  let i = Array(t.length), a = -1;
119
120
  for (let e = 0; e < t.length; e++) r[e] && r[e].nodeIndex > a && (a = r[e].nodeIndex);
120
121
  let o = Array(a + 1);
@@ -126,17 +127,19 @@ function _(e, t, n, r) {
126
127
  let t = r[e];
127
128
  i[e] = t ? o[t.nodeIndex] : null;
128
129
  }
129
- return v(e, t, n, r, i);
130
+ return x(e, t, n, r, i);
130
131
  }
131
- function v(o, s, c, l, u) {
132
- let d = [], f = [];
133
- for (let o = 0; o < s.length; o++) {
134
- let p = s[o], m = c[o], _ = l[o];
135
- if (!_) continue;
136
- let v = u[o];
137
- if (p.type === "event") {
138
- let e = _.name, t = m, n = p.modifiers;
139
- if (g(e) && !n.includes("capture") && !n.includes("once") && !n.includes("passive")) d.push(h(v, e, n, t));
132
+ function x(l, u, d, f, p) {
133
+ let m = [], h = [];
134
+ for (let l = 0; l < u.length; l++) {
135
+ let g = u[l], _ = d[l];
136
+ r(_) && (_ = _.get);
137
+ let b = f[l];
138
+ if (!b) continue;
139
+ let x = p[l];
140
+ if (g.type === "event") {
141
+ let e = b.name, t = _, n = g.modifiers;
142
+ if (y(e) && !n.includes("capture") && !n.includes("once") && !n.includes("passive")) m.push(v(x, e, n, t));
140
143
  else {
141
144
  let r = {
142
145
  once: n.includes("once"),
@@ -145,70 +148,81 @@ function v(o, s, c, l, u) {
145
148
  }, i = (e) => {
146
149
  n.includes("prevent") && e.preventDefault(), n.includes("stop") && e.stopPropagation(), !(n.includes("self") && e.target !== e.currentTarget) && t(e);
147
150
  };
148
- v.addEventListener(e, i, r), d.push(() => v.removeEventListener(e, i, r));
151
+ x.addEventListener(e, i, r), m.push(() => x.removeEventListener(e, i, r));
149
152
  }
150
153
  continue;
151
154
  }
152
- if (p.type === "attr") {
153
- let n = _.name, o = v;
154
- if (n === "ref") {
155
- m.el = o, d.push(() => {
156
- m.el = null;
155
+ if (g.type === "attr") {
156
+ let r = b.name, a = x;
157
+ if (r === "ref") {
158
+ _.el = a, m.push(() => {
159
+ _.el = null;
157
160
  });
158
161
  continue;
159
162
  }
160
- if (n === "show" || n === "hide") {
161
- let r = o, i = null;
162
- if (typeof m == "function") {
163
- let a = !1, o = !1, s = !0, c = e(() => {
164
- o = !!m();
165
- let e = () => {
163
+ if (r === "show" || r === "hide") {
164
+ let e = a, t = null;
165
+ if (typeof _ == "function") {
166
+ let a = !1, o = !1, s = !0, c = n(() => {
167
+ o = !!_();
168
+ let n = () => {
166
169
  a = !1;
167
- let e = n === "show" ? o : !o;
168
- i === null && (i = r.style.display || ""), r.style.display = e ? i : "none";
170
+ let n = r === "show" ? o : !o;
171
+ t === null && (t = e.style.display || ""), e.style.display = n ? t : "none";
169
172
  };
170
- s ? (s = !1, e()) : a || (a = !0, t(e));
173
+ s ? (s = !1, n()) : a || (a = !0, i(n));
171
174
  });
172
- d.push(c);
173
- } else (n === "show" ? m : !m) || (r.style.display = "none");
175
+ m.push(c);
176
+ } else (r === "show" ? _ : !_) || (e.style.display = "none");
177
+ continue;
178
+ }
179
+ (g.executable ?? o(r)) && console.warn(`[elur] Dynamic binding on executable attribute "${r}". Use @event for handlers; avoid binding untrusted values here.`);
180
+ let l = g.url ?? s(r), u = (r === "value" || r === "checked" || r === "selected") && r in a;
181
+ if (_ instanceof e) {
182
+ m.push(t(_, (e) => {
183
+ if (u) a[r] = e ?? "";
184
+ else if (e == null || e === !1) a.removeAttribute(r);
185
+ else {
186
+ let t = String(e);
187
+ a.setAttribute(r, l ? c(t) : t);
188
+ }
189
+ }));
174
190
  continue;
175
191
  }
176
- (p.executable ?? r(n)) && console.warn(`[elur] Dynamic binding on executable attribute "${n}". Use @event for handlers; avoid binding untrusted values here.`);
177
- let s = p.url ?? i(n), c = (n === "value" || n === "checked" || n === "selected") && n in o;
178
- if (typeof m == "function") {
179
- let r = !1, i, l = !0, u = e(() => {
180
- i = m();
181
- let e = () => {
182
- r = !1;
183
- let e = i;
184
- if (c) o[n] = e ?? "";
185
- else if (e == null || e === !1) o.removeAttribute(n);
192
+ if (typeof _ == "function") {
193
+ let e = !1, t, o = !0, s = n(() => {
194
+ t = _();
195
+ let n = () => {
196
+ e = !1;
197
+ let n = t;
198
+ if (u) a[r] = n ?? "";
199
+ else if (n == null || n === !1) a.removeAttribute(r);
186
200
  else {
187
- let t = String(e);
188
- o.setAttribute(n, s ? a(t) : t);
201
+ let e = String(n);
202
+ a.setAttribute(r, l ? c(e) : e);
189
203
  }
190
204
  };
191
- l ? (l = !1, e()) : r || (r = !0, t(e));
205
+ o ? (o = !1, n()) : e || (e = !0, i(n));
192
206
  });
193
- d.push(u);
194
- } else if (c) o[n] = m ?? "";
195
- else if (m != null && m !== !1) {
196
- let e = String(m);
197
- o.setAttribute(n, s ? a(e) : e);
207
+ m.push(s);
208
+ } else if (u) a[r] = _ ?? "";
209
+ else if (_ != null && _ !== !1) {
210
+ let e = String(_);
211
+ a.setAttribute(r, l ? c(e) : e);
198
212
  }
199
213
  continue;
200
214
  }
201
- let y = v;
202
- if (!y) continue;
203
- let b = document.createTextNode("");
204
- y.parentNode.replaceChild(b, y), n(b, m, d, f);
215
+ let S = x;
216
+ if (!S) continue;
217
+ let C = document.createTextNode("");
218
+ S.parentNode.replaceChild(C, S), a(C, _, m, h);
205
219
  }
206
220
  return {
207
- disposes: d,
208
- postMountHooks: f
221
+ disposes: m,
222
+ postMountHooks: h
209
223
  };
210
224
  }
211
225
  //#endregion
212
- export { v as _activateBindingsWithNodes, p as _ensureDelegatedEvent, m as _setDelegatedEvent, _ as activateBindings, h as activateDelegatedEvent, s as detectContext, g as isDelegableEvent, o as showWhen };
226
+ export { x as _activateBindingsWithNodes, g as _ensureDelegatedEvent, _ as _setDelegatedEvent, b as activateBindings, v as activateDelegatedEvent, u as detectContext, y as isDelegableEvent, l as showWhen };
213
227
 
214
228
  //# sourceMappingURL=bindings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bindings.js","names":[],"sources":["../../../../src/elur/template/bindings.ts"],"sourcesContent":["import { effect } from \"../reactivity.js\";\nimport type { ElurRef, TemplateBindingContext } from \"./types.js\";\nimport { activateNodeBinding } from \"./node-binding.js\";\nimport { queueDOMWrite } from \"./dom-write.js\";\nimport { isUrlAttrName, isExecutableAttrName, sanitizeUrl } from \"./sanitize.js\";\n\n// =============================================================================\n// --- show / hide ---\n// =============================================================================\n\n/** Toggles element visibility via `display: none` without unmounting. */\nexport function showWhen(el: HTMLElement, condition: boolean): void {\n if (!condition) {\n if (el.style.display !== \"none\") el.style.display = \"none\";\n } else {\n if (el.style.display === \"none\") el.style.display = \"\";\n }\n}\n\n// =============================================================================\n// --- Binding context ---\n// =============================================================================\n\nexport type BindingContext = TemplateBindingContext;\n\n/**\n * Determines the binding context (node, event, or attribute) for an interpolated\n * value based on the preceding template string.\n */\nexport function detectContext(prevString: string): BindingContext {\n const lastClose = prevString.lastIndexOf(\">\");\n const lastOpen = prevString.lastIndexOf(\"<\");\n\n if (lastOpen <= lastClose) {\n return { type: \"node\" };\n }\n\n const tagContent = prevString.slice(lastOpen + 1);\n\n const eqIdx = tagContent.lastIndexOf(\"=\");\n if (eqIdx === -1) {\n return { type: \"node\" };\n }\n\n const hadOpenQuote =\n tagContent.endsWith('\"') ||\n tagContent.endsWith(\"'\") ||\n tagContent[tagContent.length - 1] === '\"' ||\n tagContent[tagContent.length - 1] === \"'\";\n\n let startIdx = eqIdx - 1;\n while (startIdx >= 0 && /\\S/.test(tagContent[startIdx])) {\n startIdx--;\n }\n startIdx++;\n\n const fullAttr = tagContent.slice(startIdx, eqIdx);\n\n if (fullAttr[0] === \"@\") {\n const parts = fullAttr.slice(1).split(\".\");\n return {\n type: \"event\",\n eventName: parts[0],\n modifiers: parts.slice(1),\n hadOpenQuote,\n };\n }\n\n return {\n type: \"attr\",\n attrName: fullAttr,\n hadOpenQuote,\n // Precomputed once per template (compile time). Read as a cheap boolean\n // in the render/update hot path.\n url: isUrlAttrName(fullAttr),\n executable: isExecutableAttrName(fullAttr),\n };\n}\n\n// =============================================================================\n// --- Keyboard modifier map ---\n// =============================================================================\n\nconst KEY_MAP: Readonly<Record<string, string>> = {\n enter: \"Enter\",\n escape: \"Escape\",\n space: \" \",\n tab: \"Tab\",\n delete: \"Delete\",\n backspace: \"Backspace\",\n up: \"ArrowUp\",\n down: \"ArrowDown\",\n left: \"ArrowLeft\",\n right: \"ArrowRight\",\n};\n\n// =============================================================================\n// --- Global Event Delegation ---\n// =============================================================================\n\nconst DELEGABLE_EVENTS = new Set([\n \"click\", \"dblclick\", \"mousedown\", \"mouseup\",\n \"keydown\", \"keyup\", \"input\", \"change\", \"submit\"\n]);\nconst _delegatedRegistry = new Set<string>();\n\nfunction _globalEventHandlerCore(e: Event, propName: string, modsName: string): void {\n let target = e.target as Node | null;\n\n const originalStop = e.stopPropagation;\n let stopped = false;\n e.stopPropagation = () => {\n stopped = true;\n originalStop.call(e);\n };\n\n while (target && target !== document) {\n const handler = (target as any)[propName] as EventListener | undefined;\n if (handler) {\n const mods = (target as any)[modsName] as string[] | undefined;\n if (mods) {\n if (mods.includes(\"prevent\")) e.preventDefault();\n if (mods.includes(\"stop\")) e.stopPropagation();\n if (mods.includes(\"self\") && e.target !== target) {\n target = target.parentNode;\n continue;\n }\n if (\"key\" in e) {\n const ke = e as KeyboardEvent;\n let keyMatch = true;\n for (const mod of mods) {\n const mapped = KEY_MAP[mod];\n if (mapped !== undefined && ke.key !== mapped) { keyMatch = false; break; }\n if (!mapped && mod.length === 1 && ke.key.toLowerCase() !== mod) { keyMatch = false; break; }\n }\n if (!keyMatch) {\n target = target.parentNode;\n continue;\n }\n }\n }\n handler(e);\n if (stopped) break;\n }\n target = target.parentNode;\n }\n\n e.stopPropagation = originalStop;\n}\n\n// NOTE: entries are intentionally permanent — delegated listeners on document\n// live for the application lifetime.\nconst _delegatedHandlers = new Map<string, (e: Event) => void>();\n\n/**\n * Activates a delegated event on an element, using the same global registry\n * as mount-time bindings. Used by both `activateBindings` (mount) and the\n * hydrator to ensure consistent event delegation.\n *\n * @returns A dispose function that removes the handler from the element.\n */\nexport function _ensureDelegatedEvent(eventName: string): void {\n if (!_delegatedRegistry.has(eventName)) {\n const propName = `__elur_${eventName}`;\n const modsName = `__elur_${eventName}_mods`;\n const boundHandler = (e: Event) => _globalEventHandlerCore(e, propName, modsName);\n _delegatedHandlers.set(eventName, boundHandler);\n document.addEventListener(eventName, boundHandler);\n _delegatedRegistry.add(eventName);\n }\n}\n\nexport function _setDelegatedEvent(\n el: Element,\n eventName: string,\n modifiers: readonly string[],\n rawHandler: EventListener,\n): void {\n _ensureDelegatedEvent(eventName);\n const nodePropName = `__elur_${eventName}`;\n const nodeModsName = `__elur_${eventName}_mods`;\n (el as any)[nodePropName] = rawHandler;\n if (modifiers.length > 0) (el as any)[nodeModsName] = modifiers;\n}\n\nexport function activateDelegatedEvent(\n el: Element,\n eventName: string,\n modifiers: readonly string[],\n rawHandler: EventListener,\n): () => void {\n _setDelegatedEvent(el, eventName, modifiers, rawHandler);\n const nodePropName = `__elur_${eventName}`;\n const nodeModsName = `__elur_${eventName}_mods`;\n return () => {\n (el as any)[nodePropName] = null;\n (el as any)[nodeModsName] = null;\n };\n}\n\n/** Returns true if an event name is in the delegable set. */\nexport function isDelegableEvent(eventName: string): boolean {\n return DELEGABLE_EVENTS.has(eventName);\n}\n\n// =============================================================================\n// --- Binding activation ---\n// =============================================================================\n\n/** Activates all bindings on the cloned fragment. Returns dispose/postMount. */\nexport function activateBindings(\n fragment: DocumentFragment,\n contexts: BindingContext[],\n values: unknown[],\n pathMap: Array<{ nodeIndex: number; name?: string } | null>,\n): { disposes: Array<() => void>; postMountHooks: Array<() => void> } {\n // PHASE 1: READ — single-pass TreeWalker O(N)\n const resolvedNodes = new Array<Node | null>(contexts.length);\n\n let maxNodeIndex = -1;\n for (let i = 0; i < contexts.length; i++) {\n if (pathMap[i] && pathMap[i]!.nodeIndex > maxNodeIndex) {\n maxNodeIndex = pathMap[i]!.nodeIndex;\n }\n }\n\n const flatNodes = new Array<Node>(maxNodeIndex + 1);\n flatNodes[0] = fragment;\n if (maxNodeIndex > 0) {\n const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);\n let fi = 1;\n let currentNode: Node | null;\n while (fi <= maxNodeIndex && (currentNode = walker.nextNode())) {\n flatNodes[fi++] = currentNode;\n }\n }\n\n for (let i = 0; i < contexts.length; i++) {\n const info = pathMap[i];\n resolvedNodes[i] = info ? flatNodes[info.nodeIndex] : null;\n }\n\n // PHASE 2: MUTATE (delegated to _activateBindingsWithNodes)\n return _activateBindingsWithNodes(fragment, contexts, values, pathMap, resolvedNodes);\n}\n\n/**\n * Activates bindings using pre-resolved nodes — skips the TreeWalker phase.\n * Used by the compiler's __elurCompiledTemplate to eliminate the second TreeWalker.\n */\nexport function _activateBindingsWithNodes(\n _fragment: DocumentFragment,\n contexts: BindingContext[],\n values: unknown[],\n pathMap: Array<{ nodeIndex: number; name?: string } | null>,\n resolvedNodes: Array<Node | null>,\n): { disposes: Array<() => void>; postMountHooks: Array<() => void> } {\n const disposes: Array<() => void> = [];\n const postMountHooks: Array<() => void> = [];\n\n for (let i = 0; i < contexts.length; i++) {\n const ctx = contexts[i];\n const value = values[i];\n const info = pathMap[i];\n if (!info) continue;\n\n const el = resolvedNodes[i]!;\n\n // --- Events ---\n if (ctx.type === \"event\") {\n const eventName = info.name!;\n const rawHandler = value as EventListener;\n const mods = ctx.modifiers;\n\n const canDelegate =\n isDelegableEvent(eventName) &&\n !mods.includes(\"capture\") &&\n !mods.includes(\"once\") &&\n !mods.includes(\"passive\");\n\n if (canDelegate) {\n disposes.push(activateDelegatedEvent(el as Element, eventName, mods, rawHandler));\n } else {\n const listenerOpts: AddEventListenerOptions = {\n once: mods.includes(\"once\"),\n capture: mods.includes(\"capture\"),\n passive: mods.includes(\"passive\")\n };\n const handler = (e: Event) => {\n if (mods.includes(\"prevent\")) e.preventDefault();\n if (mods.includes(\"stop\")) e.stopPropagation();\n if (mods.includes(\"self\") && e.target !== e.currentTarget) return;\n rawHandler(e);\n };\n el.addEventListener(eventName, handler, listenerOpts);\n disposes.push(() => el.removeEventListener(eventName, handler, listenerOpts));\n }\n continue;\n }\n\n // --- Attributes ---\n if (ctx.type === \"attr\") {\n const attrName = info.name!;\n const element = el as Element;\n\n if (attrName === \"ref\") {\n (value as ElurRef<Element>).el = element;\n disposes.push(() => { (value as ElurRef<Element>).el = null; });\n continue;\n }\n\n if (attrName === \"show\" || attrName === \"hide\") {\n const htmlEl = element as HTMLElement;\n let originalDisplay: string | null = null;\n\n if (typeof value === \"function\") {\n let queued = false;\n let pendingVisible = false;\n let isFirstRun = true;\n\n const dispose = effect(() => {\n pendingVisible = Boolean((value as () => unknown)());\n const update = () => {\n queued = false;\n const shouldShow = attrName === \"show\" ? pendingVisible : !pendingVisible;\n if (originalDisplay === null) {\n originalDisplay = htmlEl.style.display || \"\";\n }\n htmlEl.style.display = shouldShow ? originalDisplay : \"none\";\n };\n\n if (isFirstRun) {\n isFirstRun = false;\n update();\n } else if (!queued) {\n queued = true;\n queueDOMWrite(update);\n }\n });\n disposes.push(dispose);\n } else {\n const shouldShow = attrName === \"show\" ? Boolean(value) : !Boolean(value);\n if (!shouldShow) htmlEl.style.display = \"none\";\n }\n continue;\n }\n\n // on*/srcdoc bindings are non-idiomatic in Elur (events use @click) and\n // turn an untrusted value into executable code. Warn the developer but\n // do not block — the attribute name is developer-authored.\n if (ctx.executable ?? isExecutableAttrName(attrName)) {\n console.warn(\n `[elur] Dynamic binding on executable attribute \"${attrName}\". Use @event for handlers; avoid binding untrusted values here.`,\n );\n }\n\n // Precomputed at compile time. Only URL attributes pay the sanitizer;\n // class/style/aria-*/data-*/custom attributes skip it entirely.\n const isUrl = ctx.url ?? isUrlAttrName(attrName);\n\n const isDomProp = (attrName === \"value\" || attrName === \"checked\" || attrName === \"selected\") && attrName in element;\n\n if (typeof value === \"function\") {\n let queued = false;\n let pendingValue: unknown;\n let isFirstRun = true;\n\n const dispose = effect(() => {\n pendingValue = (value as () => unknown)();\n const update = () => {\n queued = false;\n const v = pendingValue;\n if (isDomProp) {\n (element as any)[attrName] = v ?? \"\";\n } else if (v == null || v === false) {\n element.removeAttribute(attrName);\n } else {\n const s = String(v);\n element.setAttribute(attrName, isUrl ? sanitizeUrl(s) : s);\n }\n };\n\n if (isFirstRun) {\n isFirstRun = false;\n update();\n } else if (!queued) {\n queued = true;\n queueDOMWrite(update);\n }\n });\n disposes.push(dispose);\n } else {\n if (isDomProp) {\n (element as any)[attrName] = value ?? \"\";\n } else if (value != null && value !== false) {\n const s = String(value);\n element.setAttribute(attrName, isUrl ? sanitizeUrl(s) : s);\n }\n }\n continue;\n }\n\n // --- Nodes — delegate to node-binding.ts ---\n const originalAnchor = el as Comment;\n if (!originalAnchor) continue;\n\n const anchor = document.createTextNode(\"\");\n originalAnchor.parentNode!.replaceChild(anchor, originalAnchor);\n\n activateNodeBinding(anchor, value, disposes, postMountHooks);\n }\n\n return { disposes, postMountHooks };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bindings.js","names":[],"sources":["../../../../src/elur/template/bindings.ts"],"sourcesContent":["import { effect, Signal, _bindSignal } from \"../reactivity.js\";\nimport type { ElurRef, TemplateBindingContext } from \"./types.js\";\nimport { isDerivedBinding } from \"./types.js\";\nimport { activateNodeBinding } from \"./node-binding.js\";\nimport { queueDOMWrite } from \"./dom-write.js\";\nimport { isUrlAttrName, isExecutableAttrName, sanitizeUrl } from \"./sanitize.js\";\n\n// =============================================================================\n// --- show / hide ---\n// =============================================================================\n\n/** Toggles element visibility via `display: none` without unmounting. */\nexport function showWhen(el: HTMLElement, condition: boolean): void {\n if (!condition) {\n if (el.style.display !== \"none\") el.style.display = \"none\";\n } else {\n if (el.style.display === \"none\") el.style.display = \"\";\n }\n}\n\n// =============================================================================\n// --- Binding context ---\n// =============================================================================\n\nexport type BindingContext = TemplateBindingContext;\n\n/**\n * Determines the binding context (node, event, or attribute) for an interpolated\n * value based on the preceding template string.\n */\nexport function detectContext(prevString: string): BindingContext {\n const lastClose = prevString.lastIndexOf(\">\");\n const lastOpen = prevString.lastIndexOf(\"<\");\n\n if (lastOpen <= lastClose) {\n return { type: \"node\" };\n }\n\n const tagContent = prevString.slice(lastOpen + 1);\n\n const eqIdx = tagContent.lastIndexOf(\"=\");\n if (eqIdx === -1) {\n return { type: \"node\" };\n }\n\n const hadOpenQuote =\n tagContent.endsWith('\"') ||\n tagContent.endsWith(\"'\") ||\n tagContent[tagContent.length - 1] === '\"' ||\n tagContent[tagContent.length - 1] === \"'\";\n\n let startIdx = eqIdx - 1;\n while (startIdx >= 0 && /\\S/.test(tagContent[startIdx])) {\n startIdx--;\n }\n startIdx++;\n\n const fullAttr = tagContent.slice(startIdx, eqIdx);\n\n if (fullAttr[0] === \"@\") {\n const parts = fullAttr.slice(1).split(\".\");\n return {\n type: \"event\",\n eventName: parts[0],\n modifiers: parts.slice(1),\n hadOpenQuote,\n };\n }\n\n return {\n type: \"attr\",\n attrName: fullAttr,\n hadOpenQuote,\n // Precomputed once per template (compile time). Read as a cheap boolean\n // in the render/update hot path.\n url: isUrlAttrName(fullAttr),\n executable: isExecutableAttrName(fullAttr),\n };\n}\n\n// =============================================================================\n// --- Keyboard modifier map ---\n// =============================================================================\n\nconst KEY_MAP: Readonly<Record<string, string>> = {\n enter: \"Enter\",\n escape: \"Escape\",\n space: \" \",\n tab: \"Tab\",\n delete: \"Delete\",\n backspace: \"Backspace\",\n up: \"ArrowUp\",\n down: \"ArrowDown\",\n left: \"ArrowLeft\",\n right: \"ArrowRight\",\n};\n\n// =============================================================================\n// --- Global Event Delegation ---\n// =============================================================================\n\nconst DELEGABLE_EVENTS = new Set([\n \"click\", \"dblclick\", \"mousedown\", \"mouseup\",\n \"keydown\", \"keyup\", \"input\", \"change\", \"submit\"\n]);\nconst _delegatedRegistry = new Set<string>();\n\nfunction _globalEventHandlerCore(e: Event, propName: string, modsName: string): void {\n let target = e.target as Node | null;\n\n const originalStop = e.stopPropagation;\n let stopped = false;\n e.stopPropagation = () => {\n stopped = true;\n originalStop.call(e);\n };\n\n while (target && target !== document) {\n const handler = (target as any)[propName] as EventListener | undefined;\n if (handler) {\n const mods = (target as any)[modsName] as string[] | undefined;\n if (mods) {\n if (mods.includes(\"prevent\")) e.preventDefault();\n if (mods.includes(\"stop\")) e.stopPropagation();\n if (mods.includes(\"self\") && e.target !== target) {\n target = target.parentNode;\n continue;\n }\n if (\"key\" in e) {\n const ke = e as KeyboardEvent;\n let keyMatch = true;\n for (const mod of mods) {\n const mapped = KEY_MAP[mod];\n if (mapped !== undefined && ke.key !== mapped) { keyMatch = false; break; }\n if (!mapped && mod.length === 1 && ke.key.toLowerCase() !== mod) { keyMatch = false; break; }\n }\n if (!keyMatch) {\n target = target.parentNode;\n continue;\n }\n }\n }\n handler(e);\n if (stopped) break;\n }\n target = target.parentNode;\n }\n\n e.stopPropagation = originalStop;\n}\n\n// NOTE: entries are intentionally permanent — delegated listeners on document\n// live for the application lifetime.\nconst _delegatedHandlers = new Map<string, (e: Event) => void>();\n\n/**\n * Activates a delegated event on an element, using the same global registry\n * as mount-time bindings. Used by both `activateBindings` (mount) and the\n * hydrator to ensure consistent event delegation.\n *\n * @returns A dispose function that removes the handler from the element.\n */\nexport function _ensureDelegatedEvent(eventName: string): void {\n if (!_delegatedRegistry.has(eventName)) {\n const propName = `__elur_${eventName}`;\n const modsName = `__elur_${eventName}_mods`;\n const boundHandler = (e: Event) => _globalEventHandlerCore(e, propName, modsName);\n _delegatedHandlers.set(eventName, boundHandler);\n document.addEventListener(eventName, boundHandler);\n _delegatedRegistry.add(eventName);\n }\n}\n\nexport function _setDelegatedEvent(\n el: Element,\n eventName: string,\n modifiers: readonly string[],\n rawHandler: EventListener,\n): void {\n _ensureDelegatedEvent(eventName);\n const nodePropName = `__elur_${eventName}`;\n const nodeModsName = `__elur_${eventName}_mods`;\n (el as any)[nodePropName] = rawHandler;\n if (modifiers.length > 0) (el as any)[nodeModsName] = modifiers;\n}\n\nexport function activateDelegatedEvent(\n el: Element,\n eventName: string,\n modifiers: readonly string[],\n rawHandler: EventListener,\n): () => void {\n _setDelegatedEvent(el, eventName, modifiers, rawHandler);\n const nodePropName = `__elur_${eventName}`;\n const nodeModsName = `__elur_${eventName}_mods`;\n return () => {\n (el as any)[nodePropName] = null;\n (el as any)[nodeModsName] = null;\n };\n}\n\n/** Returns true if an event name is in the delegable set. */\nexport function isDelegableEvent(eventName: string): boolean {\n return DELEGABLE_EVENTS.has(eventName);\n}\n\n// =============================================================================\n// --- Binding activation ---\n// =============================================================================\n\n/** Activates all bindings on the cloned fragment. Returns dispose/postMount. */\nexport function activateBindings(\n fragment: DocumentFragment,\n contexts: BindingContext[],\n values: unknown[],\n pathMap: Array<{ nodeIndex: number; name?: string } | null>,\n): { disposes: Array<() => void>; postMountHooks: Array<() => void> } {\n // PHASE 1: READ — single-pass TreeWalker O(N)\n const resolvedNodes = new Array<Node | null>(contexts.length);\n\n let maxNodeIndex = -1;\n for (let i = 0; i < contexts.length; i++) {\n if (pathMap[i] && pathMap[i]!.nodeIndex > maxNodeIndex) {\n maxNodeIndex = pathMap[i]!.nodeIndex;\n }\n }\n\n const flatNodes = new Array<Node>(maxNodeIndex + 1);\n flatNodes[0] = fragment;\n if (maxNodeIndex > 0) {\n const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);\n let fi = 1;\n let currentNode: Node | null;\n while (fi <= maxNodeIndex && (currentNode = walker.nextNode())) {\n flatNodes[fi++] = currentNode;\n }\n }\n\n for (let i = 0; i < contexts.length; i++) {\n const info = pathMap[i];\n resolvedNodes[i] = info ? flatNodes[info.nodeIndex] : null;\n }\n\n // PHASE 2: MUTATE (delegated to _activateBindingsWithNodes)\n return _activateBindingsWithNodes(fragment, contexts, values, pathMap, resolvedNodes);\n}\n\n/**\n * Activates bindings using pre-resolved nodes — skips the TreeWalker phase.\n * Used by the compiler's __elurCompiledTemplate to eliminate the second TreeWalker.\n */\nexport function _activateBindingsWithNodes(\n _fragment: DocumentFragment,\n contexts: BindingContext[],\n values: unknown[],\n pathMap: Array<{ nodeIndex: number; name?: string } | null>,\n resolvedNodes: Array<Node | null>,\n): { disposes: Array<() => void>; postMountHooks: Array<() => void> } {\n const disposes: Array<() => void> = [];\n const postMountHooks: Array<() => void> = [];\n\n for (let i = 0; i < contexts.length; i++) {\n const ctx = contexts[i];\n let value = values[i];\n // C.7 T2: desenvolver el pack derivado a getter — cubre todos los\n // paths aguas abajo (attr, show/hide, prop, etc.) con tracking\n // dinámico — semántica idéntica al getter genérico.\n if (isDerivedBinding(value)) value = value.get;\n const info = pathMap[i];\n if (!info) continue;\n\n const el = resolvedNodes[i]!;\n\n // --- Events ---\n if (ctx.type === \"event\") {\n const eventName = info.name!;\n const rawHandler = value as EventListener;\n const mods = ctx.modifiers;\n\n const canDelegate =\n isDelegableEvent(eventName) &&\n !mods.includes(\"capture\") &&\n !mods.includes(\"once\") &&\n !mods.includes(\"passive\");\n\n if (canDelegate) {\n disposes.push(activateDelegatedEvent(el as Element, eventName, mods, rawHandler));\n } else {\n const listenerOpts: AddEventListenerOptions = {\n once: mods.includes(\"once\"),\n capture: mods.includes(\"capture\"),\n passive: mods.includes(\"passive\")\n };\n const handler = (e: Event) => {\n if (mods.includes(\"prevent\")) e.preventDefault();\n if (mods.includes(\"stop\")) e.stopPropagation();\n if (mods.includes(\"self\") && e.target !== e.currentTarget) return;\n rawHandler(e);\n };\n el.addEventListener(eventName, handler, listenerOpts);\n disposes.push(() => el.removeEventListener(eventName, handler, listenerOpts));\n }\n continue;\n }\n\n // --- Attributes ---\n if (ctx.type === \"attr\") {\n const attrName = info.name!;\n const element = el as Element;\n\n if (attrName === \"ref\") {\n (value as ElurRef<Element>).el = element;\n disposes.push(() => { (value as ElurRef<Element>).el = null; });\n continue;\n }\n\n if (attrName === \"show\" || attrName === \"hide\") {\n const htmlEl = element as HTMLElement;\n let originalDisplay: string | null = null;\n\n if (typeof value === \"function\") {\n let queued = false;\n let pendingVisible = false;\n let isFirstRun = true;\n\n const dispose = effect(() => {\n pendingVisible = Boolean((value as () => unknown)());\n const update = () => {\n queued = false;\n const shouldShow = attrName === \"show\" ? pendingVisible : !pendingVisible;\n if (originalDisplay === null) {\n originalDisplay = htmlEl.style.display || \"\";\n }\n htmlEl.style.display = shouldShow ? originalDisplay : \"none\";\n };\n\n if (isFirstRun) {\n isFirstRun = false;\n update();\n } else if (!queued) {\n queued = true;\n queueDOMWrite(update);\n }\n });\n disposes.push(dispose);\n } else {\n const shouldShow = attrName === \"show\" ? Boolean(value) : !Boolean(value);\n if (!shouldShow) htmlEl.style.display = \"none\";\n }\n continue;\n }\n\n // on*/srcdoc bindings are non-idiomatic in Elur (events use @click) and\n // turn an untrusted value into executable code. Warn the developer but\n // do not block — the attribute name is developer-authored.\n if (ctx.executable ?? isExecutableAttrName(attrName)) {\n console.warn(\n `[elur] Dynamic binding on executable attribute \"${attrName}\". Use @event for handlers; avoid binding untrusted values here.`,\n );\n }\n\n // Precomputed at compile time. Only URL attributes pay the sanitizer;\n // class/style/aria-*/data-*/custom attributes skip it entirely.\n const isUrl = ctx.url ?? isUrlAttrName(attrName);\n\n const isDomProp = (attrName === \"value\" || attrName === \"checked\" || attrName === \"selected\") && attrName in element;\n\n // C.6 T1: la señal viaja como valor — edge directa, sin getter.\n if (value instanceof Signal) {\n disposes.push(_bindSignal(value, (v) => {\n if (isDomProp) {\n (element as any)[attrName] = v ?? \"\";\n } else if (v == null || v === false) {\n element.removeAttribute(attrName);\n } else {\n const s = String(v);\n element.setAttribute(attrName, isUrl ? sanitizeUrl(s) : s);\n }\n }));\n continue;\n }\n\n if (typeof value === \"function\") {\n let queued = false;\n let pendingValue: unknown;\n let isFirstRun = true;\n\n const dispose = effect(() => {\n pendingValue = (value as () => unknown)();\n const update = () => {\n queued = false;\n const v = pendingValue;\n if (isDomProp) {\n (element as any)[attrName] = v ?? \"\";\n } else if (v == null || v === false) {\n element.removeAttribute(attrName);\n } else {\n const s = String(v);\n element.setAttribute(attrName, isUrl ? sanitizeUrl(s) : s);\n }\n };\n\n if (isFirstRun) {\n isFirstRun = false;\n update();\n } else if (!queued) {\n queued = true;\n queueDOMWrite(update);\n }\n });\n disposes.push(dispose);\n } else {\n if (isDomProp) {\n (element as any)[attrName] = value ?? \"\";\n } else if (value != null && value !== false) {\n const s = String(value);\n element.setAttribute(attrName, isUrl ? sanitizeUrl(s) : s);\n }\n }\n continue;\n }\n\n // --- Nodes — delegate to node-binding.ts ---\n const originalAnchor = el as Comment;\n if (!originalAnchor) continue;\n\n const anchor = document.createTextNode(\"\");\n originalAnchor.parentNode!.replaceChild(anchor, originalAnchor);\n\n activateNodeBinding(anchor, value, disposes, postMountHooks);\n }\n\n return { disposes, postMountHooks };\n}\n"],"mappings":"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"}
@@ -1,5 +1 @@
1
- /**
2
- * Queues a DOM mutation to run in the next microtask.
3
- * Avoids Layout Thrashing by grouping multiple writes into a single frame.
4
- */
5
- export declare function queueDOMWrite(task: () => void): void;
1
+ export * from "../next-2/dom-write.js";
@@ -1,5 +1 @@
1
- /**
2
- * Queues a DOM mutation to run in the next microtask.
3
- * Avoids Layout Thrashing by grouping multiple writes into a single frame.
4
- */
5
- export declare function queueDOMWrite(task: () => void): void;
1
+ export * from "../next-2/dom-write.js";
@@ -1,2 +1,2 @@
1
- const e=require(`../../signals.cjs`),t=require(`./types.cjs`),n=require(`../../lifecycle.cjs`),r=require(`../../context.cjs`),i=require(`./mount-helpers.cjs`);function a(a,o){return{__isElurTemplate:!0,mount(e){let t=typeof e==`string`?document.querySelector(e)??document.body:e;return{unmount:this._render(t,null)}},_render(s,c){let l=document.createComment(t.COMMENT.ERROR_BOUNDARY);s.insertBefore(l,c);let u=null,d=!1,f=!1,p,m=!1,h=t=>{let r=l.parentNode;if(!r)return;let a;try{a=typeof o==`function`&&!n.isElurComponent(o)?o(t):o}catch(e){console.error(`[elur] Error boundary fallback threw while producing the fallback UI:`,e),u=_(r,c);return}e._pushErrorHandler(g);try{u=n.isElurComponent(a)?i._mountComponentSilent(a,r,c):a._render(r,c)}catch(e){console.error(`[elur] Error boundary fallback threw during render:`,e),u?.(),u=_(r,c)}finally{e._popErrorHandler()}},g=e=>{console.error(`[elur] Error boundary fallback threw during a reactive update:`,e),u?.(),u=null;let t=l.parentNode;t&&(u=_(t,c))},_=(e,t)=>{let n=document.createElement(`div`);return n.setAttribute(`data-elur-error-boundary`,`fallback-failed`),n.textContent=`[elur] Error boundary fallback failed to render.`,e.insertBefore(n,t),()=>n.remove()};e._pushErrorHandler(e=>{d||(d=!0,f?(u?.(),u=null,h(e)):(p=e,m=!0))});try{if(n.isElurComponent(a)){r._pushComponentContext();try{try{a.onInit?.()}catch(e){if(a.onError)a.onError(e);else throw e}u=a.render()._render(s,c)}finally{r._popComponentContext()}if(!d)try{let e=a.onMount?.(),t=u;u=()=>{try{a.onUnmount?.()}catch{}if(typeof e==`function`)try{e()}catch{}t?.()}}catch(e){if(a.onError)a.onError(e);else throw e}}else u=a._render(s,c)}catch(e){d=!0,u?.(),u=null,p=e,m=!0}finally{e._popErrorHandler(),f=!0}return m&&(u?.(),u=null,h(p)),()=>{u?.(),l.remove()}}}}exports.createErrorBoundary=a;
1
+ const e=require(`../next-2/reactivity.cjs`),t=require(`./types.cjs`),n=require(`../../lifecycle.cjs`),r=require(`../../context.cjs`),i=require(`../next-2/mount-helpers.cjs`);function a(a,o){return{__isElurTemplate:!0,mount(e){let t=typeof e==`string`?document.querySelector(e)??document.body:e;return{unmount:this._render(t,null)}},_render(s,c){let l=document.createComment(t.COMMENT.ERROR_BOUNDARY);s.insertBefore(l,c);let u=null,d=()=>{u?.()},f=!1,p=!1,m,h=!1,g=t=>{let r=l.parentNode;if(!r)return;let a;try{a=typeof o==`function`&&!n.isElurComponent(o)?o(t):o}catch(e){console.error(`[elur] Error boundary fallback threw while producing the fallback UI:`,e),u=v(r,c);return}e._pushErrorHandler(_);try{u=n.isElurComponent(a)?i._mountComponentSilent(a,r,c):a._render(r,c)}catch(e){console.error(`[elur] Error boundary fallback threw during render:`,e),u?.(),u=v(r,c)}finally{e._popErrorHandler()}},_=e=>{console.error(`[elur] Error boundary fallback threw during a reactive update:`,e),u?.(),u=null;let t=l.parentNode;t&&(u=v(t,c))},v=(e,t)=>{let n=document.createElement(`div`);return n.setAttribute(`data-elur-error-boundary`,`fallback-failed`),n.textContent=`[elur] Error boundary fallback failed to render.`,e.insertBefore(n,t),()=>n.remove()};e._pushErrorHandler(e=>{f||(f=!0,p?(u?.(),u=null,g(e)):(m=e,h=!0))});try{i._postMountScopeSub(()=>{if(n.isElurComponent(a)){r._pushComponentContext();try{try{a.onInit?.()}catch(e){if(a.onError)a.onError(e);else throw e}u=a.render()._render(s,c)}finally{r._popComponentContext()}f||i._deferOnMount(()=>{try{let e=a.onMount?.(),t=u;u=()=>{try{a.onUnmount?.()}catch{}if(typeof e==`function`)try{e()}catch{}t?.()}}catch(e){if(a.onError)a.onError(e);else throw e}})}else u=a._render(s,c)})}catch(e){f=!0,d(),u=null,m=e,h=!0}finally{e._popErrorHandler(),p=!0}return h&&(d(),u=null,g(m)),()=>{u?.(),l.remove()}}}}exports.createErrorBoundary=a;
2
2
  //# sourceMappingURL=error-boundary.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-boundary.cjs","names":[],"sources":["../../../../src/elur/template/error-boundary.ts"],"sourcesContent":["import { _pushErrorHandler, _popErrorHandler } from \"../reactivity.js\";\nimport { isElurComponent } from \"../lifecycle.js\";\nimport type { ElurComponent } from \"../lifecycle.js\";\nimport { _pushComponentContext, _popComponentContext } from \"../context.js\";\nimport type { ElurTemplate, ElurMountHandle, ErrorFallback } from \"./types.js\";\nimport { COMMENT } from \"./types.js\";\nimport { _mountComponentSilent } from \"./mount-helpers.js\";\n\n// =============================================================================\n// --- Error Boundary ---\n// =============================================================================\n\n/**\n * Wraps `content` in an error boundary. If rendering or a reactive update\n * throws, the boundary tears down the broken subtree and renders `fallback`.\n */\nexport function createErrorBoundary(\n content: ElurTemplate | ElurComponent,\n fallback: ErrorFallback\n): ElurTemplate {\n return {\n __isElurTemplate: true as const,\n\n mount(container: Element | string): ElurMountHandle {\n const el =\n typeof container === \"string\"\n ? (document.querySelector(container) ?? document.body)\n : container;\n const cleanup = this._render(el, null);\n return { unmount: cleanup };\n },\n\n _render(parent: Node, before: Node | null): () => void {\n const marker = document.createComment(COMMENT.ERROR_BOUNDARY);\n parent.insertBefore(marker, before);\n\n let activeCleanup: (() => void) | null = null;\n let errored = false;\n let initialRenderDone = false;\n let deferredError: unknown = undefined;\n let hasDeferredError = false;\n\n // Renders the fallback outside the error handler window.\n // Uses marker.parentNode (not captured `parent`) because `parent` may be\n // a stale DocumentFragment that was already flushed to the live DOM.\n const renderFallback = (err: unknown): void => {\n const liveParent = marker.parentNode;\n if (!liveParent) return;\n\n let fb: ElurTemplate | ElurComponent;\n try {\n fb =\n typeof fallback === \"function\" && !isElurComponent(fallback as object)\n ? (fallback as (err: unknown) => ElurTemplate | ElurComponent)(err)\n : (fallback as ElurTemplate | ElurComponent);\n } catch (e) {\n console.error(\"[elur] Error boundary fallback threw while producing the fallback UI:\", e);\n activeCleanup = renderBrokenFallback(liveParent, before);\n return;\n }\n\n // Capture reactive errors from effects created inside the fallback.\n _pushErrorHandler(fallbackReactiveErrorHandler);\n try {\n if (isElurComponent(fb)) {\n activeCleanup = _mountComponentSilent(fb, liveParent, before);\n } else {\n activeCleanup = fb._render(liveParent, before);\n }\n } catch (e) {\n console.error(\"[elur] Error boundary fallback threw during render:\", e);\n activeCleanup?.();\n activeCleanup = renderBrokenFallback(liveParent, before);\n } finally {\n _popErrorHandler();\n }\n };\n\n const fallbackReactiveErrorHandler = (e: unknown): void => {\n console.error(\"[elur] Error boundary fallback threw during a reactive update:\", e);\n activeCleanup?.();\n activeCleanup = null;\n const liveParent = marker.parentNode;\n if (liveParent) {\n activeCleanup = renderBrokenFallback(liveParent, before);\n }\n };\n\n const renderBrokenFallback = (liveParent: Node, before: Node | null): (() => void) => {\n const el = document.createElement(\"div\");\n el.setAttribute(\"data-elur-error-boundary\", \"fallback-failed\");\n el.textContent = \"[elur] Error boundary fallback failed to render.\";\n liveParent.insertBefore(el, before);\n return () => el.remove();\n };\n\n // Called by effects inside `content` when they throw\n const handleReactiveError = (err: unknown): void => {\n if (errored) return;\n errored = true;\n if (initialRenderDone) {\n activeCleanup?.();\n activeCleanup = null;\n renderFallback(err);\n } else {\n deferredError = err;\n hasDeferredError = true;\n }\n };\n\n _pushErrorHandler(handleReactiveError);\n try {\n if (isElurComponent(content)) {\n _pushComponentContext();\n try {\n try { content.onInit?.(); } catch (e) {\n if (content.onError) content.onError(e); else throw e;\n }\n activeCleanup = content.render()._render(parent, before);\n } finally {\n _popComponentContext();\n }\n if (!errored) {\n try {\n const ret = content.onMount?.();\n const prev = activeCleanup;\n activeCleanup = () => {\n try { content.onUnmount?.(); } catch { /* ignore */ }\n if (typeof ret === \"function\") try { ret(); } catch { /* ignore */ }\n prev?.();\n };\n } catch (e) {\n if (content.onError) content.onError(e); else throw e;\n }\n }\n } else {\n activeCleanup = content._render(parent, before);\n }\n } catch (err) {\n errored = true;\n activeCleanup?.();\n activeCleanup = null;\n deferredError = err;\n hasDeferredError = true;\n } finally {\n _popErrorHandler();\n initialRenderDone = true;\n }\n\n if (hasDeferredError) {\n activeCleanup?.();\n activeCleanup = null;\n renderFallback(deferredError);\n }\n\n return () => {\n activeCleanup?.();\n marker.remove();\n };\n },\n };\n}\n"],"mappings":"+JAgBA,SAAgB,EACZ,EACA,EACY,CACZ,MAAO,CACH,iBAAkB,GAElB,MAAM,EAA8C,CAChD,IAAM,EACF,OAAO,GAAc,SACd,SAAS,cAAc,EAAU,EAAI,SAAS,KAC/C,EAEV,MAAO,CAAE,QADO,KAAK,QAAQ,EAAI,KAAK,CACX,EAG/B,QAAQ,EAAc,EAAiC,CACnD,IAAM,EAAS,SAAS,cAAc,EAAA,QAAQ,eAAe,CAC7D,EAAO,aAAa,EAAQ,EAAO,CAEnC,IAAI,EAAqC,KACrC,EAAU,GACV,EAAoB,GACpB,EACA,EAAmB,GAKjB,EAAkB,GAAuB,CAC3C,IAAM,EAAa,EAAO,WAC1B,GAAI,CAAC,EAAY,OAEjB,IAAI,EACJ,GAAI,CACA,EACI,OAAO,GAAa,YAAc,CAAC,EAAA,gBAAgB,EAAmB,CAC/D,EAA4D,EAAI,CAChE,QACN,EAAG,CACR,QAAQ,MAAM,wEAAyE,EAAE,CACzF,EAAgB,EAAqB,EAAY,EAAO,CACxD,OAIJ,EAAA,kBAAkB,EAA6B,CAC/C,GAAI,CACA,AAGI,EAHA,EAAA,gBAAgB,EAAG,CACH,EAAA,sBAAsB,EAAI,EAAY,EAAO,CAE7C,EAAG,QAAQ,EAAY,EAAO,OAE7C,EAAG,CACR,QAAQ,MAAM,sDAAuD,EAAE,CACvE,KAAiB,CACjB,EAAgB,EAAqB,EAAY,EAAO,QAClD,CACN,EAAA,kBAAkB,GAIpB,EAAgC,GAAqB,CACvD,QAAQ,MAAM,iEAAkE,EAAE,CAClF,KAAiB,CACjB,EAAgB,KAChB,IAAM,EAAa,EAAO,WACtB,IACA,EAAgB,EAAqB,EAAY,EAAO,GAI1D,GAAwB,EAAkB,IAAsC,CAClF,IAAM,EAAK,SAAS,cAAc,MAAM,CAIxC,OAHA,EAAG,aAAa,2BAA4B,kBAAkB,CAC9D,EAAG,YAAc,mDACjB,EAAW,aAAa,EAAI,EAAO,KACtB,EAAG,QAAQ,EAiB5B,EAAA,kBAb6B,GAAuB,CAC5C,IACJ,EAAU,GACN,GACA,KAAiB,CACjB,EAAgB,KAChB,EAAe,EAAI,GAEnB,EAAgB,EAChB,EAAmB,MAIW,CACtC,GAAI,CACA,GAAI,EAAA,gBAAgB,EAAQ,CAAE,CAC1B,EAAA,uBAAuB,CACvB,GAAI,CACA,GAAI,CAAE,EAAQ,UAAU,OAAW,EAAG,CAClC,GAAI,EAAQ,QAAS,EAAQ,QAAQ,EAAE,MAAO,MAAM,EAExD,EAAgB,EAAQ,QAAQ,CAAC,QAAQ,EAAQ,EAAO,QAClD,CACN,EAAA,sBAAsB,CAE1B,GAAI,CAAC,EACD,GAAI,CACA,IAAM,EAAM,EAAQ,WAAW,CACzB,EAAO,EACb,MAAsB,CAClB,GAAI,CAAE,EAAQ,aAAa,MAAU,EACrC,GAAI,OAAO,GAAQ,WAAY,GAAI,CAAE,GAAK,MAAU,EACpD,KAAQ,QAEP,EAAG,CACR,GAAI,EAAQ,QAAS,EAAQ,QAAQ,EAAE,MAAO,MAAM,QAI5D,EAAgB,EAAQ,QAAQ,EAAQ,EAAO,OAE9C,EAAK,CACV,EAAU,GACV,KAAiB,CACjB,EAAgB,KAChB,EAAgB,EAChB,EAAmB,UACb,CACN,EAAA,kBAAkB,CAClB,EAAoB,GASxB,OANI,IACA,KAAiB,CACjB,EAAgB,KAChB,EAAe,EAAc,MAGpB,CACT,KAAiB,CACjB,EAAO,QAAQ,GAG1B"}
1
+ {"version":3,"file":"error-boundary.cjs","names":[],"sources":["../../../../src/elur/template/error-boundary.ts"],"sourcesContent":["import { _pushErrorHandler, _popErrorHandler } from \"../reactivity.js\";\nimport { isElurComponent } from \"../lifecycle.js\";\nimport type { ElurComponent } from \"../lifecycle.js\";\nimport { _pushComponentContext, _popComponentContext } from \"../context.js\";\nimport type { ElurTemplate, ElurMountHandle, ErrorFallback } from \"./types.js\";\nimport { COMMENT } from \"./types.js\";\nimport { _deferOnMount, _mountComponentSilent, _postMountScopeSub } from \"./mount-helpers.js\";\n\n// =============================================================================\n// --- Error Boundary ---\n// =============================================================================\n\n/**\n * Wraps `content` in an error boundary. If rendering or a reactive update\n * throws, the boundary tears down the broken subtree and renders `fallback`.\n */\nexport function createErrorBoundary(\n content: ElurTemplate | ElurComponent,\n fallback: ErrorFallback\n): ElurTemplate {\n return {\n __isElurTemplate: true as const,\n\n mount(container: Element | string): ElurMountHandle {\n const el =\n typeof container === \"string\"\n ? (document.querySelector(container) ?? document.body)\n : container;\n const cleanup = this._render(el, null);\n return { unmount: cleanup };\n },\n\n _render(parent: Node, before: Node | null): () => void {\n const marker = document.createComment(COMMENT.ERROR_BOUNDARY);\n parent.insertBefore(marker, before);\n\n let activeCleanup: (() => void) | null = null;\n const runActive = (): void => { activeCleanup?.(); };\n let errored = false;\n let initialRenderDone = false;\n let deferredError: unknown = undefined;\n let hasDeferredError = false;\n\n // Renders the fallback outside the error handler window.\n // Uses marker.parentNode (not captured `parent`) because `parent` may be\n // a stale DocumentFragment that was already flushed to the live DOM.\n const renderFallback = (err: unknown): void => {\n const liveParent = marker.parentNode;\n if (!liveParent) return;\n\n let fb: ElurTemplate | ElurComponent;\n try {\n fb =\n typeof fallback === \"function\" && !isElurComponent(fallback as object)\n ? (fallback as (err: unknown) => ElurTemplate | ElurComponent)(err)\n : (fallback as ElurTemplate | ElurComponent);\n } catch (e) {\n console.error(\"[elur] Error boundary fallback threw while producing the fallback UI:\", e);\n activeCleanup = renderBrokenFallback(liveParent, before);\n return;\n }\n\n // Capture reactive errors from effects created inside the fallback.\n _pushErrorHandler(fallbackReactiveErrorHandler);\n try {\n if (isElurComponent(fb)) {\n activeCleanup = _mountComponentSilent(fb, liveParent, before);\n } else {\n activeCleanup = fb._render(liveParent, before);\n }\n } catch (e) {\n console.error(\"[elur] Error boundary fallback threw during render:\", e);\n activeCleanup?.();\n activeCleanup = renderBrokenFallback(liveParent, before);\n } finally {\n _popErrorHandler();\n }\n };\n\n const fallbackReactiveErrorHandler = (e: unknown): void => {\n console.error(\"[elur] Error boundary fallback threw during a reactive update:\", e);\n activeCleanup?.();\n activeCleanup = null;\n const liveParent = marker.parentNode;\n if (liveParent) {\n activeCleanup = renderBrokenFallback(liveParent, before);\n }\n };\n\n const renderBrokenFallback = (liveParent: Node, before: Node | null): (() => void) => {\n const el = document.createElement(\"div\");\n el.setAttribute(\"data-elur-error-boundary\", \"fallback-failed\");\n el.textContent = \"[elur] Error boundary fallback failed to render.\";\n liveParent.insertBefore(el, before);\n return () => el.remove();\n };\n\n // Called by effects inside `content` when they throw\n const handleReactiveError = (err: unknown): void => {\n if (errored) return;\n errored = true;\n if (initialRenderDone) {\n activeCleanup?.();\n activeCleanup = null;\n renderFallback(err);\n } else {\n deferredError = err;\n hasDeferredError = true;\n }\n };\n\n _pushErrorHandler(handleReactiveError);\n try {\n // Sub-cola de onMount: si el contenido lanza, sus hooks\n // diferidos se descartan; si no, se fusionan a la cola del\n // render externo y corren post-commit.\n _postMountScopeSub(() => {\n if (isElurComponent(content)) {\n _pushComponentContext();\n try {\n try { content.onInit?.(); } catch (e) {\n if (content.onError) content.onError(e); else throw e;\n }\n activeCleanup = content.render()._render(parent, before);\n } finally {\n _popComponentContext();\n }\n if (!errored) {\n _deferOnMount(() => {\n try {\n const ret = content.onMount?.();\n const prev = activeCleanup;\n activeCleanup = () => {\n try { content.onUnmount?.(); } catch { /* ignore */ }\n if (typeof ret === \"function\") try { ret(); } catch { /* ignore */ }\n prev?.();\n };\n } catch (e) {\n if (content.onError) content.onError(e); else throw e;\n }\n });\n }\n } else {\n activeCleanup = content._render(parent, before);\n }\n });\n } catch (err) {\n errored = true;\n runActive();\n activeCleanup = null;\n deferredError = err;\n hasDeferredError = true;\n } finally {\n _popErrorHandler();\n initialRenderDone = true;\n }\n\n if (hasDeferredError) {\n runActive();\n activeCleanup = null;\n renderFallback(deferredError);\n }\n\n return () => {\n activeCleanup?.();\n marker.remove();\n };\n },\n };\n}\n"],"mappings":"8KAgBA,SAAgB,EACZ,EACA,EACY,CACZ,MAAO,CACH,iBAAkB,GAElB,MAAM,EAA8C,CAChD,IAAM,EACF,OAAO,GAAc,SACd,SAAS,cAAc,EAAU,EAAI,SAAS,KAC/C,EAEV,MAAO,CAAE,QADO,KAAK,QAAQ,EAAI,KAAK,CACX,EAG/B,QAAQ,EAAc,EAAiC,CACnD,IAAM,EAAS,SAAS,cAAc,EAAA,QAAQ,eAAe,CAC7D,EAAO,aAAa,EAAQ,EAAO,CAEnC,IAAI,EAAqC,KACnC,MAAwB,CAAE,KAAiB,EAC7C,EAAU,GACV,EAAoB,GACpB,EACA,EAAmB,GAKjB,EAAkB,GAAuB,CAC3C,IAAM,EAAa,EAAO,WAC1B,GAAI,CAAC,EAAY,OAEjB,IAAI,EACJ,GAAI,CACA,EACI,OAAO,GAAa,YAAc,CAAC,EAAA,gBAAgB,EAAmB,CAC/D,EAA4D,EAAI,CAChE,QACN,EAAG,CACR,QAAQ,MAAM,wEAAyE,EAAE,CACzF,EAAgB,EAAqB,EAAY,EAAO,CACxD,OAIJ,EAAA,kBAAkB,EAA6B,CAC/C,GAAI,CACA,AAGI,EAHA,EAAA,gBAAgB,EAAG,CACH,EAAA,sBAAsB,EAAI,EAAY,EAAO,CAE7C,EAAG,QAAQ,EAAY,EAAO,OAE7C,EAAG,CACR,QAAQ,MAAM,sDAAuD,EAAE,CACvE,KAAiB,CACjB,EAAgB,EAAqB,EAAY,EAAO,QAClD,CACN,EAAA,kBAAkB,GAIpB,EAAgC,GAAqB,CACvD,QAAQ,MAAM,iEAAkE,EAAE,CAClF,KAAiB,CACjB,EAAgB,KAChB,IAAM,EAAa,EAAO,WACtB,IACA,EAAgB,EAAqB,EAAY,EAAO,GAI1D,GAAwB,EAAkB,IAAsC,CAClF,IAAM,EAAK,SAAS,cAAc,MAAM,CAIxC,OAHA,EAAG,aAAa,2BAA4B,kBAAkB,CAC9D,EAAG,YAAc,mDACjB,EAAW,aAAa,EAAI,EAAO,KACtB,EAAG,QAAQ,EAiB5B,EAAA,kBAb6B,GAAuB,CAC5C,IACJ,EAAU,GACN,GACA,KAAiB,CACjB,EAAgB,KAChB,EAAe,EAAI,GAEnB,EAAgB,EAChB,EAAmB,MAIW,CACtC,GAAI,CAIA,EAAA,uBAAyB,CACrB,GAAI,EAAA,gBAAgB,EAAQ,CAAE,CAC1B,EAAA,uBAAuB,CACvB,GAAI,CACA,GAAI,CAAE,EAAQ,UAAU,OAAW,EAAG,CAClC,GAAI,EAAQ,QAAS,EAAQ,QAAQ,EAAE,MAAO,MAAM,EAExD,EAAgB,EAAQ,QAAQ,CAAC,QAAQ,EAAQ,EAAO,QAClD,CACN,EAAA,sBAAsB,CAErB,GACD,EAAA,kBAAoB,CAChB,GAAI,CACA,IAAM,EAAM,EAAQ,WAAW,CACzB,EAAO,EACb,MAAsB,CAClB,GAAI,CAAE,EAAQ,aAAa,MAAU,EACrC,GAAI,OAAO,GAAQ,WAAY,GAAI,CAAE,GAAK,MAAU,EACpD,KAAQ,QAEP,EAAG,CACR,GAAI,EAAQ,QAAS,EAAQ,QAAQ,EAAE,MAAO,MAAM,IAE1D,MAGN,EAAgB,EAAQ,QAAQ,EAAQ,EAAO,EAErD,OACG,EAAK,CACV,EAAU,GACV,GAAW,CACX,EAAgB,KAChB,EAAgB,EAChB,EAAmB,UACb,CACN,EAAA,kBAAkB,CAClB,EAAoB,GASxB,OANI,IACA,GAAW,CACX,EAAgB,KAChB,EAAe,EAAc,MAGpB,CACT,KAAiB,CACjB,EAAO,QAAQ,GAG1B"}
@@ -1,90 +1,96 @@
1
- import { _popErrorHandler as e, _pushErrorHandler as t } from "../../signals.js";
1
+ import { _popErrorHandler as e, _pushErrorHandler as t } from "../next-2/reactivity.js";
2
2
  import { COMMENT as n } from "./types.js";
3
3
  import { isElurComponent as r } from "../../lifecycle.js";
4
4
  import { _popComponentContext as i, _pushComponentContext as a } from "../../context.js";
5
- import { _mountComponentSilent as o } from "./mount-helpers.js";
5
+ import { _deferOnMount as o, _mountComponentSilent as s, _postMountScopeSub as c } from "../next-2/mount-helpers.js";
6
6
  //#region src/elur/template/error-boundary.ts
7
- function s(s, c) {
7
+ function l(l, u) {
8
8
  return {
9
9
  __isElurTemplate: !0,
10
10
  mount(e) {
11
11
  let t = typeof e == "string" ? document.querySelector(e) ?? document.body : e;
12
12
  return { unmount: this._render(t, null) };
13
13
  },
14
- _render(l, u) {
15
- let d = document.createComment(n.ERROR_BOUNDARY);
16
- l.insertBefore(d, u);
17
- let f = null, p = !1, m = !1, h, g = !1, _ = (n) => {
18
- let i = d.parentNode;
14
+ _render(d, f) {
15
+ let p = document.createComment(n.ERROR_BOUNDARY);
16
+ d.insertBefore(p, f);
17
+ let m = null, h = () => {
18
+ m?.();
19
+ }, g = !1, _ = !1, v, y = !1, b = (n) => {
20
+ let i = p.parentNode;
19
21
  if (!i) return;
20
22
  let a;
21
23
  try {
22
- a = typeof c == "function" && !r(c) ? c(n) : c;
24
+ a = typeof u == "function" && !r(u) ? u(n) : u;
23
25
  } catch (e) {
24
- console.error("[elur] Error boundary fallback threw while producing the fallback UI:", e), f = y(i, u);
26
+ console.error("[elur] Error boundary fallback threw while producing the fallback UI:", e), m = S(i, f);
25
27
  return;
26
28
  }
27
- t(v);
29
+ t(x);
28
30
  try {
29
- f = r(a) ? o(a, i, u) : a._render(i, u);
31
+ m = r(a) ? s(a, i, f) : a._render(i, f);
30
32
  } catch (e) {
31
- console.error("[elur] Error boundary fallback threw during render:", e), f?.(), f = y(i, u);
33
+ console.error("[elur] Error boundary fallback threw during render:", e), m?.(), m = S(i, f);
32
34
  } finally {
33
35
  e();
34
36
  }
35
- }, v = (e) => {
36
- console.error("[elur] Error boundary fallback threw during a reactive update:", e), f?.(), f = null;
37
- let t = d.parentNode;
38
- t && (f = y(t, u));
39
- }, y = (e, t) => {
37
+ }, x = (e) => {
38
+ console.error("[elur] Error boundary fallback threw during a reactive update:", e), m?.(), m = null;
39
+ let t = p.parentNode;
40
+ t && (m = S(t, f));
41
+ }, S = (e, t) => {
40
42
  let n = document.createElement("div");
41
43
  return n.setAttribute("data-elur-error-boundary", "fallback-failed"), n.textContent = "[elur] Error boundary fallback failed to render.", e.insertBefore(n, t), () => n.remove();
42
44
  };
43
45
  t((e) => {
44
- p || (p = !0, m ? (f?.(), f = null, _(e)) : (h = e, g = !0));
46
+ g || (g = !0, _ ? (m?.(), m = null, b(e)) : (v = e, y = !0));
45
47
  });
46
48
  try {
47
- if (r(s)) {
48
- a();
49
- try {
49
+ c(() => {
50
+ if (r(l)) {
51
+ a();
50
52
  try {
51
- s.onInit?.();
52
- } catch (e) {
53
- if (s.onError) s.onError(e);
54
- else throw e;
53
+ try {
54
+ l.onInit?.();
55
+ } catch (e) {
56
+ if (l.onError) l.onError(e);
57
+ else throw e;
58
+ }
59
+ m = l.render()._render(d, f);
60
+ } finally {
61
+ i();
55
62
  }
56
- f = s.render()._render(l, u);
57
- } finally {
58
- i();
59
- }
60
- if (!p) try {
61
- let e = s.onMount?.(), t = f;
62
- f = () => {
63
+ g || o(() => {
63
64
  try {
64
- s.onUnmount?.();
65
- } catch {}
66
- if (typeof e == "function") try {
67
- e();
68
- } catch {}
69
- t?.();
70
- };
71
- } catch (e) {
72
- if (s.onError) s.onError(e);
73
- else throw e;
74
- }
75
- } else f = s._render(l, u);
65
+ let e = l.onMount?.(), t = m;
66
+ m = () => {
67
+ try {
68
+ l.onUnmount?.();
69
+ } catch {}
70
+ if (typeof e == "function") try {
71
+ e();
72
+ } catch {}
73
+ t?.();
74
+ };
75
+ } catch (e) {
76
+ if (l.onError) l.onError(e);
77
+ else throw e;
78
+ }
79
+ });
80
+ } else m = l._render(d, f);
81
+ });
76
82
  } catch (e) {
77
- p = !0, f?.(), f = null, h = e, g = !0;
83
+ g = !0, h(), m = null, v = e, y = !0;
78
84
  } finally {
79
- e(), m = !0;
85
+ e(), _ = !0;
80
86
  }
81
- return g && (f?.(), f = null, _(h)), () => {
82
- f?.(), d.remove();
87
+ return y && (h(), m = null, b(v)), () => {
88
+ m?.(), p.remove();
83
89
  };
84
90
  }
85
91
  };
86
92
  }
87
93
  //#endregion
88
- export { s as createErrorBoundary };
94
+ export { l as createErrorBoundary };
89
95
 
90
96
  //# sourceMappingURL=error-boundary.js.map