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