elit 3.6.5 → 3.6.7
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/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/README.md +6 -0
- package/dist/build.cjs +421 -331
- package/dist/build.d.ts +1 -16
- package/dist/build.js +420 -330
- package/dist/build.mjs +420 -330
- package/dist/chokidar.cjs +219 -182
- package/dist/chokidar.d.ts +25 -10
- package/dist/chokidar.js +217 -182
- package/dist/chokidar.mjs +218 -183
- package/dist/cli.cjs +21608 -20241
- package/dist/cli.d.ts +19 -37
- package/dist/cli.mjs +21262 -19910
- package/dist/config.cjs +357 -350
- package/dist/config.d.ts +19 -240
- package/dist/config.js +520 -515
- package/dist/config.mjs +346 -341
- package/dist/contracts-BeW9k0yZ.d.ts +54 -0
- package/dist/contracts-D7KIS-TK.d.ts +36 -0
- package/dist/coverage.cjs +448 -485
- package/dist/coverage.d.ts +13 -59
- package/dist/coverage.js +447 -484
- package/dist/coverage.mjs +447 -484
- package/dist/database.cjs +819 -828
- package/dist/database.d.ts +8 -24
- package/dist/database.js +818 -829
- package/dist/database.mjs +818 -829
- package/dist/desktop-auto-render.cjs +1700 -1522
- package/dist/desktop-auto-render.d.ts +4 -9
- package/dist/desktop-auto-render.js +1695 -1517
- package/dist/desktop-auto-render.mjs +1696 -1518
- package/dist/desktop.cjs +3 -1
- package/dist/desktop.d.ts +4 -1
- package/dist/desktop.js +1 -1
- package/dist/desktop.mjs +1 -1
- package/dist/dev-build.cjs +830 -0
- package/dist/dev-build.d.ts +53 -0
- package/dist/dev-build.js +3318 -0
- package/dist/dev-build.mjs +797 -0
- package/dist/dom.cjs +717 -590
- package/dist/dom.d.ts +2 -15
- package/dist/dom.js +714 -587
- package/dist/dom.mjs +716 -589
- package/dist/el.cjs +62 -52
- package/dist/el.d.ts +5 -10
- package/dist/el.js +60 -52
- package/dist/el.mjs +60 -52
- package/dist/fs.cjs +72 -63
- package/dist/fs.d.ts +22 -19
- package/dist/fs.js +71 -62
- package/dist/fs.mjs +71 -62
- package/dist/hmr.cjs +40 -14
- package/dist/hmr.d.ts +11 -23
- package/dist/hmr.js +38 -14
- package/dist/hmr.mjs +38 -14
- package/dist/http.cjs +251 -99
- package/dist/http.d.ts +38 -104
- package/dist/http.js +249 -99
- package/dist/http.mjs +249 -99
- package/dist/https.cjs +524 -228
- package/dist/https.d.ts +44 -36
- package/dist/https.js +520 -226
- package/dist/https.mjs +522 -228
- package/dist/index.cjs +7502 -7690
- package/dist/index.d.ts +8 -3
- package/dist/index.js +7486 -7676
- package/dist/index.mjs +7497 -7686
- package/dist/mime-types.cjs +10 -4
- package/dist/mime-types.d.ts +8 -11
- package/dist/mime-types.js +9 -3
- package/dist/mime-types.mjs +9 -3
- package/dist/native.cjs +8616 -8869
- package/dist/native.d.ts +7 -8
- package/dist/native.js +8682 -8935
- package/dist/native.mjs +8615 -8868
- package/dist/path.cjs +83 -77
- package/dist/path.d.ts +29 -29
- package/dist/path.js +82 -76
- package/dist/path.mjs +82 -76
- package/dist/pm.cjs +3300 -0
- package/dist/pm.d.ts +256 -0
- package/dist/pm.js +5638 -0
- package/dist/pm.mjs +3196 -0
- package/dist/preview-build.cjs +712 -0
- package/dist/preview-build.d.ts +59 -0
- package/dist/preview-build.js +3194 -0
- package/dist/preview-build.mjs +676 -0
- package/dist/render-context.cjs +13 -2
- package/dist/render-context.d.ts +9 -31
- package/dist/render-context.js +11 -2
- package/dist/render-context.mjs +11 -2
- package/dist/router.cjs +787 -645
- package/dist/router.d.ts +8 -12
- package/dist/router.js +786 -644
- package/dist/router.mjs +786 -644
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/server.cjs +3315 -2603
- package/dist/server.d.ts +49 -4
- package/dist/server.js +7611 -2834
- package/dist/server.mjs +3317 -2607
- package/dist/smtp-server.cjs +128 -0
- package/dist/smtp-server.d.ts +27 -0
- package/dist/smtp-server.js +4199 -0
- package/dist/smtp-server.mjs +100 -0
- package/dist/state-DvEkDehk.d.ts +195 -0
- package/dist/state.cjs +768 -658
- package/dist/state.d.ts +11 -69
- package/dist/state.js +760 -650
- package/dist/state.mjs +767 -657
- package/dist/style.cjs +1011 -968
- package/dist/style.d.ts +13 -127
- package/dist/style.js +1009 -970
- package/dist/style.mjs +1011 -971
- package/dist/test-reporter.cjs +332 -316
- package/dist/test-reporter.d.ts +28 -33
- package/dist/test-reporter.js +328 -312
- package/dist/test-reporter.mjs +328 -312
- package/dist/test-runtime.cjs +927 -968
- package/dist/test-runtime.d.ts +24 -99
- package/dist/test-runtime.js +922 -965
- package/dist/test-runtime.mjs +922 -965
- package/dist/test.cjs +4428 -4273
- package/dist/test.d.ts +2 -8
- package/dist/test.js +4307 -4154
- package/dist/test.mjs +4419 -4267
- package/dist/types-BONVzPtp.d.ts +59 -0
- package/dist/types-BR4wMiVx.d.ts +32 -0
- package/dist/types-C4gKykuG.d.ts +23 -0
- package/dist/types-CIhpN1-K.d.ts +64 -0
- package/dist/types-Ckj8md_j.d.ts +84 -0
- package/dist/types-CpjQTAkX.d.ts +24 -0
- package/dist/types-D0LjrYjS.d.ts +14 -0
- package/dist/types-DAisuVr5.d.ts +75 -0
- package/dist/types-tJn88E1N.d.ts +242 -0
- package/dist/types.d.ts +71 -226
- package/dist/universal.cjs +1 -1
- package/dist/universal.d.ts +1 -5
- package/dist/universal.js +1 -1
- package/dist/universal.mjs +1 -1
- package/dist/websocket-XfyK23zD.d.ts +119 -0
- package/dist/ws.cjs +129 -108
- package/dist/ws.d.ts +21 -131
- package/dist/ws.js +128 -109
- package/dist/ws.mjs +128 -109
- package/dist/wss.cjs +757 -479
- package/dist/wss.d.ts +31 -28
- package/dist/wss.js +755 -479
- package/dist/wss.mjs +758 -482
- package/package.json +16 -1
- package/vendor/epaint-0.31.1/src/image.rs +418 -0
- package/dist/server-CcBFc2F5.d.ts +0 -449
package/dist/state.mjs
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
// src/render-context.ts
|
|
1
|
+
// src/desktop/render-context/constants.ts
|
|
2
2
|
var RUNTIME_TARGET_KEY = "__ELIT_RUNTIME_TARGET__";
|
|
3
3
|
var CAPTURED_RENDER_KEY = "__ELIT_CAPTURED_RENDER__";
|
|
4
4
|
var RUNTIME_TARGET_ENV = "ELIT_RUNTIME_TARGET";
|
|
5
|
+
|
|
6
|
+
// src/desktop/render-context/globals.ts
|
|
5
7
|
function getGlobalRenderScope() {
|
|
6
8
|
return globalThis;
|
|
7
9
|
}
|
|
10
|
+
|
|
11
|
+
// src/desktop/render-context/runtime-target.ts
|
|
8
12
|
function isRenderRuntimeTarget(value) {
|
|
9
13
|
return value === "web" || value === "desktop" || value === "mobile" || value === "unknown";
|
|
10
14
|
}
|
|
@@ -20,7 +24,8 @@ function detectRenderRuntimeTarget() {
|
|
|
20
24
|
if (typeof globalScope.createWindow === "function") {
|
|
21
25
|
return "desktop";
|
|
22
26
|
}
|
|
23
|
-
const
|
|
27
|
+
const argvValues = globalScope.process?.argv;
|
|
28
|
+
const argv = Array.isArray(argvValues) ? argvValues.join(" ") : "";
|
|
24
29
|
if (/\bdesktop\b/i.test(argv)) {
|
|
25
30
|
return "desktop";
|
|
26
31
|
}
|
|
@@ -29,6 +34,8 @@ function detectRenderRuntimeTarget() {
|
|
|
29
34
|
}
|
|
30
35
|
return "unknown";
|
|
31
36
|
}
|
|
37
|
+
|
|
38
|
+
// src/desktop/render-context/captured-render.ts
|
|
32
39
|
function captureRenderedVNode(rootElement, vNode, target = detectRenderRuntimeTarget()) {
|
|
33
40
|
const globalScope = getGlobalRenderScope();
|
|
34
41
|
globalScope[RUNTIME_TARGET_KEY] = target;
|
|
@@ -39,7 +46,7 @@ function captureRenderedVNode(rootElement, vNode, target = detectRenderRuntimeTa
|
|
|
39
46
|
};
|
|
40
47
|
}
|
|
41
48
|
|
|
42
|
-
// src/dom.ts
|
|
49
|
+
// src/client/dom/helpers.ts
|
|
43
50
|
function resolveElement(rootElement) {
|
|
44
51
|
return typeof rootElement === "string" ? document.getElementById(rootElement.replace("#", "")) : rootElement;
|
|
45
52
|
}
|
|
@@ -67,668 +74,788 @@ function resolveTextareaValue(tagName, props) {
|
|
|
67
74
|
function hasDocumentApi() {
|
|
68
75
|
return typeof document !== "undefined";
|
|
69
76
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
});
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
if (Array.isArray(vNode)) {
|
|
93
|
-
for (const child of vNode) {
|
|
94
|
-
this.renderToDOM(child, parent);
|
|
77
|
+
function isState(value) {
|
|
78
|
+
return value && typeof value === "object" && "value" in value && "subscribe" in value && typeof value.subscribe === "function";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/client/dom/dom-render.ts
|
|
82
|
+
function isSvgElement(tagName, parent) {
|
|
83
|
+
return tagName === "svg" || tagName[0] === "s" && tagName[1] === "v" && tagName[2] === "g" || parent.namespaceURI === "http://www.w3.org/2000/svg";
|
|
84
|
+
}
|
|
85
|
+
function applyProps(el, props, textareaValue) {
|
|
86
|
+
for (const key in props) {
|
|
87
|
+
const value = props[key];
|
|
88
|
+
if (value == null || value === false) continue;
|
|
89
|
+
const c = key.charCodeAt(0);
|
|
90
|
+
if (c === 99 && (key.length < 6 || key[5] === "N")) {
|
|
91
|
+
const classValue = Array.isArray(value) ? value.join(" ") : String(value);
|
|
92
|
+
if (el instanceof SVGElement) {
|
|
93
|
+
el.setAttribute("class", classValue);
|
|
94
|
+
} else {
|
|
95
|
+
el.className = classValue;
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (Array.isArray(child)) {
|
|
104
|
-
for (const c of child) {
|
|
105
|
-
!shouldSkipChild(c) && this.renderToDOM(c, parent);
|
|
106
|
-
}
|
|
107
|
-
} else {
|
|
108
|
-
this.renderToDOM(child, parent);
|
|
97
|
+
} else if (c === 115 && key.length === 5) {
|
|
98
|
+
if (typeof value === "string") {
|
|
99
|
+
el.style.cssText = value;
|
|
100
|
+
} else {
|
|
101
|
+
const style = el.style;
|
|
102
|
+
for (const styleKey in value) {
|
|
103
|
+
style[styleKey] = value[styleKey];
|
|
109
104
|
}
|
|
110
105
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (c === 99 && (key.length < 6 || key[5] === "N")) {
|
|
120
|
-
const classValue = Array.isArray(value) ? value.join(" ") : value;
|
|
121
|
-
isSVG ? el.setAttribute("class", classValue) : el.className = classValue;
|
|
122
|
-
} else if (c === 115 && key.length === 5) {
|
|
123
|
-
if (typeof value === "string") {
|
|
124
|
-
el.style.cssText = value;
|
|
106
|
+
} else if (c === 111 && key.charCodeAt(1) === 110) {
|
|
107
|
+
el[key.toLowerCase()] = value;
|
|
108
|
+
} else if (c === 100 && key.length > 20) {
|
|
109
|
+
el.innerHTML = value.__html;
|
|
110
|
+
} else if (c === 114 && key === "ref") {
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
if (typeof value === "function") {
|
|
113
|
+
value(el);
|
|
125
114
|
} else {
|
|
126
|
-
|
|
127
|
-
for (const k in value) s[k] = value[k];
|
|
115
|
+
value.current = el;
|
|
128
116
|
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
setTimeout(() => {
|
|
135
|
-
typeof value === "function" ? value(el) : value.current = el;
|
|
136
|
-
}, 0);
|
|
137
|
-
} else if (textareaValue !== void 0 && key === "value") {
|
|
138
|
-
continue;
|
|
139
|
-
} else {
|
|
140
|
-
el.setAttribute(key, value === true ? "" : String(value));
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
const renderableChildren = textareaValue === void 0 ? children : [];
|
|
144
|
-
const len = renderableChildren.length;
|
|
145
|
-
if (!len) {
|
|
146
|
-
if (textareaValue !== void 0) {
|
|
147
|
-
el.value = textareaValue;
|
|
148
|
-
}
|
|
149
|
-
parent.appendChild(el);
|
|
150
|
-
return;
|
|
117
|
+
}, 0);
|
|
118
|
+
} else if (textareaValue !== void 0 && key === "value") {
|
|
119
|
+
continue;
|
|
120
|
+
} else {
|
|
121
|
+
el.setAttribute(key, value === true ? "" : String(value));
|
|
151
122
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function renderChildren(children, target) {
|
|
126
|
+
const len = children.length;
|
|
127
|
+
for (let i = 0; i < len; i++) {
|
|
128
|
+
const child = children[i];
|
|
129
|
+
if (shouldSkipChild(child)) continue;
|
|
130
|
+
if (Array.isArray(child)) {
|
|
131
|
+
for (let j = 0, childLen = child.length; j < childLen; j++) {
|
|
132
|
+
const nestedChild = child[j];
|
|
133
|
+
if (!shouldSkipChild(nestedChild)) {
|
|
134
|
+
renderToDOM(nestedChild, target);
|
|
163
135
|
}
|
|
164
136
|
}
|
|
165
|
-
};
|
|
166
|
-
if (len > 30) {
|
|
167
|
-
const fragment = document.createDocumentFragment();
|
|
168
|
-
renderChildren(fragment);
|
|
169
|
-
el.appendChild(fragment);
|
|
170
137
|
} else {
|
|
171
|
-
|
|
138
|
+
renderToDOM(child, target);
|
|
172
139
|
}
|
|
173
|
-
parent.appendChild(el);
|
|
174
140
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
141
|
+
}
|
|
142
|
+
function renderToDOM(vNode, parent) {
|
|
143
|
+
if (vNode == null || vNode === false) return;
|
|
144
|
+
if (typeof vNode !== "object") {
|
|
145
|
+
parent.appendChild(document.createTextNode(String(vNode)));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (isState(vNode)) {
|
|
149
|
+
const textNode = document.createTextNode(String(vNode.value ?? ""));
|
|
150
|
+
parent.appendChild(textNode);
|
|
151
|
+
vNode.subscribe((newValue) => {
|
|
152
|
+
textNode.textContent = String(newValue ?? "");
|
|
153
|
+
});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (Array.isArray(vNode)) {
|
|
157
|
+
for (const child of vNode) {
|
|
158
|
+
renderToDOM(child, parent);
|
|
183
159
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const { tagName, props, children } = vNode;
|
|
163
|
+
const textareaValue = resolveTextareaValue(tagName, props);
|
|
164
|
+
if (!tagName) {
|
|
165
|
+
renderChildren(children, parent);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const el = isSvgElement(tagName, parent) ? document.createElementNS("http://www.w3.org/2000/svg", tagName.replace("svg", "").toLowerCase() || tagName) : document.createElement(tagName);
|
|
169
|
+
applyProps(el, props, textareaValue);
|
|
170
|
+
const renderableChildren = textareaValue === void 0 ? children : [];
|
|
171
|
+
if (!renderableChildren.length) {
|
|
172
|
+
if (textareaValue !== void 0) {
|
|
173
|
+
el.value = textareaValue;
|
|
192
174
|
}
|
|
193
|
-
|
|
175
|
+
parent.appendChild(el);
|
|
176
|
+
return;
|
|
194
177
|
}
|
|
195
|
-
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
} else {
|
|
211
|
-
requestAnimationFrame(processChunk);
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
processChunk();
|
|
215
|
-
} else {
|
|
216
|
-
const fragment = document.createDocumentFragment();
|
|
217
|
-
for (let i = 0; i < len; i++) {
|
|
218
|
-
this.renderToDOM(vNodes[i], fragment);
|
|
219
|
-
}
|
|
220
|
-
el.appendChild(fragment);
|
|
178
|
+
if (renderableChildren.length > 30) {
|
|
179
|
+
const fragment = document.createDocumentFragment();
|
|
180
|
+
renderChildren(renderableChildren, fragment);
|
|
181
|
+
el.appendChild(fragment);
|
|
182
|
+
} else {
|
|
183
|
+
renderChildren(renderableChildren, el);
|
|
184
|
+
}
|
|
185
|
+
parent.appendChild(el);
|
|
186
|
+
}
|
|
187
|
+
function render(rootElement, vNode) {
|
|
188
|
+
if (!hasDocumentApi()) {
|
|
189
|
+
const runtimeTarget = detectRenderRuntimeTarget();
|
|
190
|
+
if (runtimeTarget === "desktop" || runtimeTarget === "mobile") {
|
|
191
|
+
captureRenderedVNode(rootElement, vNode, runtimeTarget);
|
|
192
|
+
return {};
|
|
221
193
|
}
|
|
222
|
-
|
|
194
|
+
throw new Error("render() requires a DOM or an Elit desktop/mobile runtime target.");
|
|
195
|
+
}
|
|
196
|
+
const el = ensureElement(resolveElement(rootElement), rootElement);
|
|
197
|
+
el.innerHTML = "";
|
|
198
|
+
if (vNode.children && vNode.children.length > 500) {
|
|
199
|
+
const fragment = document.createDocumentFragment();
|
|
200
|
+
renderToDOM(vNode, fragment);
|
|
201
|
+
el.appendChild(fragment);
|
|
202
|
+
} else {
|
|
203
|
+
renderToDOM(vNode, el);
|
|
223
204
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
205
|
+
return el;
|
|
206
|
+
}
|
|
207
|
+
function batchRender(rootElement, vNodes) {
|
|
208
|
+
const el = ensureElement(resolveElement(rootElement), rootElement);
|
|
209
|
+
const len = vNodes.length;
|
|
210
|
+
if (len > 3e3) {
|
|
211
|
+
const fragment = document.createDocumentFragment();
|
|
212
|
+
let processed = 0;
|
|
213
|
+
const chunkSize = 1500;
|
|
214
|
+
const processChunk = () => {
|
|
215
|
+
const end = Math.min(processed + chunkSize, len);
|
|
216
|
+
for (let i = processed; i < end; i++) {
|
|
217
|
+
renderToDOM(vNodes[i], fragment);
|
|
233
218
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
requestAnimationFrame(
|
|
219
|
+
processed = end;
|
|
220
|
+
if (processed >= len) {
|
|
221
|
+
el.appendChild(fragment);
|
|
222
|
+
} else {
|
|
223
|
+
requestAnimationFrame(processChunk);
|
|
239
224
|
}
|
|
240
225
|
};
|
|
241
|
-
|
|
242
|
-
|
|
226
|
+
processChunk();
|
|
227
|
+
} else {
|
|
228
|
+
const fragment = document.createDocumentFragment();
|
|
229
|
+
for (let i = 0; i < len; i++) {
|
|
230
|
+
renderToDOM(vNodes[i], fragment);
|
|
231
|
+
}
|
|
232
|
+
el.appendChild(fragment);
|
|
243
233
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
234
|
+
return el;
|
|
235
|
+
}
|
|
236
|
+
function renderChunked(rootElement, vNodes, chunkSize = 5e3, onProgress) {
|
|
237
|
+
const el = ensureElement(resolveElement(rootElement), rootElement);
|
|
238
|
+
const len = vNodes.length;
|
|
239
|
+
let index = 0;
|
|
240
|
+
const renderChunkFrame = () => {
|
|
241
|
+
const end = Math.min(index + chunkSize, len);
|
|
242
|
+
const fragment = document.createDocumentFragment();
|
|
243
|
+
for (let i = index; i < end; i++) {
|
|
244
|
+
renderToDOM(vNodes[i], fragment);
|
|
245
|
+
}
|
|
246
|
+
el.appendChild(fragment);
|
|
247
|
+
index = end;
|
|
248
|
+
if (onProgress) {
|
|
249
|
+
onProgress(index, len);
|
|
250
|
+
}
|
|
251
|
+
if (index < len) {
|
|
252
|
+
requestAnimationFrame(renderChunkFrame);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
requestAnimationFrame(renderChunkFrame);
|
|
256
|
+
return el;
|
|
257
|
+
}
|
|
258
|
+
function renderToHead(...vNodes) {
|
|
259
|
+
const head = document.head;
|
|
260
|
+
if (head) {
|
|
261
|
+
for (const vNode of vNodes.flat()) {
|
|
262
|
+
if (vNode) {
|
|
263
|
+
renderToDOM(vNode, head);
|
|
249
264
|
}
|
|
250
265
|
}
|
|
251
|
-
return head;
|
|
252
|
-
}
|
|
253
|
-
addStyle(cssText) {
|
|
254
|
-
const el = document.createElement("style");
|
|
255
|
-
el.textContent = cssText;
|
|
256
|
-
return document.head.appendChild(el);
|
|
257
266
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
267
|
+
return head;
|
|
268
|
+
}
|
|
269
|
+
function addStyle(cssText) {
|
|
270
|
+
const el = document.createElement("style");
|
|
271
|
+
el.textContent = cssText;
|
|
272
|
+
return document.head.appendChild(el);
|
|
273
|
+
}
|
|
274
|
+
function addMeta(attrs) {
|
|
275
|
+
const el = document.createElement("meta");
|
|
276
|
+
for (const key in attrs) {
|
|
277
|
+
el.setAttribute(key, attrs[key]);
|
|
262
278
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
279
|
+
return document.head.appendChild(el);
|
|
280
|
+
}
|
|
281
|
+
function addLink(attrs) {
|
|
282
|
+
const el = document.createElement("link");
|
|
283
|
+
for (const key in attrs) {
|
|
284
|
+
el.setAttribute(key, attrs[key]);
|
|
267
285
|
}
|
|
268
|
-
|
|
269
|
-
|
|
286
|
+
return document.head.appendChild(el);
|
|
287
|
+
}
|
|
288
|
+
function setTitle(text2) {
|
|
289
|
+
return document.title = text2;
|
|
290
|
+
}
|
|
291
|
+
function cleanupUnusedElements(root, elementCache) {
|
|
292
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
293
|
+
const toRemove = [];
|
|
294
|
+
while (walker.nextNode()) {
|
|
295
|
+
const node = walker.currentNode;
|
|
296
|
+
if (node.id && node.id.startsWith("r") && !elementCache.has(node)) {
|
|
297
|
+
toRemove.push(node);
|
|
298
|
+
}
|
|
270
299
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
} else {
|
|
287
|
-
notify();
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
return {
|
|
291
|
-
get value() {
|
|
292
|
-
return value;
|
|
293
|
-
},
|
|
294
|
-
set value(newValue) {
|
|
295
|
-
const changed = deep ? JSON.stringify(value) !== JSON.stringify(newValue) : value !== newValue;
|
|
296
|
-
if (changed) {
|
|
297
|
-
value = newValue;
|
|
298
|
-
scheduleUpdate();
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
subscribe(fn) {
|
|
302
|
-
listeners.add(fn);
|
|
303
|
-
return () => listeners.delete(fn);
|
|
304
|
-
},
|
|
305
|
-
destroy() {
|
|
306
|
-
listeners.clear();
|
|
307
|
-
updateTimer && clearTimeout(updateTimer);
|
|
300
|
+
toRemove.forEach((el) => el.remove());
|
|
301
|
+
return toRemove.length;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/client/dom/reactive.ts
|
|
305
|
+
function createReactiveChild(state, reactiveNodes, renderFn) {
|
|
306
|
+
const currentValue = renderFn(state.value);
|
|
307
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
308
|
+
const entry = { node: null, renderFn };
|
|
309
|
+
reactiveNodes.set(state, entry);
|
|
310
|
+
state.subscribe(() => {
|
|
311
|
+
if (entry.node && entry.node.parentNode) {
|
|
312
|
+
const newValue = renderFn(state.value);
|
|
313
|
+
entry.node.textContent = String(newValue ?? "");
|
|
308
314
|
}
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
computed(states, computeFn) {
|
|
312
|
-
const values = states.map((s) => s.value);
|
|
313
|
-
const result = this.createState(computeFn(...values));
|
|
314
|
-
states.forEach((state, index) => {
|
|
315
|
-
state.subscribe((newValue) => {
|
|
316
|
-
values[index] = newValue;
|
|
317
|
-
result.value = computeFn(...values);
|
|
318
|
-
});
|
|
319
315
|
});
|
|
320
|
-
return result;
|
|
321
316
|
}
|
|
322
|
-
|
|
323
|
-
|
|
317
|
+
return currentValue;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// src/client/dom/string-render.ts
|
|
321
|
+
var SELF_CLOSING_TAGS = /* @__PURE__ */ new Set([
|
|
322
|
+
"area",
|
|
323
|
+
"base",
|
|
324
|
+
"br",
|
|
325
|
+
"col",
|
|
326
|
+
"embed",
|
|
327
|
+
"hr",
|
|
328
|
+
"img",
|
|
329
|
+
"input",
|
|
330
|
+
"link",
|
|
331
|
+
"meta",
|
|
332
|
+
"param",
|
|
333
|
+
"source",
|
|
334
|
+
"track",
|
|
335
|
+
"wbr"
|
|
336
|
+
]);
|
|
337
|
+
function resolveStateValue(value) {
|
|
338
|
+
return isState(value) ? value.value : value;
|
|
339
|
+
}
|
|
340
|
+
function isReactiveWrapper(vNode) {
|
|
341
|
+
if (!vNode || typeof vNode !== "object" || !vNode.tagName) {
|
|
342
|
+
return false;
|
|
324
343
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const getVisibleRange = () => {
|
|
331
|
-
const start = Math.max(0, Math.floor(scrollTop / itemHeight) - bufferSize);
|
|
332
|
-
const end = Math.min(items.length, Math.ceil((scrollTop + viewportHeight) / itemHeight) + bufferSize);
|
|
333
|
-
return { start, end };
|
|
334
|
-
};
|
|
335
|
-
const render2 = () => {
|
|
336
|
-
const { start, end } = getVisibleRange();
|
|
337
|
-
const wrapper = document.createElement("div");
|
|
338
|
-
wrapper.style.cssText = `height:${totalHeight}px;position:relative`;
|
|
339
|
-
for (let i = start; i < end; i++) {
|
|
340
|
-
const itemEl = document.createElement("div");
|
|
341
|
-
itemEl.style.cssText = `position:absolute;top:${i * itemHeight}px;height:${itemHeight}px;width:100%`;
|
|
342
|
-
this.renderToDOM(renderItem(items[i], i), itemEl);
|
|
343
|
-
wrapper.appendChild(itemEl);
|
|
344
|
-
}
|
|
345
|
-
container.innerHTML = "";
|
|
346
|
-
container.appendChild(wrapper);
|
|
347
|
-
};
|
|
348
|
-
const scrollHandler = () => {
|
|
349
|
-
scrollTop = container.scrollTop;
|
|
350
|
-
requestAnimationFrame(render2);
|
|
351
|
-
};
|
|
352
|
-
container.addEventListener("scroll", scrollHandler);
|
|
353
|
-
render2();
|
|
354
|
-
return {
|
|
355
|
-
render: render2,
|
|
356
|
-
destroy: () => {
|
|
357
|
-
container.removeEventListener("scroll", scrollHandler);
|
|
358
|
-
container.innerHTML = "";
|
|
359
|
-
}
|
|
360
|
-
};
|
|
344
|
+
return vNode.tagName === "span" && vNode.props?.id && typeof vNode.props.id === "string" && /^r[a-z0-9]{9}$/.test(vNode.props.id);
|
|
345
|
+
}
|
|
346
|
+
function unwrapReactive(vNode) {
|
|
347
|
+
if (!isReactiveWrapper(vNode)) {
|
|
348
|
+
return vNode;
|
|
361
349
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
let loading = false;
|
|
366
|
-
return async (...args) => {
|
|
367
|
-
if (!component && !loading) {
|
|
368
|
-
loading = true;
|
|
369
|
-
component = await loadFn();
|
|
370
|
-
loading = false;
|
|
371
|
-
}
|
|
372
|
-
return component ? component(...args) : { tagName: "div", props: { class: "loading" }, children: ["Loading..."] };
|
|
373
|
-
};
|
|
350
|
+
const children = vNode.children;
|
|
351
|
+
if (!children || children.length === 0) {
|
|
352
|
+
return "";
|
|
374
353
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const
|
|
381
|
-
if (
|
|
382
|
-
|
|
354
|
+
if (children.length === 1) {
|
|
355
|
+
const child = children[0];
|
|
356
|
+
if (child && typeof child === "object" && child.tagName === "span") {
|
|
357
|
+
const props = child.props;
|
|
358
|
+
const hasNoProps = !props || Object.keys(props).length === 0;
|
|
359
|
+
const hasSingleStringChild = child.children && child.children.length === 1 && typeof child.children[0] === "string";
|
|
360
|
+
if (hasNoProps && hasSingleStringChild) {
|
|
361
|
+
return child.children[0];
|
|
383
362
|
}
|
|
384
363
|
}
|
|
385
|
-
|
|
386
|
-
return toRemove.length;
|
|
364
|
+
return unwrapReactive(child);
|
|
387
365
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
366
|
+
return children.map((child) => unwrapReactive(child));
|
|
367
|
+
}
|
|
368
|
+
function escapeHtml(text2) {
|
|
369
|
+
const htmlEscapes = {
|
|
370
|
+
"&": "&",
|
|
371
|
+
"<": "<",
|
|
372
|
+
">": ">",
|
|
373
|
+
'"': """,
|
|
374
|
+
"'": "'"
|
|
375
|
+
};
|
|
376
|
+
return text2.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
|
|
377
|
+
}
|
|
378
|
+
function isSelfClosingTag(tagName) {
|
|
379
|
+
return SELF_CLOSING_TAGS.has(tagName.toLowerCase());
|
|
380
|
+
}
|
|
381
|
+
function styleToString(style) {
|
|
382
|
+
if (typeof style === "string") {
|
|
383
|
+
return style;
|
|
384
|
+
}
|
|
385
|
+
if (typeof style === "object" && style !== null) {
|
|
386
|
+
const styles = [];
|
|
387
|
+
for (const key in style) {
|
|
388
|
+
const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
389
|
+
styles.push(`${cssKey}:${style[key]}`);
|
|
397
390
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
391
|
+
return styles.join(";");
|
|
392
|
+
}
|
|
393
|
+
return "";
|
|
394
|
+
}
|
|
395
|
+
function propsToAttributes(props, tagName) {
|
|
396
|
+
const attrs = [];
|
|
397
|
+
for (const key in props) {
|
|
398
|
+
if (key === "children" || key === "dangerouslySetInnerHTML" || key === "ref" || tagName === "textarea" && key === "value") {
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
let value = props[key];
|
|
402
|
+
value = resolveStateValue(value);
|
|
403
|
+
if (value == null || value === false) continue;
|
|
404
|
+
if (key.startsWith("on") && typeof value === "function") {
|
|
405
|
+
continue;
|
|
403
406
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
html += ` ${attrs}`;
|
|
407
|
+
if (key === "className" || key === "class") {
|
|
408
|
+
const className = Array.isArray(value) ? value.join(" ") : value;
|
|
409
|
+
if (className) {
|
|
410
|
+
attrs.push(`class="${escapeHtml(String(className))}"`);
|
|
411
|
+
}
|
|
412
|
+
continue;
|
|
411
413
|
}
|
|
412
|
-
if (
|
|
413
|
-
|
|
414
|
-
|
|
414
|
+
if (key === "style") {
|
|
415
|
+
const styleStr = styleToString(value);
|
|
416
|
+
if (styleStr) {
|
|
417
|
+
attrs.push(`style="${escapeHtml(styleStr)}"`);
|
|
418
|
+
}
|
|
419
|
+
continue;
|
|
415
420
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
html += `</${tagName}>${newLine}`;
|
|
420
|
-
return html;
|
|
421
|
+
if (value === true) {
|
|
422
|
+
attrs.push(key);
|
|
423
|
+
continue;
|
|
421
424
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
425
|
+
attrs.push(`${key}="${escapeHtml(String(value))}"`);
|
|
426
|
+
}
|
|
427
|
+
return attrs.join(" ");
|
|
428
|
+
}
|
|
429
|
+
function renderToString(vNode, options = {}) {
|
|
430
|
+
const { pretty = false, indent = 0 } = options;
|
|
431
|
+
const indentStr = pretty ? " ".repeat(indent) : "";
|
|
432
|
+
const newLine = pretty ? "\n" : "";
|
|
433
|
+
let resolvedVNode = resolveStateValue(vNode);
|
|
434
|
+
resolvedVNode = unwrapReactive(resolvedVNode);
|
|
435
|
+
if (Array.isArray(resolvedVNode)) {
|
|
436
|
+
return resolvedVNode.map((child) => renderToString(child, options)).join("");
|
|
437
|
+
}
|
|
438
|
+
if (typeof resolvedVNode !== "object" || resolvedVNode === null) {
|
|
439
|
+
if (resolvedVNode === null || resolvedVNode === void 0 || resolvedVNode === false) {
|
|
440
|
+
return "";
|
|
426
441
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
442
|
+
return escapeHtml(String(resolvedVNode));
|
|
443
|
+
}
|
|
444
|
+
const { tagName, props, children } = resolvedVNode;
|
|
445
|
+
const textareaValue = resolveTextareaValue(tagName, props);
|
|
446
|
+
const selfClosing = isSelfClosingTag(tagName);
|
|
447
|
+
let html = `${indentStr}<${tagName}`;
|
|
448
|
+
const attrs = propsToAttributes(props, tagName);
|
|
449
|
+
if (attrs) {
|
|
450
|
+
html += ` ${attrs}`;
|
|
451
|
+
}
|
|
452
|
+
if (selfClosing) {
|
|
453
|
+
html += ` />${newLine}`;
|
|
454
|
+
return html;
|
|
455
|
+
}
|
|
456
|
+
html += ">";
|
|
457
|
+
if (textareaValue !== void 0) {
|
|
458
|
+
html += escapeHtml(textareaValue);
|
|
459
|
+
html += `</${tagName}>${newLine}`;
|
|
460
|
+
return html;
|
|
461
|
+
}
|
|
462
|
+
if (props.dangerouslySetInnerHTML) {
|
|
463
|
+
html += props.dangerouslySetInnerHTML.__html;
|
|
464
|
+
html += `</${tagName}>${newLine}`;
|
|
465
|
+
return html;
|
|
466
|
+
}
|
|
467
|
+
const isRawText = tagName === "script" || tagName === "style";
|
|
468
|
+
if (children && children.length > 0) {
|
|
469
|
+
const resolvedChildren = children.map((child) => unwrapReactive(resolveStateValue(child)));
|
|
470
|
+
const hasComplexChildren = resolvedChildren.some(
|
|
471
|
+
(child) => typeof child === "object" && child !== null && !Array.isArray(child) && "tagName" in child
|
|
472
|
+
);
|
|
473
|
+
if (pretty && hasComplexChildren) {
|
|
474
|
+
html += newLine;
|
|
475
|
+
for (const child of resolvedChildren) {
|
|
476
|
+
if (shouldSkipChild(child)) continue;
|
|
477
|
+
if (Array.isArray(child)) {
|
|
478
|
+
for (const nestedChild of child) {
|
|
479
|
+
if (!shouldSkipChild(nestedChild)) {
|
|
480
|
+
html += isRawText && typeof nestedChild === "string" ? nestedChild : renderToString(nestedChild, { pretty, indent: indent + 1 });
|
|
444
481
|
}
|
|
445
|
-
} else {
|
|
446
|
-
html += this.renderToString(child, { pretty, indent: indent + 1 });
|
|
447
482
|
}
|
|
483
|
+
} else {
|
|
484
|
+
html += isRawText && typeof child === "string" ? child : renderToString(child, { pretty, indent: indent + 1 });
|
|
448
485
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}
|
|
486
|
+
}
|
|
487
|
+
html += indentStr;
|
|
488
|
+
} else {
|
|
489
|
+
for (const child of resolvedChildren) {
|
|
490
|
+
if (shouldSkipChild(child)) continue;
|
|
491
|
+
if (Array.isArray(child)) {
|
|
492
|
+
for (const nestedChild of child) {
|
|
493
|
+
if (!shouldSkipChild(nestedChild)) {
|
|
494
|
+
html += isRawText && typeof nestedChild === "string" ? nestedChild : renderToString(nestedChild, { pretty: false, indent: 0 });
|
|
458
495
|
}
|
|
459
|
-
} else {
|
|
460
|
-
html += this.renderToString(child, { pretty: false, indent: 0 });
|
|
461
496
|
}
|
|
497
|
+
} else {
|
|
498
|
+
html += isRawText && typeof child === "string" ? child : renderToString(child, { pretty: false, indent: 0 });
|
|
462
499
|
}
|
|
463
500
|
}
|
|
464
501
|
}
|
|
465
|
-
html += `</${tagName}>${newLine}`;
|
|
466
|
-
return html;
|
|
467
502
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
503
|
+
html += `</${tagName}>${newLine}`;
|
|
504
|
+
return html;
|
|
505
|
+
}
|
|
506
|
+
function renderToHTMLDocument(vNode, options = {}) {
|
|
507
|
+
const {
|
|
508
|
+
title = "",
|
|
509
|
+
meta = [],
|
|
510
|
+
links = [],
|
|
511
|
+
scripts = [],
|
|
512
|
+
styles = [],
|
|
513
|
+
lang = "en",
|
|
514
|
+
head = "",
|
|
515
|
+
bodyAttrs = {},
|
|
516
|
+
pretty = false
|
|
517
|
+
} = options;
|
|
518
|
+
const nl = pretty ? "\n" : "";
|
|
519
|
+
const indent = pretty ? " " : "";
|
|
520
|
+
const indent2 = pretty ? " " : "";
|
|
521
|
+
let html = `<!DOCTYPE html>${nl}<html lang="${lang}">${nl}${indent}<head>${nl}${indent2}<meta charset="UTF-8">${nl}${indent2}<meta name="viewport" content="width=device-width, initial-scale=1.0">${nl}`;
|
|
522
|
+
if (title) {
|
|
523
|
+
html += `${indent2}<title>${escapeHtml(title)}</title>${nl}`;
|
|
524
|
+
}
|
|
525
|
+
for (const metaAttrs of meta) {
|
|
526
|
+
html += `${indent2}<meta`;
|
|
527
|
+
for (const key in metaAttrs) {
|
|
528
|
+
html += ` ${key}="${escapeHtml(metaAttrs[key])}"`;
|
|
471
529
|
}
|
|
472
|
-
|
|
530
|
+
html += `>${nl}`;
|
|
473
531
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
532
|
+
for (const linkAttrs of links) {
|
|
533
|
+
html += `${indent2}<link`;
|
|
534
|
+
for (const key in linkAttrs) {
|
|
535
|
+
html += ` ${key}="${escapeHtml(linkAttrs[key])}"`;
|
|
477
536
|
}
|
|
478
|
-
|
|
537
|
+
html += `>${nl}`;
|
|
479
538
|
}
|
|
480
|
-
|
|
481
|
-
if (
|
|
482
|
-
|
|
539
|
+
for (const style of styles) {
|
|
540
|
+
if (style.href) {
|
|
541
|
+
html += `${indent2}<link rel="stylesheet" href="${escapeHtml(style.href)}">${nl}`;
|
|
542
|
+
} else if (style.content) {
|
|
543
|
+
html += `${indent2}<style>${style.content}</style>${nl}`;
|
|
483
544
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
545
|
+
}
|
|
546
|
+
if (head) {
|
|
547
|
+
html += head + nl;
|
|
548
|
+
}
|
|
549
|
+
html += `${indent}</head>${nl}${indent}<body`;
|
|
550
|
+
for (const key in bodyAttrs) {
|
|
551
|
+
html += ` ${key}="${escapeHtml(bodyAttrs[key])}"`;
|
|
552
|
+
}
|
|
553
|
+
html += `>${nl}`;
|
|
554
|
+
html += renderToString(vNode, { pretty, indent: 2 });
|
|
555
|
+
for (const script of scripts) {
|
|
556
|
+
html += `${indent2}<script`;
|
|
557
|
+
if (script.type) {
|
|
558
|
+
html += ` type="${escapeHtml(script.type)}"`;
|
|
487
559
|
}
|
|
488
|
-
if (
|
|
489
|
-
|
|
490
|
-
if (child && typeof child === "object" && child.tagName === "span") {
|
|
491
|
-
const props = child.props;
|
|
492
|
-
const hasNoProps = !props || Object.keys(props).length === 0;
|
|
493
|
-
const hasSingleStringChild = child.children && child.children.length === 1 && typeof child.children[0] === "string";
|
|
494
|
-
if (hasNoProps && hasSingleStringChild) {
|
|
495
|
-
return child.children[0];
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
return this.unwrapReactive(child);
|
|
560
|
+
if (script.async) {
|
|
561
|
+
html += " async";
|
|
499
562
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
const className = Array.isArray(value) ? value.join(" ") : value;
|
|
545
|
-
if (className) {
|
|
546
|
-
attrs.push(`class="${this.escapeHtml(String(className))}"`);
|
|
547
|
-
}
|
|
548
|
-
continue;
|
|
549
|
-
}
|
|
550
|
-
if (key === "style") {
|
|
551
|
-
const styleStr = this.styleToString(value);
|
|
552
|
-
if (styleStr) {
|
|
553
|
-
attrs.push(`style="${this.escapeHtml(styleStr)}"`);
|
|
563
|
+
if (script.defer) {
|
|
564
|
+
html += " defer";
|
|
565
|
+
}
|
|
566
|
+
if (script.src) {
|
|
567
|
+
html += ` src="${escapeHtml(script.src)}"></script>${nl}`;
|
|
568
|
+
} else if (script.content) {
|
|
569
|
+
html += `>${script.content}</script>${nl}`;
|
|
570
|
+
} else {
|
|
571
|
+
html += `></script>${nl}`;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
html += `${indent}</body>${nl}</html>`;
|
|
575
|
+
return html;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// src/client/dom/json.ts
|
|
579
|
+
function jsonToVNode(json, reactiveNodes) {
|
|
580
|
+
if (isState(json)) {
|
|
581
|
+
return createReactiveChild(json, reactiveNodes, (value) => value);
|
|
582
|
+
}
|
|
583
|
+
if (isPrimitiveJson(json)) {
|
|
584
|
+
return json;
|
|
585
|
+
}
|
|
586
|
+
const { tag, attributes = {}, children } = json;
|
|
587
|
+
const props = {};
|
|
588
|
+
for (const key in attributes) {
|
|
589
|
+
const value = attributes[key];
|
|
590
|
+
if (key === "class") {
|
|
591
|
+
props.className = isState(value) ? value.value : value;
|
|
592
|
+
} else {
|
|
593
|
+
props[key] = isState(value) ? value.value : value;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
const childrenArray = [];
|
|
597
|
+
if (children != null) {
|
|
598
|
+
if (Array.isArray(children)) {
|
|
599
|
+
for (const child of children) {
|
|
600
|
+
if (isState(child)) {
|
|
601
|
+
childrenArray.push(createReactiveChild(child, reactiveNodes, (value) => value));
|
|
602
|
+
} else {
|
|
603
|
+
const converted = jsonToVNode(child, reactiveNodes);
|
|
604
|
+
if (converted != null && converted !== false) {
|
|
605
|
+
childrenArray.push(converted);
|
|
606
|
+
}
|
|
554
607
|
}
|
|
555
|
-
continue;
|
|
556
608
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
609
|
+
} else if (isState(children)) {
|
|
610
|
+
childrenArray.push(createReactiveChild(children, reactiveNodes, (value) => value));
|
|
611
|
+
} else if (typeof children === "object" && children !== null && "tag" in children) {
|
|
612
|
+
const converted = jsonToVNode(children, reactiveNodes);
|
|
613
|
+
if (converted != null && converted !== false) {
|
|
614
|
+
childrenArray.push(converted);
|
|
560
615
|
}
|
|
561
|
-
|
|
616
|
+
} else {
|
|
617
|
+
childrenArray.push(children);
|
|
562
618
|
}
|
|
563
|
-
return attrs.join(" ");
|
|
564
619
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
620
|
+
return { tagName: tag, props, children: childrenArray };
|
|
621
|
+
}
|
|
622
|
+
function vNodeJsonToVNode(json, reactiveNodes) {
|
|
623
|
+
if (isState(json)) {
|
|
624
|
+
return createReactiveChild(json, reactiveNodes, (value) => value);
|
|
625
|
+
}
|
|
626
|
+
if (isPrimitiveJson(json)) {
|
|
627
|
+
return json;
|
|
628
|
+
}
|
|
629
|
+
const { tagName, props = {}, children = [] } = json;
|
|
630
|
+
const resolvedProps = {};
|
|
631
|
+
for (const key in props) {
|
|
632
|
+
const value = props[key];
|
|
633
|
+
resolvedProps[key] = isState(value) ? value.value : value;
|
|
634
|
+
}
|
|
635
|
+
const childrenArray = [];
|
|
636
|
+
for (const child of children) {
|
|
637
|
+
if (isState(child)) {
|
|
638
|
+
childrenArray.push(createReactiveChild(child, reactiveNodes, (value) => value));
|
|
639
|
+
} else {
|
|
640
|
+
const converted = vNodeJsonToVNode(child, reactiveNodes);
|
|
641
|
+
if (converted != null && converted !== false) {
|
|
642
|
+
childrenArray.push(converted);
|
|
574
643
|
}
|
|
575
|
-
return styles.join(";");
|
|
576
644
|
}
|
|
577
|
-
return "";
|
|
578
645
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
const entry = { node: null, renderFn };
|
|
586
|
-
this.reactiveNodes.set(state, entry);
|
|
587
|
-
state.subscribe(() => {
|
|
588
|
-
if (entry.node && entry.node.parentNode) {
|
|
589
|
-
const newValue = renderFn(state.value);
|
|
590
|
-
entry.node.textContent = String(newValue ?? "");
|
|
591
|
-
}
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
return currentValue;
|
|
646
|
+
return { tagName, props: resolvedProps, children: childrenArray };
|
|
647
|
+
}
|
|
648
|
+
function renderJson(rootElement, json, reactiveNodes) {
|
|
649
|
+
const vNode = jsonToVNode(json, reactiveNodes);
|
|
650
|
+
if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
|
|
651
|
+
throw new Error("Invalid JSON structure");
|
|
595
652
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
653
|
+
return render(rootElement, vNode);
|
|
654
|
+
}
|
|
655
|
+
function renderVNode(rootElement, json, reactiveNodes) {
|
|
656
|
+
const vNode = vNodeJsonToVNode(json, reactiveNodes);
|
|
657
|
+
if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
|
|
658
|
+
throw new Error("Invalid VNode JSON structure");
|
|
659
|
+
}
|
|
660
|
+
return render(rootElement, vNode);
|
|
661
|
+
}
|
|
662
|
+
function renderJsonToString(json, reactiveNodes, options = {}) {
|
|
663
|
+
const vNode = jsonToVNode(json, reactiveNodes);
|
|
664
|
+
return renderToString(vNode, options);
|
|
665
|
+
}
|
|
666
|
+
function renderVNodeToString(json, reactiveNodes, options = {}) {
|
|
667
|
+
const vNode = vNodeJsonToVNode(json, reactiveNodes);
|
|
668
|
+
return renderToString(vNode, options);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// src/client/dom/state-utils.ts
|
|
672
|
+
function createState(initialValue, options = {}) {
|
|
673
|
+
let value = initialValue;
|
|
674
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
675
|
+
let updateTimer = null;
|
|
676
|
+
const { throttle: throttle2 = 0, deep = false } = options;
|
|
677
|
+
const notify = () => listeners.forEach((listener) => listener(value));
|
|
678
|
+
const scheduleUpdate = () => {
|
|
679
|
+
if (throttle2 > 0) {
|
|
680
|
+
if (!updateTimer) {
|
|
681
|
+
updateTimer = setTimeout(() => {
|
|
682
|
+
updateTimer = null;
|
|
683
|
+
notify();
|
|
684
|
+
}, throttle2);
|
|
611
685
|
}
|
|
686
|
+
} else {
|
|
687
|
+
notify();
|
|
612
688
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
} else {
|
|
634
|
-
childrenArray.push(children);
|
|
689
|
+
};
|
|
690
|
+
return {
|
|
691
|
+
get value() {
|
|
692
|
+
return value;
|
|
693
|
+
},
|
|
694
|
+
set value(newValue) {
|
|
695
|
+
const changed = deep ? JSON.stringify(value) !== JSON.stringify(newValue) : value !== newValue;
|
|
696
|
+
if (changed) {
|
|
697
|
+
value = newValue;
|
|
698
|
+
scheduleUpdate();
|
|
699
|
+
}
|
|
700
|
+
},
|
|
701
|
+
subscribe(fn) {
|
|
702
|
+
listeners.add(fn);
|
|
703
|
+
return () => listeners.delete(fn);
|
|
704
|
+
},
|
|
705
|
+
destroy() {
|
|
706
|
+
listeners.clear();
|
|
707
|
+
if (updateTimer) {
|
|
708
|
+
clearTimeout(updateTimer);
|
|
635
709
|
}
|
|
636
710
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
function computed(states, computeFn) {
|
|
714
|
+
const values = states.map((state) => state.value);
|
|
715
|
+
const result = createState(computeFn(...values));
|
|
716
|
+
states.forEach((state, index) => {
|
|
717
|
+
state.subscribe((newValue) => {
|
|
718
|
+
values[index] = newValue;
|
|
719
|
+
result.value = computeFn(...values);
|
|
720
|
+
});
|
|
721
|
+
});
|
|
722
|
+
return result;
|
|
723
|
+
}
|
|
724
|
+
function effect(stateFn) {
|
|
725
|
+
stateFn();
|
|
726
|
+
}
|
|
727
|
+
function createVirtualList(container, items, renderItem, itemHeight = 50, bufferSize = 5) {
|
|
728
|
+
const viewportHeight = container.clientHeight;
|
|
729
|
+
const totalHeight = items.length * itemHeight;
|
|
730
|
+
let scrollTop = 0;
|
|
731
|
+
const getVisibleRange = () => {
|
|
732
|
+
const start = Math.max(0, Math.floor(scrollTop / itemHeight) - bufferSize);
|
|
733
|
+
const end = Math.min(items.length, Math.ceil((scrollTop + viewportHeight) / itemHeight) + bufferSize);
|
|
734
|
+
return { start, end };
|
|
735
|
+
};
|
|
736
|
+
const render3 = () => {
|
|
737
|
+
const { start, end } = getVisibleRange();
|
|
738
|
+
const wrapper = document.createElement("div");
|
|
739
|
+
wrapper.style.cssText = `height:${totalHeight}px;position:relative`;
|
|
740
|
+
for (let i = start; i < end; i++) {
|
|
741
|
+
const itemEl = document.createElement("div");
|
|
742
|
+
itemEl.style.cssText = `position:absolute;top:${i * itemHeight}px;height:${itemHeight}px;width:100%`;
|
|
743
|
+
renderToDOM(renderItem(items[i], i), itemEl);
|
|
744
|
+
wrapper.appendChild(itemEl);
|
|
645
745
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
746
|
+
container.innerHTML = "";
|
|
747
|
+
container.appendChild(wrapper);
|
|
748
|
+
};
|
|
749
|
+
const scrollHandler = () => {
|
|
750
|
+
scrollTop = container.scrollTop;
|
|
751
|
+
requestAnimationFrame(render3);
|
|
752
|
+
};
|
|
753
|
+
container.addEventListener("scroll", scrollHandler);
|
|
754
|
+
render3();
|
|
755
|
+
return {
|
|
756
|
+
render: render3,
|
|
757
|
+
destroy: () => {
|
|
758
|
+
container.removeEventListener("scroll", scrollHandler);
|
|
759
|
+
container.innerHTML = "";
|
|
651
760
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
function lazy(loadFn) {
|
|
764
|
+
let component = null;
|
|
765
|
+
let loading = false;
|
|
766
|
+
return async (...args) => {
|
|
767
|
+
if (!component && !loading) {
|
|
768
|
+
loading = true;
|
|
769
|
+
component = await loadFn();
|
|
770
|
+
loading = false;
|
|
662
771
|
}
|
|
663
|
-
return { tagName, props:
|
|
772
|
+
return component ? component(...args) : { tagName: "div", props: { class: "loading" }, children: ["Loading..."] };
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// src/client/dom/index.ts
|
|
777
|
+
var DomNode = class {
|
|
778
|
+
constructor() {
|
|
779
|
+
this.elementCache = /* @__PURE__ */ new WeakMap();
|
|
780
|
+
this.reactiveNodes = /* @__PURE__ */ new Map();
|
|
781
|
+
}
|
|
782
|
+
createElement(tagName, props = {}, children = []) {
|
|
783
|
+
return { tagName, props, children };
|
|
784
|
+
}
|
|
785
|
+
renderToDOM(vNode, parent) {
|
|
786
|
+
return renderToDOM(vNode, parent);
|
|
787
|
+
}
|
|
788
|
+
render(rootElement, vNode) {
|
|
789
|
+
return render(rootElement, vNode);
|
|
790
|
+
}
|
|
791
|
+
batchRender(rootElement, vNodes) {
|
|
792
|
+
return batchRender(rootElement, vNodes);
|
|
793
|
+
}
|
|
794
|
+
renderChunked(rootElement, vNodes, chunkSize = 5e3, onProgress) {
|
|
795
|
+
return renderChunked(rootElement, vNodes, chunkSize, onProgress);
|
|
796
|
+
}
|
|
797
|
+
renderToHead(...vNodes) {
|
|
798
|
+
return renderToHead(...vNodes);
|
|
799
|
+
}
|
|
800
|
+
addStyle(cssText) {
|
|
801
|
+
return addStyle(cssText);
|
|
802
|
+
}
|
|
803
|
+
addMeta(attrs) {
|
|
804
|
+
return addMeta(attrs);
|
|
805
|
+
}
|
|
806
|
+
addLink(attrs) {
|
|
807
|
+
return addLink(attrs);
|
|
808
|
+
}
|
|
809
|
+
setTitle(text2) {
|
|
810
|
+
return setTitle(text2);
|
|
811
|
+
}
|
|
812
|
+
// Reactive State Management
|
|
813
|
+
createState(initialValue, options = {}) {
|
|
814
|
+
return createState(initialValue, options);
|
|
815
|
+
}
|
|
816
|
+
computed(states, computeFn) {
|
|
817
|
+
return computed(states, computeFn);
|
|
818
|
+
}
|
|
819
|
+
effect(stateFn) {
|
|
820
|
+
effect(stateFn);
|
|
821
|
+
}
|
|
822
|
+
// Virtual scrolling helper for large lists
|
|
823
|
+
createVirtualList(container, items, renderItem, itemHeight = 50, bufferSize = 5) {
|
|
824
|
+
return createVirtualList(container, items, renderItem, itemHeight, bufferSize);
|
|
825
|
+
}
|
|
826
|
+
// Lazy load components
|
|
827
|
+
lazy(loadFn) {
|
|
828
|
+
return lazy(loadFn);
|
|
829
|
+
}
|
|
830
|
+
// Memory management - cleanup unused elements
|
|
831
|
+
cleanupUnusedElements(root) {
|
|
832
|
+
return cleanupUnusedElements(root, this.elementCache);
|
|
833
|
+
}
|
|
834
|
+
// Server-Side Rendering - convert VNode to HTML string
|
|
835
|
+
renderToString(vNode, options = {}) {
|
|
836
|
+
return renderToString(vNode, options);
|
|
837
|
+
}
|
|
838
|
+
jsonToVNode(json) {
|
|
839
|
+
return jsonToVNode(json, this.reactiveNodes);
|
|
840
|
+
}
|
|
841
|
+
vNodeJsonToVNode(json) {
|
|
842
|
+
return vNodeJsonToVNode(json, this.reactiveNodes);
|
|
664
843
|
}
|
|
665
844
|
renderJson(rootElement, json) {
|
|
666
|
-
|
|
667
|
-
if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
|
|
668
|
-
throw new Error("Invalid JSON structure");
|
|
669
|
-
}
|
|
670
|
-
return this.render(rootElement, vNode);
|
|
845
|
+
return renderJson(rootElement, json, this.reactiveNodes);
|
|
671
846
|
}
|
|
672
847
|
renderVNode(rootElement, json) {
|
|
673
|
-
|
|
674
|
-
if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
|
|
675
|
-
throw new Error("Invalid VNode JSON structure");
|
|
676
|
-
}
|
|
677
|
-
return this.render(rootElement, vNode);
|
|
848
|
+
return renderVNode(rootElement, json, this.reactiveNodes);
|
|
678
849
|
}
|
|
679
850
|
renderJsonToString(json, options = {}) {
|
|
680
|
-
|
|
681
|
-
return this.renderToString(vNode, options);
|
|
851
|
+
return renderJsonToString(json, this.reactiveNodes, options);
|
|
682
852
|
}
|
|
683
853
|
renderVNodeToString(json, options = {}) {
|
|
684
|
-
|
|
685
|
-
return this.renderToString(vNode, options);
|
|
854
|
+
return renderVNodeToString(json, this.reactiveNodes, options);
|
|
686
855
|
}
|
|
687
856
|
// Generate complete HTML document as string (for SSR)
|
|
688
857
|
renderToHTMLDocument(vNode, options = {}) {
|
|
689
|
-
|
|
690
|
-
const nl = pretty ? "\n" : "";
|
|
691
|
-
const indent = pretty ? " " : "";
|
|
692
|
-
const indent2 = pretty ? " " : "";
|
|
693
|
-
let html = `<!DOCTYPE html>${nl}<html lang="${lang}">${nl}${indent}<head>${nl}${indent2}<meta charset="UTF-8">${nl}${indent2}<meta name="viewport" content="width=device-width, initial-scale=1.0">${nl}`;
|
|
694
|
-
if (title) html += `${indent2}<title>${this.escapeHtml(title)}</title>${nl}`;
|
|
695
|
-
for (const m of meta) {
|
|
696
|
-
html += `${indent2}<meta`;
|
|
697
|
-
for (const k in m) html += ` ${k}="${this.escapeHtml(m[k])}"`;
|
|
698
|
-
html += `>${nl}`;
|
|
699
|
-
}
|
|
700
|
-
for (const l of links) {
|
|
701
|
-
html += `${indent2}<link`;
|
|
702
|
-
for (const k in l) html += ` ${k}="${this.escapeHtml(l[k])}"`;
|
|
703
|
-
html += `>${nl}`;
|
|
704
|
-
}
|
|
705
|
-
for (const s of styles) {
|
|
706
|
-
if (s.href) {
|
|
707
|
-
html += `${indent2}<link rel="stylesheet" href="${this.escapeHtml(s.href)}">${nl}`;
|
|
708
|
-
} else if (s.content) {
|
|
709
|
-
html += `${indent2}<style>${s.content}</style>${nl}`;
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
if (head) html += head + nl;
|
|
713
|
-
html += `${indent}</head>${nl}${indent}<body`;
|
|
714
|
-
for (const k in bodyAttrs) html += ` ${k}="${this.escapeHtml(bodyAttrs[k])}"`;
|
|
715
|
-
html += `>${nl}`;
|
|
716
|
-
html += this.renderToString(vNode, { pretty, indent: 2 });
|
|
717
|
-
for (const script of scripts) {
|
|
718
|
-
html += `${indent2}<script`;
|
|
719
|
-
if (script.type) html += ` type="${this.escapeHtml(script.type)}"`;
|
|
720
|
-
if (script.async) html += ` async`;
|
|
721
|
-
if (script.defer) html += ` defer`;
|
|
722
|
-
if (script.src) {
|
|
723
|
-
html += ` src="${this.escapeHtml(script.src)}"></script>${nl}`;
|
|
724
|
-
} else if (script.content) {
|
|
725
|
-
html += `>${script.content}</script>${nl}`;
|
|
726
|
-
} else {
|
|
727
|
-
html += `></script>${nl}`;
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
html += `${indent}</body>${nl}</html>`;
|
|
731
|
-
return html;
|
|
858
|
+
return renderToHTMLDocument(vNode, options);
|
|
732
859
|
}
|
|
733
860
|
// Expose elementCache for reactive updates
|
|
734
861
|
getElementCache() {
|
|
@@ -736,20 +863,20 @@ var DomNode = class {
|
|
|
736
863
|
}
|
|
737
864
|
};
|
|
738
865
|
var dom = new DomNode();
|
|
739
|
-
var
|
|
740
|
-
var
|
|
866
|
+
var render2 = dom.render.bind(dom);
|
|
867
|
+
var renderToString2 = dom.renderToString.bind(dom);
|
|
741
868
|
|
|
742
|
-
// src/state.ts
|
|
743
|
-
var
|
|
744
|
-
var
|
|
745
|
-
var
|
|
746
|
-
var
|
|
747
|
-
var
|
|
748
|
-
var
|
|
749
|
-
var
|
|
750
|
-
var createVirtualList = (container, items, renderItem, itemHeight, bufferSize) => dom.createVirtualList(container, items, renderItem, itemHeight, bufferSize);
|
|
751
|
-
var lazy = (loadFn) => dom.lazy(loadFn);
|
|
869
|
+
// src/client/state/core.ts
|
|
870
|
+
var createState2 = (initial, options) => dom.createState(initial, options);
|
|
871
|
+
var computed2 = (states, fn) => dom.computed(states, fn);
|
|
872
|
+
var effect2 = (fn) => dom.effect(fn);
|
|
873
|
+
var batchRender2 = (container, vNodes) => dom.batchRender(container, vNodes);
|
|
874
|
+
var renderChunked2 = (container, vNodes, chunkSize, onProgress) => dom.renderChunked(container, vNodes, chunkSize, onProgress);
|
|
875
|
+
var createVirtualList2 = (container, items, renderItem, itemHeight, bufferSize) => dom.createVirtualList(container, items, renderItem, itemHeight, bufferSize);
|
|
876
|
+
var lazy2 = (loadFn) => dom.lazy(loadFn);
|
|
752
877
|
var cleanupUnused = (root) => dom.cleanupUnusedElements(root);
|
|
878
|
+
|
|
879
|
+
// src/client/state/timing.ts
|
|
753
880
|
var throttle = (fn, delay) => {
|
|
754
881
|
let timer = null;
|
|
755
882
|
return (...args) => {
|
|
@@ -764,10 +891,15 @@ var throttle = (fn, delay) => {
|
|
|
764
891
|
var debounce = (fn, delay) => {
|
|
765
892
|
let timer = null;
|
|
766
893
|
return (...args) => {
|
|
767
|
-
|
|
894
|
+
if (timer) {
|
|
895
|
+
clearTimeout(timer);
|
|
896
|
+
}
|
|
768
897
|
timer = setTimeout(() => fn(...args), delay);
|
|
769
898
|
};
|
|
770
899
|
};
|
|
900
|
+
|
|
901
|
+
// src/client/state/bindings.ts
|
|
902
|
+
var ELIT_NATIVE_BINDING = /* @__PURE__ */ Symbol.for("elit.native.binding");
|
|
771
903
|
function bindValue(state) {
|
|
772
904
|
const props = {
|
|
773
905
|
value: state.value,
|
|
@@ -807,6 +939,9 @@ function bindChecked(state) {
|
|
|
807
939
|
};
|
|
808
940
|
return props;
|
|
809
941
|
}
|
|
942
|
+
|
|
943
|
+
// src/client/state/shared-state.ts
|
|
944
|
+
var ELIT_INTERNAL_WS_PATH = "/__elit_ws";
|
|
810
945
|
function resolveSharedStateWebSocketUrl(wsUrl) {
|
|
811
946
|
const protocol = typeof location !== "undefined" && location.protocol === "https:" ? "wss:" : "ws:";
|
|
812
947
|
const origin = typeof location !== "undefined" ? `${protocol}//${location.host}` : `${protocol}//localhost`;
|
|
@@ -831,33 +966,21 @@ var SharedState = class {
|
|
|
831
966
|
this.wsUrl = wsUrl;
|
|
832
967
|
this.ws = null;
|
|
833
968
|
this.pendingUpdates = [];
|
|
834
|
-
this.localState =
|
|
969
|
+
this.localState = createState2(defaultValue);
|
|
835
970
|
this.previousValue = defaultValue;
|
|
836
971
|
this.connect();
|
|
837
972
|
}
|
|
838
|
-
/**
|
|
839
|
-
* Get current value
|
|
840
|
-
*/
|
|
841
973
|
get value() {
|
|
842
974
|
return this.localState.value;
|
|
843
975
|
}
|
|
844
|
-
/**
|
|
845
|
-
* Set new value and sync to server
|
|
846
|
-
*/
|
|
847
976
|
set value(newValue) {
|
|
848
977
|
this.previousValue = this.localState.value;
|
|
849
978
|
this.localState.value = newValue;
|
|
850
979
|
this.sendToServer(newValue);
|
|
851
980
|
}
|
|
852
|
-
/**
|
|
853
|
-
* Get the underlying Elit State (for reactive binding)
|
|
854
|
-
*/
|
|
855
981
|
get state() {
|
|
856
982
|
return this.localState;
|
|
857
983
|
}
|
|
858
|
-
/**
|
|
859
|
-
* Subscribe to changes (returns Elit State for reactive)
|
|
860
|
-
*/
|
|
861
984
|
onChange(callback) {
|
|
862
985
|
return this.localState.subscribe((newValue) => {
|
|
863
986
|
const oldValue = this.previousValue;
|
|
@@ -865,17 +988,13 @@ var SharedState = class {
|
|
|
865
988
|
callback(newValue, oldValue);
|
|
866
989
|
});
|
|
867
990
|
}
|
|
868
|
-
/**
|
|
869
|
-
* Update value using a function
|
|
870
|
-
*/
|
|
871
991
|
update(updater) {
|
|
872
992
|
this.value = updater(this.value);
|
|
873
993
|
}
|
|
874
|
-
/**
|
|
875
|
-
* Connect to WebSocket
|
|
876
|
-
*/
|
|
877
994
|
connect() {
|
|
878
|
-
if (typeof window === "undefined")
|
|
995
|
+
if (typeof window === "undefined") {
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
879
998
|
const url = resolveSharedStateWebSocketUrl(this.wsUrl);
|
|
880
999
|
this.ws = new WebSocket(url);
|
|
881
1000
|
this.ws.addEventListener("open", () => {
|
|
@@ -895,34 +1014,31 @@ var SharedState = class {
|
|
|
895
1014
|
console.error("[SharedState] WebSocket error:", error);
|
|
896
1015
|
});
|
|
897
1016
|
}
|
|
898
|
-
/**
|
|
899
|
-
* Subscribe to server state
|
|
900
|
-
*/
|
|
901
1017
|
subscribe() {
|
|
902
|
-
if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
|
|
1018
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
903
1021
|
this.ws.send(JSON.stringify({
|
|
904
1022
|
type: "state:subscribe",
|
|
905
1023
|
key: this.key
|
|
906
1024
|
}));
|
|
907
1025
|
}
|
|
908
|
-
/**
|
|
909
|
-
* Handle message from server
|
|
910
|
-
*/
|
|
911
1026
|
handleMessage(data) {
|
|
912
1027
|
try {
|
|
913
1028
|
const msg = JSON.parse(data);
|
|
914
|
-
if (msg.key !== this.key)
|
|
1029
|
+
if (msg.key !== this.key) {
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
915
1032
|
if (msg.type === "state:init" || msg.type === "state:update") {
|
|
916
1033
|
this.localState.value = msg.value;
|
|
917
1034
|
}
|
|
918
1035
|
} catch (error) {
|
|
919
1036
|
}
|
|
920
1037
|
}
|
|
921
|
-
/**
|
|
922
|
-
* Send value to server
|
|
923
|
-
*/
|
|
924
1038
|
sendToServer(value) {
|
|
925
|
-
if (!this.ws)
|
|
1039
|
+
if (!this.ws) {
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
926
1042
|
if (this.ws.readyState !== WebSocket.OPEN) {
|
|
927
1043
|
this.pendingUpdates.push(value);
|
|
928
1044
|
return;
|
|
@@ -933,18 +1049,12 @@ var SharedState = class {
|
|
|
933
1049
|
value
|
|
934
1050
|
}));
|
|
935
1051
|
}
|
|
936
|
-
/**
|
|
937
|
-
* Disconnect
|
|
938
|
-
*/
|
|
939
1052
|
disconnect() {
|
|
940
1053
|
if (this.ws) {
|
|
941
1054
|
this.ws.close();
|
|
942
1055
|
this.ws = null;
|
|
943
1056
|
}
|
|
944
1057
|
}
|
|
945
|
-
/**
|
|
946
|
-
* Destroy state and cleanup
|
|
947
|
-
*/
|
|
948
1058
|
destroy() {
|
|
949
1059
|
this.disconnect();
|
|
950
1060
|
this.localState.destroy();
|
|
@@ -957,9 +1067,6 @@ var SharedStateManager = class {
|
|
|
957
1067
|
constructor() {
|
|
958
1068
|
this.states = /* @__PURE__ */ new Map();
|
|
959
1069
|
}
|
|
960
|
-
/**
|
|
961
|
-
* Create or get a shared state
|
|
962
|
-
*/
|
|
963
1070
|
create(key, defaultValue, wsUrl) {
|
|
964
1071
|
if (this.states.has(key)) {
|
|
965
1072
|
return this.states.get(key);
|
|
@@ -968,15 +1075,9 @@ var SharedStateManager = class {
|
|
|
968
1075
|
this.states.set(key, state);
|
|
969
1076
|
return state;
|
|
970
1077
|
}
|
|
971
|
-
/**
|
|
972
|
-
* Get existing state
|
|
973
|
-
*/
|
|
974
1078
|
get(key) {
|
|
975
1079
|
return this.states.get(key);
|
|
976
1080
|
}
|
|
977
|
-
/**
|
|
978
|
-
* Delete a state
|
|
979
|
-
*/
|
|
980
1081
|
delete(key) {
|
|
981
1082
|
const state = this.states.get(key);
|
|
982
1083
|
if (state) {
|
|
@@ -985,17 +1086,18 @@ var SharedStateManager = class {
|
|
|
985
1086
|
}
|
|
986
1087
|
return false;
|
|
987
1088
|
}
|
|
988
|
-
/**
|
|
989
|
-
* Clear all states
|
|
990
|
-
*/
|
|
991
1089
|
clear() {
|
|
992
1090
|
this.states.forEach((state) => state.destroy());
|
|
993
1091
|
this.states.clear();
|
|
994
1092
|
}
|
|
995
1093
|
};
|
|
996
1094
|
var sharedStateManager = new SharedStateManager();
|
|
1095
|
+
|
|
1096
|
+
// src/client/state/reactive-utils.ts
|
|
997
1097
|
var scheduleRAFUpdate = (rafId, updateFn) => {
|
|
998
|
-
|
|
1098
|
+
if (rafId) {
|
|
1099
|
+
cancelAnimationFrame(rafId);
|
|
1100
|
+
}
|
|
999
1101
|
return requestAnimationFrame(() => {
|
|
1000
1102
|
updateFn();
|
|
1001
1103
|
});
|
|
@@ -1019,12 +1121,16 @@ var renderToFragment = (content, isVNode) => {
|
|
|
1019
1121
|
var updateElementProps = (element, props) => {
|
|
1020
1122
|
for (const key in props) {
|
|
1021
1123
|
const value = props[key];
|
|
1022
|
-
if (key === "ref")
|
|
1124
|
+
if (key === "ref") {
|
|
1125
|
+
continue;
|
|
1126
|
+
}
|
|
1023
1127
|
if (key === "class" || key === "className") {
|
|
1024
1128
|
element.className = Array.isArray(value) ? value.join(" ") : value || "";
|
|
1025
1129
|
} else if (key === "style" && typeof value === "object") {
|
|
1026
|
-
const
|
|
1027
|
-
for (const
|
|
1130
|
+
const style = element.style;
|
|
1131
|
+
for (const styleKey in value) {
|
|
1132
|
+
style[styleKey] = value[styleKey];
|
|
1133
|
+
}
|
|
1028
1134
|
} else if (key.startsWith("on")) {
|
|
1029
1135
|
element[key.toLowerCase()] = value;
|
|
1030
1136
|
} else if (value != null && value !== false) {
|
|
@@ -1034,6 +1140,8 @@ var updateElementProps = (element, props) => {
|
|
|
1034
1140
|
}
|
|
1035
1141
|
}
|
|
1036
1142
|
};
|
|
1143
|
+
|
|
1144
|
+
// src/client/state/reactive.ts
|
|
1037
1145
|
var reactive = (state, renderFn) => {
|
|
1038
1146
|
let rafId = null;
|
|
1039
1147
|
let elementRef = null;
|
|
@@ -1043,7 +1151,9 @@ var reactive = (state, renderFn) => {
|
|
|
1043
1151
|
const isVNodeResult = initialResult && typeof initialResult === "object" && "tagName" in initialResult;
|
|
1044
1152
|
const initialIsNull = initialResult == null || initialResult === false;
|
|
1045
1153
|
const updateElement = () => {
|
|
1046
|
-
if (!elementRef && !placeholder)
|
|
1154
|
+
if (!elementRef && !placeholder) {
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1047
1157
|
const newResult = renderFn(state.value);
|
|
1048
1158
|
const resultIsNull = newResult == null || newResult === false;
|
|
1049
1159
|
if (resultIsNull) {
|
|
@@ -1124,24 +1234,24 @@ var reactiveAs = (tagName, state, renderFn, props = {}) => {
|
|
|
1124
1234
|
const initialChildren = Array.isArray(initialResult) ? initialResult : [initialResult];
|
|
1125
1235
|
return { tagName, props: { ...props, ref: refCallback }, children: initialChildren };
|
|
1126
1236
|
};
|
|
1127
|
-
var text = (state) => state && state.value !== void 0 ? reactive(state, (
|
|
1237
|
+
var text = (state) => state && state.value !== void 0 ? reactive(state, (value) => ({ tagName: "span", props: {}, children: [String(value)] })) : String(state);
|
|
1128
1238
|
export {
|
|
1129
1239
|
ELIT_NATIVE_BINDING,
|
|
1130
1240
|
SharedState,
|
|
1131
|
-
batchRender,
|
|
1241
|
+
batchRender2 as batchRender,
|
|
1132
1242
|
bindChecked,
|
|
1133
1243
|
bindValue,
|
|
1134
1244
|
cleanupUnused,
|
|
1135
|
-
computed,
|
|
1245
|
+
computed2 as computed,
|
|
1136
1246
|
createSharedState,
|
|
1137
|
-
createState,
|
|
1138
|
-
createVirtualList,
|
|
1247
|
+
createState2 as createState,
|
|
1248
|
+
createVirtualList2 as createVirtualList,
|
|
1139
1249
|
debounce,
|
|
1140
|
-
effect,
|
|
1141
|
-
lazy,
|
|
1250
|
+
effect2 as effect,
|
|
1251
|
+
lazy2 as lazy,
|
|
1142
1252
|
reactive,
|
|
1143
1253
|
reactiveAs,
|
|
1144
|
-
renderChunked,
|
|
1254
|
+
renderChunked2 as renderChunked,
|
|
1145
1255
|
sharedStateManager,
|
|
1146
1256
|
text,
|
|
1147
1257
|
throttle
|