@elurjs/core 3.5.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 (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -0
  3. package/dist/lib/async.cjs +16 -0
  4. package/dist/lib/async.js +123 -0
  5. package/dist/lib/component.cjs +2 -0
  6. package/dist/lib/component.js +66 -0
  7. package/dist/lib/context.cjs +2 -0
  8. package/dist/lib/context.js +52 -0
  9. package/dist/lib/devtools.cjs +59 -0
  10. package/dist/lib/devtools.js +419 -0
  11. package/dist/lib/elur/async.cjs +16 -0
  12. package/dist/lib/elur/async.cjs.map +1 -0
  13. package/dist/lib/elur/async.d.cts +32 -0
  14. package/dist/lib/elur/async.d.ts +32 -0
  15. package/dist/lib/elur/async.js +123 -0
  16. package/dist/lib/elur/async.js.map +1 -0
  17. package/dist/lib/elur/component.cjs +2 -0
  18. package/dist/lib/elur/component.cjs.map +1 -0
  19. package/dist/lib/elur/component.d.cts +17 -0
  20. package/dist/lib/elur/component.d.ts +17 -0
  21. package/dist/lib/elur/component.js +66 -0
  22. package/dist/lib/elur/component.js.map +1 -0
  23. package/dist/lib/elur/context.cjs +2 -0
  24. package/dist/lib/elur/context.cjs.map +1 -0
  25. package/dist/lib/elur/context.d.cts +29 -0
  26. package/dist/lib/elur/context.d.ts +29 -0
  27. package/dist/lib/elur/context.js +52 -0
  28. package/dist/lib/elur/context.js.map +1 -0
  29. package/dist/lib/elur/devtools.cjs +59 -0
  30. package/dist/lib/elur/devtools.cjs.map +1 -0
  31. package/dist/lib/elur/devtools.d.cts +24 -0
  32. package/dist/lib/elur/devtools.d.ts +24 -0
  33. package/dist/lib/elur/devtools.js +419 -0
  34. package/dist/lib/elur/devtools.js.map +1 -0
  35. package/dist/lib/elur/form.cjs +2 -0
  36. package/dist/lib/elur/form.cjs.map +1 -0
  37. package/dist/lib/elur/form.d.cts +283 -0
  38. package/dist/lib/elur/form.d.ts +283 -0
  39. package/dist/lib/elur/form.js +315 -0
  40. package/dist/lib/elur/form.js.map +1 -0
  41. package/dist/lib/elur/hydrate/index.cjs +2 -0
  42. package/dist/lib/elur/hydrate/index.cjs.map +1 -0
  43. package/dist/lib/elur/hydrate/index.d.cts +13 -0
  44. package/dist/lib/elur/hydrate/index.d.ts +13 -0
  45. package/dist/lib/elur/hydrate/index.js +410 -0
  46. package/dist/lib/elur/hydrate/index.js.map +1 -0
  47. package/dist/lib/elur/index.d.cts +19 -0
  48. package/dist/lib/elur/index.d.ts +19 -0
  49. package/dist/lib/elur/lifecycle.cjs +2 -0
  50. package/dist/lib/elur/lifecycle.cjs.map +1 -0
  51. package/dist/lib/elur/lifecycle.d.cts +45 -0
  52. package/dist/lib/elur/lifecycle.d.ts +45 -0
  53. package/dist/lib/elur/lifecycle.js +39 -0
  54. package/dist/lib/elur/lifecycle.js.map +1 -0
  55. package/dist/lib/elur/plugins.cjs +2 -0
  56. package/dist/lib/elur/plugins.cjs.map +1 -0
  57. package/dist/lib/elur/plugins.d.cts +48 -0
  58. package/dist/lib/elur/plugins.d.ts +48 -0
  59. package/dist/lib/elur/plugins.js +59 -0
  60. package/dist/lib/elur/plugins.js.map +1 -0
  61. package/dist/lib/elur/reactivity.cjs +2 -0
  62. package/dist/lib/elur/reactivity.cjs.map +1 -0
  63. package/dist/lib/elur/reactivity.d.cts +60 -0
  64. package/dist/lib/elur/reactivity.d.ts +60 -0
  65. package/dist/lib/elur/reactivity.js +188 -0
  66. package/dist/lib/elur/reactivity.js.map +1 -0
  67. package/dist/lib/elur/router.cjs +12 -0
  68. package/dist/lib/elur/router.cjs.map +1 -0
  69. package/dist/lib/elur/router.d.cts +137 -0
  70. package/dist/lib/elur/router.d.ts +137 -0
  71. package/dist/lib/elur/router.js +513 -0
  72. package/dist/lib/elur/router.js.map +1 -0
  73. package/dist/lib/elur/server/index.cjs +2 -0
  74. package/dist/lib/elur/server/index.cjs.map +1 -0
  75. package/dist/lib/elur/server/index.d.cts +44 -0
  76. package/dist/lib/elur/server/index.d.ts +44 -0
  77. package/dist/lib/elur/server/index.js +307 -0
  78. package/dist/lib/elur/server/index.js.map +1 -0
  79. package/dist/lib/elur/store.cjs +2 -0
  80. package/dist/lib/elur/store.cjs.map +1 -0
  81. package/dist/lib/elur/store.d.cts +137 -0
  82. package/dist/lib/elur/store.d.ts +137 -0
  83. package/dist/lib/elur/store.js +143 -0
  84. package/dist/lib/elur/store.js.map +1 -0
  85. package/dist/lib/elur/template/bindings.cjs +2 -0
  86. package/dist/lib/elur/template/bindings.cjs.map +1 -0
  87. package/dist/lib/elur/template/bindings.d.cts +40 -0
  88. package/dist/lib/elur/template/bindings.d.ts +40 -0
  89. package/dist/lib/elur/template/bindings.js +214 -0
  90. package/dist/lib/elur/template/bindings.js.map +1 -0
  91. package/dist/lib/elur/template/dom-write.cjs +2 -0
  92. package/dist/lib/elur/template/dom-write.cjs.map +1 -0
  93. package/dist/lib/elur/template/dom-write.d.cts +5 -0
  94. package/dist/lib/elur/template/dom-write.d.ts +5 -0
  95. package/dist/lib/elur/template/dom-write.js +16 -0
  96. package/dist/lib/elur/template/dom-write.js.map +1 -0
  97. package/dist/lib/elur/template/error-boundary.cjs +2 -0
  98. package/dist/lib/elur/template/error-boundary.cjs.map +1 -0
  99. package/dist/lib/elur/template/error-boundary.d.cts +7 -0
  100. package/dist/lib/elur/template/error-boundary.d.ts +7 -0
  101. package/dist/lib/elur/template/error-boundary.js +90 -0
  102. package/dist/lib/elur/template/error-boundary.js.map +1 -0
  103. package/dist/lib/elur/template/html.cjs +2 -0
  104. package/dist/lib/elur/template/html.cjs.map +1 -0
  105. package/dist/lib/elur/template/html.d.cts +8 -0
  106. package/dist/lib/elur/template/html.d.ts +8 -0
  107. package/dist/lib/elur/template/html.js +104 -0
  108. package/dist/lib/elur/template/html.js.map +1 -0
  109. package/dist/lib/elur/template/index.cjs +1 -0
  110. package/dist/lib/elur/template/index.d.cts +15 -0
  111. package/dist/lib/elur/template/index.d.ts +15 -0
  112. package/dist/lib/elur/template/index.js +13 -0
  113. package/dist/lib/elur/template/keyed-diff.cjs +2 -0
  114. package/dist/lib/elur/template/keyed-diff.cjs.map +1 -0
  115. package/dist/lib/elur/template/keyed-diff.d.cts +32 -0
  116. package/dist/lib/elur/template/keyed-diff.d.ts +32 -0
  117. package/dist/lib/elur/template/keyed-diff.js +100 -0
  118. package/dist/lib/elur/template/keyed-diff.js.map +1 -0
  119. package/dist/lib/elur/template/keyed.cjs +2 -0
  120. package/dist/lib/elur/template/keyed.cjs.map +1 -0
  121. package/dist/lib/elur/template/keyed.d.cts +27 -0
  122. package/dist/lib/elur/template/keyed.d.ts +27 -0
  123. package/dist/lib/elur/template/keyed.js +52 -0
  124. package/dist/lib/elur/template/keyed.js.map +1 -0
  125. package/dist/lib/elur/template/mount-helpers.cjs +2 -0
  126. package/dist/lib/elur/template/mount-helpers.cjs.map +1 -0
  127. package/dist/lib/elur/template/mount-helpers.d.cts +29 -0
  128. package/dist/lib/elur/template/mount-helpers.d.ts +29 -0
  129. package/dist/lib/elur/template/mount-helpers.js +132 -0
  130. package/dist/lib/elur/template/mount-helpers.js.map +1 -0
  131. package/dist/lib/elur/template/node-binding.cjs +2 -0
  132. package/dist/lib/elur/template/node-binding.cjs.map +1 -0
  133. package/dist/lib/elur/template/node-binding.d.cts +6 -0
  134. package/dist/lib/elur/template/node-binding.d.ts +6 -0
  135. package/dist/lib/elur/template/node-binding.js +95 -0
  136. package/dist/lib/elur/template/node-binding.js.map +1 -0
  137. package/dist/lib/elur/template/portal.cjs +2 -0
  138. package/dist/lib/elur/template/portal.cjs.map +1 -0
  139. package/dist/lib/elur/template/portal.d.cts +19 -0
  140. package/dist/lib/elur/template/portal.d.ts +19 -0
  141. package/dist/lib/elur/template/portal.js +49 -0
  142. package/dist/lib/elur/template/portal.js.map +1 -0
  143. package/dist/lib/elur/template/raw.cjs +2 -0
  144. package/dist/lib/elur/template/raw.cjs.map +1 -0
  145. package/dist/lib/elur/template/raw.d.cts +9 -0
  146. package/dist/lib/elur/template/raw.d.ts +9 -0
  147. package/dist/lib/elur/template/raw.js +29 -0
  148. package/dist/lib/elur/template/raw.js.map +1 -0
  149. package/dist/lib/elur/template/sanitize.cjs +2 -0
  150. package/dist/lib/elur/template/sanitize.cjs.map +1 -0
  151. package/dist/lib/elur/template/sanitize.d.cts +16 -0
  152. package/dist/lib/elur/template/sanitize.d.ts +16 -0
  153. package/dist/lib/elur/template/sanitize.js +29 -0
  154. package/dist/lib/elur/template/sanitize.js.map +1 -0
  155. package/dist/lib/elur/template/transitions.cjs +2 -0
  156. package/dist/lib/elur/template/transitions.cjs.map +1 -0
  157. package/dist/lib/elur/template/transitions.d.cts +43 -0
  158. package/dist/lib/elur/template/transitions.d.ts +43 -0
  159. package/dist/lib/elur/template/transitions.js +96 -0
  160. package/dist/lib/elur/template/transitions.js.map +1 -0
  161. package/dist/lib/elur/template/types.cjs +2 -0
  162. package/dist/lib/elur/template/types.cjs.map +1 -0
  163. package/dist/lib/elur/template/types.d.cts +114 -0
  164. package/dist/lib/elur/template/types.d.ts +114 -0
  165. package/dist/lib/elur/template/types.js +23 -0
  166. package/dist/lib/elur/template/types.js.map +1 -0
  167. package/dist/lib/elur.cjs +1 -0
  168. package/dist/lib/elur.js +18 -0
  169. package/dist/lib/form.cjs +2 -0
  170. package/dist/lib/form.js +315 -0
  171. package/dist/lib/hydrate.cjs +2 -0
  172. package/dist/lib/hydrate.js +410 -0
  173. package/dist/lib/index.cjs +1 -0
  174. package/dist/lib/index.d.cts +2 -0
  175. package/dist/lib/index.d.ts +2 -0
  176. package/dist/lib/index.js +18 -0
  177. package/dist/lib/lifecycle.cjs +2 -0
  178. package/dist/lib/lifecycle.js +39 -0
  179. package/dist/lib/plugins.cjs +2 -0
  180. package/dist/lib/plugins.js +59 -0
  181. package/dist/lib/router.cjs +12 -0
  182. package/dist/lib/router.js +513 -0
  183. package/dist/lib/server.cjs +2 -0
  184. package/dist/lib/server.js +307 -0
  185. package/dist/lib/signals.cjs +2 -0
  186. package/dist/lib/signals.js +188 -0
  187. package/dist/lib/store.cjs +2 -0
  188. package/dist/lib/store.js +143 -0
  189. package/dist/lib/template.cjs +1 -0
  190. package/dist/lib/template.js +13 -0
  191. package/package.json +216 -0
@@ -0,0 +1,419 @@
1
+ import { _setSignalDebugHooks as e } from "./signals.js";
2
+ import { _setComponentDebugHooks as t } from "./lifecycle.js";
3
+ import { _debugGetRouterInternal as n } from "./router.js";
4
+ //#region src/elur/devtools.ts
5
+ var r = {
6
+ enabled: !1,
7
+ activeTab: "signals",
8
+ renderedTab: null,
9
+ refreshId: null,
10
+ root: null,
11
+ panel: null,
12
+ content: null,
13
+ dispose: null,
14
+ renderKeys: {
15
+ signals: "",
16
+ components: "",
17
+ router: ""
18
+ },
19
+ scrollMemo: {
20
+ signals: {
21
+ top: 0,
22
+ left: 0
23
+ },
24
+ components: {
25
+ top: 0,
26
+ left: 0
27
+ },
28
+ router: {
29
+ top: 0,
30
+ left: 0
31
+ }
32
+ }
33
+ }, i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new WeakMap(), o = 1, s = 50, c = /* @__PURE__ */ new WeakMap(), l = /* @__PURE__ */ new Map(), u = [], d = 1;
34
+ function f(e) {
35
+ return typeof WeakRef < "u" ? new WeakRef(e) : { deref: () => e };
36
+ }
37
+ function p(e) {
38
+ return typeof WeakRef < "u" ? new WeakRef(e) : { deref: () => e };
39
+ }
40
+ function m(e) {
41
+ e.history.length > s && e.history.splice(0, e.history.length - s);
42
+ }
43
+ function h(e, t) {
44
+ let n = a.get(e);
45
+ if (n) return m(n), n;
46
+ let r = Date.now(), s = {
47
+ id: o++,
48
+ createdAt: r,
49
+ lastUpdated: r,
50
+ history: [{
51
+ at: r,
52
+ value: t
53
+ }]
54
+ };
55
+ return a.set(e, s), i.add(f(e)), s;
56
+ }
57
+ function g() {
58
+ let e = [];
59
+ for (let t of Array.from(i)) {
60
+ let n = t.deref();
61
+ if (!n) {
62
+ i.delete(t);
63
+ continue;
64
+ }
65
+ let r = a.get(n);
66
+ if (!r) continue;
67
+ let o = n._subs?.size ?? 0;
68
+ e.push({
69
+ id: r.id,
70
+ value: n.peek(),
71
+ subscriberCount: o,
72
+ createdAt: r.createdAt,
73
+ lastUpdated: r.lastUpdated,
74
+ history: r.history.slice()
75
+ });
76
+ }
77
+ return e.sort((e, t) => t.lastUpdated - e.lastUpdated), e;
78
+ }
79
+ function _(e) {
80
+ let t = e._debugName;
81
+ if (t && t.trim()) return t;
82
+ let n = e.constructor;
83
+ return n?.name && n.name.trim() ? n.name : "AnonymousComponent";
84
+ }
85
+ function v(e) {
86
+ let t = e._slots;
87
+ return t instanceof Map ? Array.from(t.keys()).map((e) => String(e)) : [];
88
+ }
89
+ function y(e) {
90
+ let t = {};
91
+ for (let n of Object.keys(e)) {
92
+ if (n === "__isElurComponent" || n === "children" || n === "_debugName" || n.startsWith("_")) continue;
93
+ let r = e[n];
94
+ typeof r != "function" && (t[n] = r);
95
+ }
96
+ return t;
97
+ }
98
+ function b(e) {
99
+ if (!e) return [];
100
+ if (e === "*") return ["*"];
101
+ let t = e.split("/").filter(Boolean), n = [], r = "";
102
+ for (let e of t) r += "/" + e, n.push(r);
103
+ return n.length > 0 ? n : ["/"];
104
+ }
105
+ function x() {
106
+ let e = [];
107
+ for (let [t, n] of l) {
108
+ let r = n.ref.deref();
109
+ if (!r) {
110
+ l.delete(t);
111
+ continue;
112
+ }
113
+ n.debugName = _(r), n.hasDefaultSlot = r.children != null, n.slotNames = v(r), n.props = y(r), e.push({
114
+ id: n.id,
115
+ parentId: n.parentId,
116
+ debugName: n.debugName,
117
+ mountedAt: n.mountedAt,
118
+ hasDefaultSlot: n.hasDefaultSlot,
119
+ slotNames: [...n.slotNames],
120
+ props: { ...n.props }
121
+ });
122
+ }
123
+ return e.sort((e, t) => e.id - t.id), e;
124
+ }
125
+ function S(e) {
126
+ let t = [e];
127
+ for (; t.length > 0;) {
128
+ let e = t.pop();
129
+ for (let [n, r] of l) r.parentId === e && t.push(n);
130
+ l.delete(e);
131
+ }
132
+ }
133
+ function C() {
134
+ i.clear(), a = /* @__PURE__ */ new WeakMap(), o = 1, c = /* @__PURE__ */ new WeakMap(), l.clear(), u.length = 0, d = 1;
135
+ }
136
+ function w(e) {
137
+ if (typeof e == "string") return e;
138
+ if (typeof e == "number" || typeof e == "boolean" || e == null) return String(e);
139
+ try {
140
+ return JSON.stringify(e);
141
+ } catch {
142
+ return Object.prototype.toString.call(e);
143
+ }
144
+ }
145
+ function T(e) {
146
+ return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
147
+ }
148
+ function E(e, t = 90) {
149
+ let n = w(e);
150
+ return n.length <= t ? n : n.slice(0, t - 1) + "…";
151
+ }
152
+ function D(e) {
153
+ if (!e) return "-";
154
+ let t = Date.now() - e;
155
+ return t < 1e3 ? `${t}ms ago` : t < 6e4 ? `${Math.floor(t / 1e3)}s ago` : `${Math.floor(t / 6e4)}m ago`;
156
+ }
157
+ function O(e) {
158
+ let t = g(), n = `${t.length}:${t.map((e) => `${e.id}-${e.lastUpdated}-${e.subscriberCount}`).join("|")}`;
159
+ if (r.renderedTab === "signals" && r.renderKeys.signals === n) return;
160
+ r.renderKeys.signals = n, r.renderedTab = "signals";
161
+ let i = t.map((e) => {
162
+ let t = w(e.value), n = E(e.value, 120);
163
+ return `<tr data-elur-devtools-signal-id="${e.id}">
164
+ <td style="padding:6px 8px;white-space:nowrap;">${e.id}</td>
165
+ <td style="padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;" title="${T(t)}">${T(n)}</td>
166
+ <td>${e.subscriberCount}</td>
167
+ <td data-elur-devtools-history-count="${e.history.length}">${e.history.length}</td>
168
+ <td>${D(e.lastUpdated)}</td>
169
+ </tr>`;
170
+ }).join("");
171
+ e.innerHTML = `
172
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">
173
+ <strong>Signals</strong>
174
+ <span style="opacity:.8">${t.length} active</span>
175
+ </div>
176
+ <div data-elur-devtools-scroll="signals" style="max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">
177
+ <table style="width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;">
178
+ <thead>
179
+ <tr style="background:#1f1f24;">
180
+ <th style="text-align:left;padding:6px 8px;width:42px;">ID</th>
181
+ <th style="text-align:left;padding:6px 8px;">Value</th>
182
+ <th style="text-align:left;padding:6px 8px;width:50px;">Subs</th>
183
+ <th style="text-align:left;padding:6px 8px;width:50px;">History</th>
184
+ <th style="text-align:left;padding:6px 8px;width:84px;">Updated</th>
185
+ </tr>
186
+ </thead>
187
+ <tbody>${i}</tbody>
188
+ </table>
189
+ </div>
190
+ <p style="margin:8px 0 0 0;font-size:11px;opacity:.75;">Click a row to log full history in console.</p>
191
+ `;
192
+ for (let n of e.querySelectorAll("tr[data-elur-devtools-signal-id]")) n.style.cursor = "pointer", n.addEventListener("click", () => {
193
+ let e = Number(n.dataset.elurDevtoolsSignalId), r = t.find((t) => t.id === e);
194
+ r && (console.group(`[Elur DevTools] Signal #${r.id}`), console.log("Current value:", r.value), console.log("Subscribers:", r.subscriberCount), console.table(r.history.map((e) => ({
195
+ at: new Date(e.at).toISOString(),
196
+ value: e.value
197
+ }))), console.groupEnd());
198
+ });
199
+ }
200
+ function k(e) {
201
+ let t = /* @__PURE__ */ new Map(), n = [];
202
+ for (let n of e) t.set(n.id, {
203
+ ...n,
204
+ children: []
205
+ });
206
+ for (let e of t.values()) {
207
+ if (e.parentId == null) {
208
+ n.push(e);
209
+ continue;
210
+ }
211
+ let r = t.get(e.parentId);
212
+ if (!r) {
213
+ n.push(e);
214
+ continue;
215
+ }
216
+ r.children.push(e);
217
+ }
218
+ return n;
219
+ }
220
+ function A(e, t) {
221
+ let n = 10 + t * 14, r = Object.keys(e.props).length > 0 ? w(e.props) : "{}", i = e.slotNames.length > 0 ? e.slotNames.join(", ") : "none";
222
+ return `<div style="padding:6px 8px 6px ${n}px;border-bottom:1px solid #24242b;">
223
+ <div><strong>${T(e.debugName)}</strong> <span style="opacity:.7">#${e.id}</span></div>
224
+ <div style="font-size:11px;opacity:.8;">slots: ${i} | default-slot: ${e.hasDefaultSlot ? "yes" : "no"}</div>
225
+ <div style="font-size:11px;opacity:.8;">props: ${T(E(r, 180))}</div>
226
+ </div>` + e.children.map((e) => A(e, t + 1)).join("");
227
+ }
228
+ function j(e) {
229
+ let t = x(), i = n(), a = `${i ? `${i.currentPath}|${i.matchedPath ?? ""}` : "no-router"}:${t.length}:${t.map((e) => `${e.id}-${e.parentId}-${e.debugName}-${e.hasDefaultSlot}-${e.slotNames.join(",")}-${w(e.props)}`).join("|")}`;
230
+ if (r.renderedTab === "components" && r.renderKeys.components === a) return;
231
+ r.renderKeys.components = a, r.renderedTab = "components";
232
+ let o = k(t);
233
+ e.innerHTML = `
234
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">
235
+ <strong>Component Tree</strong>
236
+ <span style="opacity:.8">${t.length} mounted</span>
237
+ </div>
238
+ <div style="font-size:11px;opacity:.82;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap;">
239
+ <span><b>current:</b> ${T(i?.currentPath ?? "-")}</span>
240
+ <span><b>matched:</b> ${T(i?.matchedPath ?? "none")}</span>
241
+ </div>
242
+ <div data-elur-devtools-scroll="components" style="max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">
243
+ ${o.length > 0 ? o.map((e) => A(e, 0)).join("") : "<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>"}
244
+ </div>
245
+ `;
246
+ }
247
+ function M(e) {
248
+ let t = n(), i = t ? `${t.mode}|${t.base}|${t.currentPath}|${JSON.stringify(t.params)}|${JSON.stringify(t.query)}|${t.matchedPath}|${t.activeGuards.names.join(",")}` : "none";
249
+ if (r.renderedTab === "router" && r.renderKeys.router === i) return;
250
+ if (r.renderKeys.router = i, r.renderedTab = "router", !t) {
251
+ e.innerHTML = "\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from elur/router.</div>\n ";
252
+ return;
253
+ }
254
+ let a = b(t.matchedPath);
255
+ e.innerHTML = `
256
+ <strong>Router State</strong>
257
+ <div data-elur-devtools-scroll="router" style="margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;">
258
+ <div><b>mode</b>: ${t.mode}</div>
259
+ <div><b>base</b>: ${t.base}</div>
260
+ <div><b>current</b>: ${T(t.currentPath)}</div>
261
+ <div><b>params</b>: ${T(w(t.params))}</div>
262
+ <div><b>query</b>: ${T(w(t.query))}</div>
263
+ <div><b>matched</b>: ${T(t.matchedPath ?? "none")}</div>
264
+ <div><b>matched chain</b>: ${a.length > 0 ? T(a.join(" -> ")) : "none"}</div>
265
+ <div><b>guards</b>: ${t.activeGuards.names.length > 0 ? T(t.activeGuards.names.join(", ")) : "none"}</div>
266
+ </div>
267
+ `;
268
+ }
269
+ function N(e) {
270
+ if (!r.content) return;
271
+ let t = r.content.querySelector(`[data-elur-devtools-scroll='${e}']`);
272
+ t && (r.scrollMemo[e] = {
273
+ top: t.scrollTop,
274
+ left: t.scrollLeft
275
+ });
276
+ }
277
+ function P(e) {
278
+ if (!r.content) return;
279
+ let t = r.content.querySelector(`[data-elur-devtools-scroll='${e}']`);
280
+ if (!t) return;
281
+ let n = r.scrollMemo[e];
282
+ t.scrollTop = n.top, t.scrollLeft = n.left, t.dataset.elurDevtoolsScrollBound !== "1" && (t.addEventListener("scroll", () => {
283
+ r.scrollMemo[e] = {
284
+ top: t.scrollTop,
285
+ left: t.scrollLeft
286
+ };
287
+ }, { passive: !0 }), t.dataset.elurDevtoolsScrollBound = "1");
288
+ }
289
+ function F(e = !1) {
290
+ if (!r.content) return;
291
+ let t = r.activeTab;
292
+ if (e || N(t), r.activeTab === "signals") {
293
+ O(r.content), P("signals");
294
+ return;
295
+ }
296
+ if (r.activeTab === "components") {
297
+ j(r.content), P("components");
298
+ return;
299
+ }
300
+ M(r.content), P("router");
301
+ }
302
+ function I() {
303
+ if (r.panel) for (let e of r.panel.querySelectorAll("button[data-elur-devtools-tab]")) {
304
+ let t = e.dataset.elurDevtoolsTab === r.activeTab;
305
+ e.style.background = t ? "#2d4c7a" : "#1f1f24";
306
+ }
307
+ }
308
+ function L(e) {
309
+ let t = document.createElement("div");
310
+ t.setAttribute("data-elur-devtools-root", ""), t.style.position = "fixed", t.style.zIndex = "2147483647", t.style.bottom = "16px", t.style.right = e.position === "bottom-right" ? "16px" : "auto", t.style.left = e.position === "bottom-left" ? "16px" : "auto", t.style.fontFamily = "ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif";
311
+ let n = document.createElement("button");
312
+ n.type = "button", n.textContent = "Elur DevTools", n.setAttribute("data-elur-devtools-button", ""), n.style.background = "#111827", n.style.color = "#f9fafb", n.style.border = "1px solid #374151", n.style.borderRadius = "999px", n.style.padding = "8px 12px", n.style.cursor = "pointer", n.style.boxShadow = "0 6px 18px rgba(0,0,0,.3)";
313
+ let i = document.createElement("div");
314
+ i.setAttribute("data-elur-devtools-panel", ""), i.style.marginTop = "8px", i.style.width = "460px", i.style.maxWidth = "min(92vw, 460px)", i.style.background = "#15151b", i.style.color = "#e5e7eb", i.style.border = "1px solid #2f2f35", i.style.borderRadius = "12px", i.style.padding = "10px", i.style.display = "none", i.style.boxShadow = "0 14px 28px rgba(0,0,0,.35)";
315
+ let a = document.createElement("div");
316
+ a.style.display = "flex", a.style.gap = "6px", a.style.marginBottom = "10px";
317
+ let o = document.createElement("div");
318
+ o.setAttribute("data-elur-devtools-content", "");
319
+ let s = (e, t) => {
320
+ let n = document.createElement("button");
321
+ return n.type = "button", n.textContent = t, n.setAttribute("data-elur-devtools-tab", e), n.style.border = "1px solid #353543", n.style.borderRadius = "8px", n.style.padding = "6px 9px", n.style.background = "#1f1f24", n.style.color = "#d1d5db", n.style.cursor = "pointer", n.addEventListener("click", () => {
322
+ r.activeTab = e, I(), F(!0);
323
+ }), n;
324
+ };
325
+ a.appendChild(s("signals", "Signals")), a.appendChild(s("components", "Components")), a.appendChild(s("router", "Router")), n.addEventListener("click", () => {
326
+ i.style.display = i.style.display === "none" ? "block" : "none", i.style.display === "block" && (I(), F(!0));
327
+ }), i.appendChild(a), i.appendChild(o), t.appendChild(n), t.appendChild(i), document.body.appendChild(t), r.root = t, r.panel = i, r.content = o;
328
+ }
329
+ function R() {
330
+ r.enabled && (r.enabled = !1, r.refreshId != null && (clearInterval(r.refreshId), r.refreshId = null), e(null), t(null), C(), r.root?.parentNode && r.root.parentNode.removeChild(r.root), r.root = null, r.panel = null, r.content = null, r.dispose = null, r.renderedTab = null, r.renderKeys = {
331
+ signals: "",
332
+ components: "",
333
+ router: ""
334
+ }, r.scrollMemo = {
335
+ signals: {
336
+ top: 0,
337
+ left: 0
338
+ },
339
+ components: {
340
+ top: 0,
341
+ left: 0
342
+ },
343
+ router: {
344
+ top: 0,
345
+ left: 0
346
+ }
347
+ });
348
+ }
349
+ function z(n = {}) {
350
+ if (typeof document > "u") return { disable: () => void 0 };
351
+ if (r.enabled && r.dispose) return { disable: r.dispose };
352
+ let o = Math.max(100, n.refreshMs ?? 350);
353
+ s = Math.max(1, n.historyLimit ?? 50);
354
+ let f = n.position ?? "bottom-right";
355
+ r.enabled = !0, r.activeTab = "signals";
356
+ for (let e of Array.from(i)) {
357
+ let t = e.deref();
358
+ if (!t) {
359
+ i.delete(e);
360
+ continue;
361
+ }
362
+ let n = a.get(t);
363
+ n && m(n);
364
+ }
365
+ e({
366
+ onCreate(e, t) {
367
+ h(e, t);
368
+ },
369
+ onWrite(e, t) {
370
+ let n = h(e, t), r = Date.now();
371
+ n.lastUpdated = r, n.history.push({
372
+ at: r,
373
+ value: t
374
+ }), m(n);
375
+ }
376
+ }), t({
377
+ onMountStart(e) {
378
+ let t = c.get(e);
379
+ t ?? (t = d++, c.set(e, t));
380
+ let n = u.length > 0 ? u[u.length - 1] : null;
381
+ l.set(t, {
382
+ id: t,
383
+ parentId: n,
384
+ debugName: _(e),
385
+ mountedAt: Date.now(),
386
+ hasDefaultSlot: e.children != null,
387
+ slotNames: v(e),
388
+ props: y(e),
389
+ ref: p(e)
390
+ }), u.push(t);
391
+ },
392
+ onMountEnd(e) {
393
+ let t = c.get(e);
394
+ if (t == null) return;
395
+ let n = l.get(t);
396
+ if (n && (n.debugName = _(e), n.hasDefaultSlot = e.children != null, n.slotNames = v(e), n.props = y(e)), u[u.length - 1] === t) {
397
+ u.pop();
398
+ return;
399
+ }
400
+ let r = u.lastIndexOf(t);
401
+ r >= 0 && u.splice(r, 1);
402
+ },
403
+ onUnmount(e) {
404
+ let t = c.get(e);
405
+ if (t == null) return;
406
+ S(t);
407
+ let n = u.lastIndexOf(t);
408
+ n >= 0 && u.splice(n, 1);
409
+ }
410
+ }), L({ position: f }), r.refreshId = setInterval(() => {
411
+ r.panel?.style.display === "block" && F();
412
+ }, o), n.initiallyOpen && r.panel && (r.panel.style.display = "block", I(), F(!0));
413
+ let g = () => R();
414
+ return r.dispose = g, { disable: g };
415
+ }
416
+ //#endregion
417
+ export { g as _listSignals, R as disableDevTools, z as enableDevTools };
418
+
419
+ //# sourceMappingURL=devtools.js.map
@@ -0,0 +1,16 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./signals.cjs`),t=require(`./elur/template/types.cjs`),n=require(`./lifecycle.cjs`),r=require(`./elur/template/html.cjs`);function i(){return r.html`
2
+ <span style="color:#52525b;font-size:13px;display:inline-flex;align-items:center;gap:6px">
3
+ <span class="elur-spinner" style="
4
+ display:inline-block;width:14px;height:14px;border-radius:50%;
5
+ border:2px solid #38bdf840;border-top-color:#38bdf8;
6
+ animation:elur-spin .7s linear infinite
7
+ "></span>
8
+ Loading…
9
+ </span>
10
+ <style>@keyframes elur-spin{to{transform:rotate(360deg)}}</style>
11
+ `}function a(e){return r.html`
12
+ <span style="color:#f87171;font-size:13px">
13
+ ⚠ ${e instanceof Error?e.message:String(e)}
14
+ </span>
15
+ `}var o=new Map,s=300*1e3,c=null,l=s;function u(){c===null&&(c=setInterval(()=>{let e=Date.now();for(let[t,n]of o)n.subscribers<=0&&e-n.fetchedAt>l&&o.delete(t);o.size===0&&c!==null&&(clearInterval(c),c=null)},6e4))}function d(e){let t=o.get(e);if(t&&t.fetchedAt>0)return t}function f(e,t){let n=o.get(e);o.set(e,{data:t,fetchedAt:Date.now(),subscribers:n?.subscribers??0}),u()}function p(e){let t=o.get(e);t?t.subscribers++:o.set(e,{fetchedAt:0,subscribers:1})}function m(e){let t=o.get(e);t&&(t.subscribers=Math.max(0,t.subscribers-1))}function h(e,t){let n=o.get(e);return n?Date.now()-n.fetchedAt<t:!1}function g(t,s,c={}){let{fallback:l,errorFallback:u,resetOnRefresh:g=!1,invalidate:_,cacheKey:v,staleTime:y=0}=c,b=l??i(),x=u??a;class S extends n.ElurComponent{_state;_disposeWatcher;constructor(){super();let t=v?d(v):void 0;this._state=e.signal(t&&t.data!==void 0?{status:`resolved`,data:t.data}:{status:`pending`})}onMount(){v&&p(v);let t=v?d(v):void 0;if(t&&h(v,y)||(t?this._fetch():this._run()),_){let t=!0;this._disposeWatcher=e.effect(()=>{if(_.value,t){t=!1;return}v&&o.delete(v),this._run()})}return()=>{this._disposeWatcher?.(),v&&m(v)}}_run(){(g||this._state.peek().status===`pending`)&&(this._state.value={status:`pending`}),this._fetch()}_fetch(){t().then(e=>{v&&f(v,e),this._state.value={status:`resolved`,data:e}},e=>{this._state.value={status:`error`,error:e}})}render(){return r.html`<div class="elur-suspense" style="display:contents">${()=>{let e=this._state.value;return e.status===`pending`?b:e.status===`error`?x(e.error):s(e.data)}}</div>`}}return new S}function _(e,n){let r=n===void 0||t.isElurTemplate(n)?{fallback:n}:n,i=r.selector??(e=>e.default),a=null;return()=>a?new a:g(async()=>(a=i(await e()),a),e=>new e,{fallback:r.fallback})}exports.lazy=_,exports.suspend=g;
16
+ //# sourceMappingURL=async.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async.cjs","names":[],"sources":["../../src/elur/async.ts"],"sourcesContent":["import { signal, effect, Signal } from \"./reactivity.js\";\nimport { ElurComponent } from \"./lifecycle.js\";\nimport { type ElurTemplate, html, isElurTemplate } from \"./template/index.js\";\n\n// --- Types ---\n\ntype AsyncState<T> =\n | { status: \"pending\" }\n | { status: \"resolved\"; data: T }\n | { status: \"error\"; error: unknown };\n\nexport interface SuspenseOptions {\n fallback?: ElurTemplate;\n errorFallback?: (err: unknown) => ElurTemplate;\n resetOnRefresh?: boolean;\n invalidate?: Signal<unknown>;\n cacheKey?: string;\n staleTime?: number;\n}\n\n// --- Default fallbacks ---\n\nfunction defaultLoadingFallback(): ElurTemplate {\n return html`\n <span style=\"color:#52525b;font-size:13px;display:inline-flex;align-items:center;gap:6px\">\n <span class=\"elur-spinner\" style=\"\n display:inline-block;width:14px;height:14px;border-radius:50%;\n border:2px solid #38bdf840;border-top-color:#38bdf8;\n animation:elur-spin .7s linear infinite\n \"></span>\n Loading…\n </span>\n <style>@keyframes elur-spin{to{transform:rotate(360deg)}}</style>\n `;\n}\n\nfunction defaultErrorTemplate(err: unknown): ElurTemplate {\n return html`\n <span style=\"color:#f87171;font-size:13px\">\n ⚠ ${err instanceof Error ? err.message : String(err)}\n </span>\n `;\n}\n\n// --- Suspense Cache ---\n\ninterface SuspenseCacheEntry<T = unknown> {\n data?: T;\n fetchedAt: number;\n subscribers: number;\n}\n\nconst _suspenseCache = new Map<string, SuspenseCacheEntry>();\n\nconst DEFAULT_CACHE_TIME = 5 * 60 * 1000;\nlet _suspenseGcTimer: ReturnType<typeof setInterval> | null = null;\nlet _suspenseCacheTime = DEFAULT_CACHE_TIME;\n\nfunction _startSuspenseGC(): void {\n if (_suspenseGcTimer !== null) return;\n _suspenseGcTimer = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of _suspenseCache) {\n if (entry.subscribers <= 0 && now - entry.fetchedAt > _suspenseCacheTime) {\n _suspenseCache.delete(key);\n }\n }\n if (_suspenseCache.size === 0 && _suspenseGcTimer !== null) {\n clearInterval(_suspenseGcTimer);\n _suspenseGcTimer = null;\n }\n }, 60_000);\n}\n\nfunction _getSuspenseCacheEntry<T>(key: string): SuspenseCacheEntry<T> | undefined {\n const entry = _suspenseCache.get(key);\n if (entry && entry.fetchedAt > 0) return entry as SuspenseCacheEntry<T>;\n return undefined;\n}\n\nfunction _setSuspenseCacheEntry<T>(key: string, data: T): void {\n const existing = _suspenseCache.get(key);\n _suspenseCache.set(key, {\n data,\n fetchedAt: Date.now(),\n subscribers: existing?.subscribers ?? 0,\n });\n _startSuspenseGC();\n}\n\nfunction _subscribeSuspenseCache(key: string): void {\n const entry = _suspenseCache.get(key);\n if (entry) {\n entry.subscribers++;\n } else {\n _suspenseCache.set(key, { fetchedAt: 0, subscribers: 1 } as SuspenseCacheEntry<any>);\n }\n}\n\nfunction _unsubscribeSuspenseCache(key: string): void {\n const entry = _suspenseCache.get(key);\n if (entry) entry.subscribers = Math.max(0, entry.subscribers - 1);\n}\n\nfunction _isSuspenseCacheFresh(key: string, staleTime: number): boolean {\n const entry = _suspenseCache.get(key);\n if (!entry) return false;\n return Date.now() - entry.fetchedAt < staleTime;\n}\n\n// --- suspend() ---\n\n/**\n * Runs an async function and renders based on its state (pending/resolved/error).\n *\n * ```ts\n * const refresh = signal(0);\n * suspend(() => fetchData(), render, { invalidate: refresh });\n * refresh.update(n => n + 1);\n * ```\n */\nexport function suspend<T>(\n asyncFn: () => Promise<T>,\n renderFn: (data: T) => ElurTemplate | ElurComponent,\n options: SuspenseOptions = {}\n): ElurComponent {\n const {\n fallback,\n errorFallback,\n resetOnRefresh = false,\n invalidate,\n cacheKey,\n staleTime = 0,\n } = options;\n\n const resolvedFallback = fallback ?? defaultLoadingFallback();\n const resolvedErrorFallback = errorFallback ?? defaultErrorTemplate;\n\n class SuspendComponent extends ElurComponent {\n private _state: Signal<AsyncState<T>>;\n private _disposeWatcher: (() => void) | undefined;\n\n constructor() {\n super();\n const cached = cacheKey ? _getSuspenseCacheEntry<T>(cacheKey) : undefined;\n\n this._state = signal<AsyncState<T>>(\n cached && cached.data !== undefined\n ? { status: \"resolved\", data: cached.data }\n : { status: \"pending\" }\n );\n }\n\n onMount(): (() => void) | void {\n if (cacheKey) _subscribeSuspenseCache(cacheKey);\n\n const cached = cacheKey ? _getSuspenseCacheEntry<T>(cacheKey) : undefined;\n\n if (cached && _isSuspenseCacheFresh(cacheKey!, staleTime)) {\n // fresh — skip\n } else if (cached) {\n this._fetch();\n } else {\n this._run();\n }\n\n if (invalidate) {\n let first = true;\n this._disposeWatcher = effect(() => {\n invalidate.value;\n if (first) { first = false; return; }\n if (cacheKey) _suspenseCache.delete(cacheKey);\n this._run();\n });\n }\n\n return () => {\n this._disposeWatcher?.();\n if (cacheKey) _unsubscribeSuspenseCache(cacheKey);\n };\n }\n\n private _run(): void {\n if (resetOnRefresh || this._state.peek().status === \"pending\") {\n this._state.value = { status: \"pending\" };\n }\n this._fetch();\n }\n\n private _fetch(): void {\n asyncFn().then(\n (data) => {\n if (cacheKey) _setSuspenseCacheEntry(cacheKey, data);\n this._state.value = { status: \"resolved\", data };\n },\n (err) => { this._state.value = { status: \"error\", error: err }; }\n );\n }\n\n render(): ElurTemplate {\n return html`<div class=\"elur-suspense\" style=\"display:contents\">${() => {\n const s = this._state.value;\n if (s.status === \"pending\") return resolvedFallback;\n if (s.status === \"error\") return resolvedErrorFallback(s.error);\n return renderFn(s.data);\n }}</div>`;\n }\n }\n\n return new SuspendComponent();\n}\n\n// --- lazy() ---\n\nexport interface LazyOptions {\n /** Component selector when the module uses a named export. Defaults to `mod.default`. */\n selector?: (mod: Record<string, unknown>) => new () => ElurComponent;\n /** Template shown while the component is loading. */\n fallback?: ElurTemplate;\n}\n\n/**\n * Wraps a dynamic import for lazy-loading route components.\n * The module is loaded once and cached. Supports both default and named exports.\n */\nexport function lazy(\n importFn: () => Promise<Record<string, unknown>>,\n options?: ElurTemplate | LazyOptions\n): () => ElurComponent {\n const opts: LazyOptions =\n options === undefined || isElurTemplate(options as object)\n ? { fallback: options as ElurTemplate | undefined }\n : (options as LazyOptions);\n\n const selector = opts.selector ?? ((mod) => mod.default as new () => ElurComponent);\n let Cached: (new () => ElurComponent) | null = null;\n\n return (): ElurComponent => {\n if (Cached) return new Cached();\n\n return suspend(\n async () => {\n const mod = await importFn();\n Cached = selector(mod);\n return Cached;\n },\n (Comp) => new Comp(),\n { fallback: opts.fallback }\n );\n };\n}"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { Signal } from "./reactivity.js";
2
+ import { ElurComponent } from "./lifecycle.js";
3
+ import { type ElurTemplate } from "./template/index.js";
4
+ export interface SuspenseOptions {
5
+ fallback?: ElurTemplate;
6
+ errorFallback?: (err: unknown) => ElurTemplate;
7
+ resetOnRefresh?: boolean;
8
+ invalidate?: Signal<unknown>;
9
+ cacheKey?: string;
10
+ staleTime?: number;
11
+ }
12
+ /**
13
+ * Runs an async function and renders based on its state (pending/resolved/error).
14
+ *
15
+ * ```ts
16
+ * const refresh = signal(0);
17
+ * suspend(() => fetchData(), render, { invalidate: refresh });
18
+ * refresh.update(n => n + 1);
19
+ * ```
20
+ */
21
+ export declare function suspend<T>(asyncFn: () => Promise<T>, renderFn: (data: T) => ElurTemplate | ElurComponent, options?: SuspenseOptions): ElurComponent;
22
+ export interface LazyOptions {
23
+ /** Component selector when the module uses a named export. Defaults to `mod.default`. */
24
+ selector?: (mod: Record<string, unknown>) => new () => ElurComponent;
25
+ /** Template shown while the component is loading. */
26
+ fallback?: ElurTemplate;
27
+ }
28
+ /**
29
+ * Wraps a dynamic import for lazy-loading route components.
30
+ * The module is loaded once and cached. Supports both default and named exports.
31
+ */
32
+ export declare function lazy(importFn: () => Promise<Record<string, unknown>>, options?: ElurTemplate | LazyOptions): () => ElurComponent;
@@ -0,0 +1,32 @@
1
+ import { Signal } from "./reactivity.js";
2
+ import { ElurComponent } from "./lifecycle.js";
3
+ import { type ElurTemplate } from "./template/index.js";
4
+ export interface SuspenseOptions {
5
+ fallback?: ElurTemplate;
6
+ errorFallback?: (err: unknown) => ElurTemplate;
7
+ resetOnRefresh?: boolean;
8
+ invalidate?: Signal<unknown>;
9
+ cacheKey?: string;
10
+ staleTime?: number;
11
+ }
12
+ /**
13
+ * Runs an async function and renders based on its state (pending/resolved/error).
14
+ *
15
+ * ```ts
16
+ * const refresh = signal(0);
17
+ * suspend(() => fetchData(), render, { invalidate: refresh });
18
+ * refresh.update(n => n + 1);
19
+ * ```
20
+ */
21
+ export declare function suspend<T>(asyncFn: () => Promise<T>, renderFn: (data: T) => ElurTemplate | ElurComponent, options?: SuspenseOptions): ElurComponent;
22
+ export interface LazyOptions {
23
+ /** Component selector when the module uses a named export. Defaults to `mod.default`. */
24
+ selector?: (mod: Record<string, unknown>) => new () => ElurComponent;
25
+ /** Template shown while the component is loading. */
26
+ fallback?: ElurTemplate;
27
+ }
28
+ /**
29
+ * Wraps a dynamic import for lazy-loading route components.
30
+ * The module is loaded once and cached. Supports both default and named exports.
31
+ */
32
+ export declare function lazy(importFn: () => Promise<Record<string, unknown>>, options?: ElurTemplate | LazyOptions): () => ElurComponent;
@@ -0,0 +1,123 @@
1
+ import { effect as e, signal as t } from "./signals.js";
2
+ import { isElurTemplate as n } from "./elur/template/types.js";
3
+ import { ElurComponent as r } from "./lifecycle.js";
4
+ import { html as i } from "./elur/template/html.js";
5
+ //#region src/elur/async.ts
6
+ function a() {
7
+ return i`
8
+ <span style="color:#52525b;font-size:13px;display:inline-flex;align-items:center;gap:6px">
9
+ <span class="elur-spinner" style="
10
+ display:inline-block;width:14px;height:14px;border-radius:50%;
11
+ border:2px solid #38bdf840;border-top-color:#38bdf8;
12
+ animation:elur-spin .7s linear infinite
13
+ "></span>
14
+ Loading…
15
+ </span>
16
+ <style>@keyframes elur-spin{to{transform:rotate(360deg)}}</style>
17
+ `;
18
+ }
19
+ function o(e) {
20
+ return i`
21
+ <span style="color:#f87171;font-size:13px">
22
+ ⚠ ${e instanceof Error ? e.message : String(e)}
23
+ </span>
24
+ `;
25
+ }
26
+ var s = /* @__PURE__ */ new Map(), c = 300 * 1e3, l = null, u = c;
27
+ function d() {
28
+ l === null && (l = setInterval(() => {
29
+ let e = Date.now();
30
+ for (let [t, n] of s) n.subscribers <= 0 && e - n.fetchedAt > u && s.delete(t);
31
+ s.size === 0 && l !== null && (clearInterval(l), l = null);
32
+ }, 6e4));
33
+ }
34
+ function f(e) {
35
+ let t = s.get(e);
36
+ if (t && t.fetchedAt > 0) return t;
37
+ }
38
+ function p(e, t) {
39
+ let n = s.get(e);
40
+ s.set(e, {
41
+ data: t,
42
+ fetchedAt: Date.now(),
43
+ subscribers: n?.subscribers ?? 0
44
+ }), d();
45
+ }
46
+ function m(e) {
47
+ let t = s.get(e);
48
+ t ? t.subscribers++ : s.set(e, {
49
+ fetchedAt: 0,
50
+ subscribers: 1
51
+ });
52
+ }
53
+ function h(e) {
54
+ let t = s.get(e);
55
+ t && (t.subscribers = Math.max(0, t.subscribers - 1));
56
+ }
57
+ function g(e, t) {
58
+ let n = s.get(e);
59
+ return n ? Date.now() - n.fetchedAt < t : !1;
60
+ }
61
+ function _(n, c, l = {}) {
62
+ let { fallback: u, errorFallback: d, resetOnRefresh: _ = !1, invalidate: v, cacheKey: y, staleTime: b = 0 } = l, x = u ?? a(), S = d ?? o;
63
+ class C extends r {
64
+ _state;
65
+ _disposeWatcher;
66
+ constructor() {
67
+ super();
68
+ let e = y ? f(y) : void 0;
69
+ this._state = t(e && e.data !== void 0 ? {
70
+ status: "resolved",
71
+ data: e.data
72
+ } : { status: "pending" });
73
+ }
74
+ onMount() {
75
+ y && m(y);
76
+ let t = y ? f(y) : void 0;
77
+ if (t && g(y, b) || (t ? this._fetch() : this._run()), v) {
78
+ let t = !0;
79
+ this._disposeWatcher = e(() => {
80
+ if (v.value, t) {
81
+ t = !1;
82
+ return;
83
+ }
84
+ y && s.delete(y), this._run();
85
+ });
86
+ }
87
+ return () => {
88
+ this._disposeWatcher?.(), y && h(y);
89
+ };
90
+ }
91
+ _run() {
92
+ (_ || this._state.peek().status === "pending") && (this._state.value = { status: "pending" }), this._fetch();
93
+ }
94
+ _fetch() {
95
+ n().then((e) => {
96
+ y && p(y, e), this._state.value = {
97
+ status: "resolved",
98
+ data: e
99
+ };
100
+ }, (e) => {
101
+ this._state.value = {
102
+ status: "error",
103
+ error: e
104
+ };
105
+ });
106
+ }
107
+ render() {
108
+ return i`<div class="elur-suspense" style="display:contents">${() => {
109
+ let e = this._state.value;
110
+ return e.status === "pending" ? x : e.status === "error" ? S(e.error) : c(e.data);
111
+ }}</div>`;
112
+ }
113
+ }
114
+ return new C();
115
+ }
116
+ function v(e, t) {
117
+ let r = t === void 0 || n(t) ? { fallback: t } : t, i = r.selector ?? ((e) => e.default), a = null;
118
+ return () => a ? new a() : _(async () => (a = i(await e()), a), (e) => new e(), { fallback: r.fallback });
119
+ }
120
+ //#endregion
121
+ export { v as lazy, _ as suspend };
122
+
123
+ //# sourceMappingURL=async.js.map