@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.
- package/LICENSE +21 -0
- package/README.md +157 -0
- package/dist/lib/async.cjs +16 -0
- package/dist/lib/async.js +123 -0
- package/dist/lib/component.cjs +2 -0
- package/dist/lib/component.js +66 -0
- package/dist/lib/context.cjs +2 -0
- package/dist/lib/context.js +52 -0
- package/dist/lib/devtools.cjs +59 -0
- package/dist/lib/devtools.js +419 -0
- package/dist/lib/elur/async.cjs +16 -0
- package/dist/lib/elur/async.cjs.map +1 -0
- package/dist/lib/elur/async.d.cts +32 -0
- package/dist/lib/elur/async.d.ts +32 -0
- package/dist/lib/elur/async.js +123 -0
- package/dist/lib/elur/async.js.map +1 -0
- package/dist/lib/elur/component.cjs +2 -0
- package/dist/lib/elur/component.cjs.map +1 -0
- package/dist/lib/elur/component.d.cts +17 -0
- package/dist/lib/elur/component.d.ts +17 -0
- package/dist/lib/elur/component.js +66 -0
- package/dist/lib/elur/component.js.map +1 -0
- package/dist/lib/elur/context.cjs +2 -0
- package/dist/lib/elur/context.cjs.map +1 -0
- package/dist/lib/elur/context.d.cts +29 -0
- package/dist/lib/elur/context.d.ts +29 -0
- package/dist/lib/elur/context.js +52 -0
- package/dist/lib/elur/context.js.map +1 -0
- package/dist/lib/elur/devtools.cjs +59 -0
- package/dist/lib/elur/devtools.cjs.map +1 -0
- package/dist/lib/elur/devtools.d.cts +24 -0
- package/dist/lib/elur/devtools.d.ts +24 -0
- package/dist/lib/elur/devtools.js +419 -0
- package/dist/lib/elur/devtools.js.map +1 -0
- package/dist/lib/elur/form.cjs +2 -0
- package/dist/lib/elur/form.cjs.map +1 -0
- package/dist/lib/elur/form.d.cts +283 -0
- package/dist/lib/elur/form.d.ts +283 -0
- package/dist/lib/elur/form.js +315 -0
- package/dist/lib/elur/form.js.map +1 -0
- package/dist/lib/elur/hydrate/index.cjs +2 -0
- package/dist/lib/elur/hydrate/index.cjs.map +1 -0
- package/dist/lib/elur/hydrate/index.d.cts +13 -0
- package/dist/lib/elur/hydrate/index.d.ts +13 -0
- package/dist/lib/elur/hydrate/index.js +410 -0
- package/dist/lib/elur/hydrate/index.js.map +1 -0
- package/dist/lib/elur/index.d.cts +19 -0
- package/dist/lib/elur/index.d.ts +19 -0
- package/dist/lib/elur/lifecycle.cjs +2 -0
- package/dist/lib/elur/lifecycle.cjs.map +1 -0
- package/dist/lib/elur/lifecycle.d.cts +45 -0
- package/dist/lib/elur/lifecycle.d.ts +45 -0
- package/dist/lib/elur/lifecycle.js +39 -0
- package/dist/lib/elur/lifecycle.js.map +1 -0
- package/dist/lib/elur/plugins.cjs +2 -0
- package/dist/lib/elur/plugins.cjs.map +1 -0
- package/dist/lib/elur/plugins.d.cts +48 -0
- package/dist/lib/elur/plugins.d.ts +48 -0
- package/dist/lib/elur/plugins.js +59 -0
- package/dist/lib/elur/plugins.js.map +1 -0
- package/dist/lib/elur/reactivity.cjs +2 -0
- package/dist/lib/elur/reactivity.cjs.map +1 -0
- package/dist/lib/elur/reactivity.d.cts +60 -0
- package/dist/lib/elur/reactivity.d.ts +60 -0
- package/dist/lib/elur/reactivity.js +188 -0
- package/dist/lib/elur/reactivity.js.map +1 -0
- package/dist/lib/elur/router.cjs +12 -0
- package/dist/lib/elur/router.cjs.map +1 -0
- package/dist/lib/elur/router.d.cts +137 -0
- package/dist/lib/elur/router.d.ts +137 -0
- package/dist/lib/elur/router.js +513 -0
- package/dist/lib/elur/router.js.map +1 -0
- package/dist/lib/elur/server/index.cjs +2 -0
- package/dist/lib/elur/server/index.cjs.map +1 -0
- package/dist/lib/elur/server/index.d.cts +44 -0
- package/dist/lib/elur/server/index.d.ts +44 -0
- package/dist/lib/elur/server/index.js +307 -0
- package/dist/lib/elur/server/index.js.map +1 -0
- package/dist/lib/elur/store.cjs +2 -0
- package/dist/lib/elur/store.cjs.map +1 -0
- package/dist/lib/elur/store.d.cts +137 -0
- package/dist/lib/elur/store.d.ts +137 -0
- package/dist/lib/elur/store.js +143 -0
- package/dist/lib/elur/store.js.map +1 -0
- package/dist/lib/elur/template/bindings.cjs +2 -0
- package/dist/lib/elur/template/bindings.cjs.map +1 -0
- package/dist/lib/elur/template/bindings.d.cts +40 -0
- package/dist/lib/elur/template/bindings.d.ts +40 -0
- package/dist/lib/elur/template/bindings.js +214 -0
- package/dist/lib/elur/template/bindings.js.map +1 -0
- package/dist/lib/elur/template/dom-write.cjs +2 -0
- package/dist/lib/elur/template/dom-write.cjs.map +1 -0
- package/dist/lib/elur/template/dom-write.d.cts +5 -0
- package/dist/lib/elur/template/dom-write.d.ts +5 -0
- package/dist/lib/elur/template/dom-write.js +16 -0
- package/dist/lib/elur/template/dom-write.js.map +1 -0
- package/dist/lib/elur/template/error-boundary.cjs +2 -0
- package/dist/lib/elur/template/error-boundary.cjs.map +1 -0
- package/dist/lib/elur/template/error-boundary.d.cts +7 -0
- package/dist/lib/elur/template/error-boundary.d.ts +7 -0
- package/dist/lib/elur/template/error-boundary.js +90 -0
- package/dist/lib/elur/template/error-boundary.js.map +1 -0
- package/dist/lib/elur/template/html.cjs +2 -0
- package/dist/lib/elur/template/html.cjs.map +1 -0
- package/dist/lib/elur/template/html.d.cts +8 -0
- package/dist/lib/elur/template/html.d.ts +8 -0
- package/dist/lib/elur/template/html.js +104 -0
- package/dist/lib/elur/template/html.js.map +1 -0
- package/dist/lib/elur/template/index.cjs +1 -0
- package/dist/lib/elur/template/index.d.cts +15 -0
- package/dist/lib/elur/template/index.d.ts +15 -0
- package/dist/lib/elur/template/index.js +13 -0
- package/dist/lib/elur/template/keyed-diff.cjs +2 -0
- package/dist/lib/elur/template/keyed-diff.cjs.map +1 -0
- package/dist/lib/elur/template/keyed-diff.d.cts +32 -0
- package/dist/lib/elur/template/keyed-diff.d.ts +32 -0
- package/dist/lib/elur/template/keyed-diff.js +100 -0
- package/dist/lib/elur/template/keyed-diff.js.map +1 -0
- package/dist/lib/elur/template/keyed.cjs +2 -0
- package/dist/lib/elur/template/keyed.cjs.map +1 -0
- package/dist/lib/elur/template/keyed.d.cts +27 -0
- package/dist/lib/elur/template/keyed.d.ts +27 -0
- package/dist/lib/elur/template/keyed.js +52 -0
- package/dist/lib/elur/template/keyed.js.map +1 -0
- package/dist/lib/elur/template/mount-helpers.cjs +2 -0
- package/dist/lib/elur/template/mount-helpers.cjs.map +1 -0
- package/dist/lib/elur/template/mount-helpers.d.cts +29 -0
- package/dist/lib/elur/template/mount-helpers.d.ts +29 -0
- package/dist/lib/elur/template/mount-helpers.js +132 -0
- package/dist/lib/elur/template/mount-helpers.js.map +1 -0
- package/dist/lib/elur/template/node-binding.cjs +2 -0
- package/dist/lib/elur/template/node-binding.cjs.map +1 -0
- package/dist/lib/elur/template/node-binding.d.cts +6 -0
- package/dist/lib/elur/template/node-binding.d.ts +6 -0
- package/dist/lib/elur/template/node-binding.js +95 -0
- package/dist/lib/elur/template/node-binding.js.map +1 -0
- package/dist/lib/elur/template/portal.cjs +2 -0
- package/dist/lib/elur/template/portal.cjs.map +1 -0
- package/dist/lib/elur/template/portal.d.cts +19 -0
- package/dist/lib/elur/template/portal.d.ts +19 -0
- package/dist/lib/elur/template/portal.js +49 -0
- package/dist/lib/elur/template/portal.js.map +1 -0
- package/dist/lib/elur/template/raw.cjs +2 -0
- package/dist/lib/elur/template/raw.cjs.map +1 -0
- package/dist/lib/elur/template/raw.d.cts +9 -0
- package/dist/lib/elur/template/raw.d.ts +9 -0
- package/dist/lib/elur/template/raw.js +29 -0
- package/dist/lib/elur/template/raw.js.map +1 -0
- package/dist/lib/elur/template/sanitize.cjs +2 -0
- package/dist/lib/elur/template/sanitize.cjs.map +1 -0
- package/dist/lib/elur/template/sanitize.d.cts +16 -0
- package/dist/lib/elur/template/sanitize.d.ts +16 -0
- package/dist/lib/elur/template/sanitize.js +29 -0
- package/dist/lib/elur/template/sanitize.js.map +1 -0
- package/dist/lib/elur/template/transitions.cjs +2 -0
- package/dist/lib/elur/template/transitions.cjs.map +1 -0
- package/dist/lib/elur/template/transitions.d.cts +43 -0
- package/dist/lib/elur/template/transitions.d.ts +43 -0
- package/dist/lib/elur/template/transitions.js +96 -0
- package/dist/lib/elur/template/transitions.js.map +1 -0
- package/dist/lib/elur/template/types.cjs +2 -0
- package/dist/lib/elur/template/types.cjs.map +1 -0
- package/dist/lib/elur/template/types.d.cts +114 -0
- package/dist/lib/elur/template/types.d.ts +114 -0
- package/dist/lib/elur/template/types.js +23 -0
- package/dist/lib/elur/template/types.js.map +1 -0
- package/dist/lib/elur.cjs +1 -0
- package/dist/lib/elur.js +18 -0
- package/dist/lib/form.cjs +2 -0
- package/dist/lib/form.js +315 -0
- package/dist/lib/hydrate.cjs +2 -0
- package/dist/lib/hydrate.js +410 -0
- package/dist/lib/index.cjs +1 -0
- package/dist/lib/index.d.cts +2 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.js +18 -0
- package/dist/lib/lifecycle.cjs +2 -0
- package/dist/lib/lifecycle.js +39 -0
- package/dist/lib/plugins.cjs +2 -0
- package/dist/lib/plugins.js +59 -0
- package/dist/lib/router.cjs +12 -0
- package/dist/lib/router.js +513 -0
- package/dist/lib/server.cjs +2 -0
- package/dist/lib/server.js +307 -0
- package/dist/lib/signals.cjs +2 -0
- package/dist/lib/signals.js +188 -0
- package/dist/lib/store.cjs +2 -0
- package/dist/lib/store.js +143 -0
- package/dist/lib/template.cjs +1 -0
- package/dist/lib/template.js +13 -0
- 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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\"/g, """).replace(/'/g, "'");
|
|
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
|