elit 3.6.6 → 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/dist/build.cjs +421 -331
- package/dist/build.d.ts +1 -19
- 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 +22439 -21563
- package/dist/cli.d.ts +19 -37
- package/dist/cli.mjs +24113 -23252
- package/dist/config.cjs +357 -350
- package/dist/config.d.ts +17 -245
- 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 -62
- 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 -1523
- package/dist/desktop-auto-render.d.ts +4 -12
- package/dist/desktop-auto-render.js +1695 -1518
- package/dist/desktop-auto-render.mjs +1696 -1519
- 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 -591
- package/dist/dom.d.ts +2 -17
- package/dist/dom.js +714 -588
- package/dist/dom.mjs +716 -590
- package/dist/el.cjs +62 -52
- package/dist/el.d.ts +5 -12
- 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 -7691
- package/dist/index.d.ts +6 -3
- package/dist/index.js +7486 -7677
- package/dist/index.mjs +7497 -7687
- 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 -8870
- package/dist/native.d.ts +7 -10
- package/dist/native.js +8682 -8936
- package/dist/native.mjs +8615 -8869
- 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 -34
- package/dist/render-context.js +11 -2
- package/dist/render-context.mjs +11 -2
- package/dist/router.cjs +787 -646
- package/dist/router.d.ts +8 -14
- package/dist/router.js +786 -645
- package/dist/router.mjs +786 -645
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/server.cjs +3254 -2684
- package/dist/server.d.ts +47 -5
- package/dist/server.js +3427 -2859
- package/dist/server.mjs +3397 -2829
- package/dist/smtp-server.cjs +16 -3
- package/dist/smtp-server.d.ts +12 -26
- package/dist/smtp-server.js +18 -5
- package/dist/smtp-server.mjs +16 -3
- package/dist/state-DvEkDehk.d.ts +195 -0
- package/dist/state.cjs +768 -659
- package/dist/state.d.ts +11 -71
- package/dist/state.js +760 -651
- package/dist/state.mjs +767 -658
- 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 +50 -237
- package/dist/universal.cjs +1 -1
- package/dist/universal.d.ts +1 -7
- 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 +8 -1
- package/vendor/epaint-0.31.1/src/image.rs +418 -0
- package/dist/server-uMQvZAll.d.ts +0 -458
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,669 +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
|
-
|
|
488
|
-
|
|
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 });
|
|
489
525
|
}
|
|
490
|
-
} else {
|
|
491
|
-
html += isRawText && typeof child === "string" ? child : this.renderToString(child, { pretty, indent: indent + 1 });
|
|
492
526
|
}
|
|
527
|
+
} else {
|
|
528
|
+
html += isRawText && typeof child === "string" ? child : renderToString(child, { pretty, indent: indent + 1 });
|
|
493
529
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
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 });
|
|
503
539
|
}
|
|
504
|
-
} else {
|
|
505
|
-
html += isRawText && typeof child === "string" ? child : this.renderToString(child, { pretty: false, indent: 0 });
|
|
506
540
|
}
|
|
541
|
+
} else {
|
|
542
|
+
html += isRawText && typeof child === "string" ? child : renderToString(child, { pretty: false, indent: 0 });
|
|
507
543
|
}
|
|
508
544
|
}
|
|
509
545
|
}
|
|
510
|
-
html += `</${tagName}>${newLine}`;
|
|
511
|
-
return html;
|
|
512
546
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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])}"`;
|
|
516
573
|
}
|
|
517
|
-
|
|
574
|
+
html += `>${nl}`;
|
|
518
575
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
576
|
+
for (const linkAttrs of links) {
|
|
577
|
+
html += `${indent2}<link`;
|
|
578
|
+
for (const key in linkAttrs) {
|
|
579
|
+
html += ` ${key}="${escapeHtml(linkAttrs[key])}"`;
|
|
522
580
|
}
|
|
523
|
-
|
|
581
|
+
html += `>${nl}`;
|
|
524
582
|
}
|
|
525
|
-
|
|
526
|
-
if (
|
|
527
|
-
|
|
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}`;
|
|
528
588
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
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)}"`;
|
|
532
603
|
}
|
|
533
|
-
if (
|
|
534
|
-
|
|
535
|
-
if (child && typeof child === "object" && child.tagName === "span") {
|
|
536
|
-
const props = child.props;
|
|
537
|
-
const hasNoProps = !props || Object.keys(props).length === 0;
|
|
538
|
-
const hasSingleStringChild = child.children && child.children.length === 1 && typeof child.children[0] === "string";
|
|
539
|
-
if (hasNoProps && hasSingleStringChild) {
|
|
540
|
-
return child.children[0];
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
return this.unwrapReactive(child);
|
|
604
|
+
if (script.async) {
|
|
605
|
+
html += " async";
|
|
544
606
|
}
|
|
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
|
-
|
|
589
|
-
const className = Array.isArray(value) ? value.join(" ") : value;
|
|
590
|
-
if (className) {
|
|
591
|
-
attrs.push(`class="${this.escapeHtml(String(className))}"`);
|
|
592
|
-
}
|
|
593
|
-
continue;
|
|
594
|
-
}
|
|
595
|
-
if (key === "style") {
|
|
596
|
-
const styleStr = this.styleToString(value);
|
|
597
|
-
if (styleStr) {
|
|
598
|
-
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
|
+
}
|
|
599
651
|
}
|
|
600
|
-
continue;
|
|
601
652
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
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);
|
|
605
659
|
}
|
|
606
|
-
|
|
660
|
+
} else {
|
|
661
|
+
childrenArray.push(children);
|
|
607
662
|
}
|
|
608
|
-
return attrs.join(" ");
|
|
609
663
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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);
|
|
619
687
|
}
|
|
620
|
-
return styles.join(";");
|
|
621
688
|
}
|
|
622
|
-
return "";
|
|
623
689
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
const entry = { node: null, renderFn };
|
|
631
|
-
this.reactiveNodes.set(state, entry);
|
|
632
|
-
state.subscribe(() => {
|
|
633
|
-
if (entry.node && entry.node.parentNode) {
|
|
634
|
-
const newValue = renderFn(state.value);
|
|
635
|
-
entry.node.textContent = String(newValue ?? "");
|
|
636
|
-
}
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
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");
|
|
640
696
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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);
|
|
656
729
|
}
|
|
730
|
+
} else {
|
|
731
|
+
notify();
|
|
657
732
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
} else {
|
|
679
|
-
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);
|
|
680
753
|
}
|
|
681
754
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
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);
|
|
690
789
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
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 = "";
|
|
696
804
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
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;
|
|
707
815
|
}
|
|
708
|
-
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);
|
|
709
887
|
}
|
|
710
888
|
renderJson(rootElement, json) {
|
|
711
|
-
|
|
712
|
-
if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
|
|
713
|
-
throw new Error("Invalid JSON structure");
|
|
714
|
-
}
|
|
715
|
-
return this.render(rootElement, vNode);
|
|
889
|
+
return renderJson(rootElement, json, this.reactiveNodes);
|
|
716
890
|
}
|
|
717
891
|
renderVNode(rootElement, json) {
|
|
718
|
-
|
|
719
|
-
if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
|
|
720
|
-
throw new Error("Invalid VNode JSON structure");
|
|
721
|
-
}
|
|
722
|
-
return this.render(rootElement, vNode);
|
|
892
|
+
return renderVNode(rootElement, json, this.reactiveNodes);
|
|
723
893
|
}
|
|
724
894
|
renderJsonToString(json, options = {}) {
|
|
725
|
-
|
|
726
|
-
return this.renderToString(vNode, options);
|
|
895
|
+
return renderJsonToString(json, this.reactiveNodes, options);
|
|
727
896
|
}
|
|
728
897
|
renderVNodeToString(json, options = {}) {
|
|
729
|
-
|
|
730
|
-
return this.renderToString(vNode, options);
|
|
898
|
+
return renderVNodeToString(json, this.reactiveNodes, options);
|
|
731
899
|
}
|
|
732
900
|
// Generate complete HTML document as string (for SSR)
|
|
733
901
|
renderToHTMLDocument(vNode, options = {}) {
|
|
734
|
-
|
|
735
|
-
const nl = pretty ? "\n" : "";
|
|
736
|
-
const indent = pretty ? " " : "";
|
|
737
|
-
const indent2 = pretty ? " " : "";
|
|
738
|
-
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}`;
|
|
739
|
-
if (title) html += `${indent2}<title>${this.escapeHtml(title)}</title>${nl}`;
|
|
740
|
-
for (const m of meta) {
|
|
741
|
-
html += `${indent2}<meta`;
|
|
742
|
-
for (const k in m) html += ` ${k}="${this.escapeHtml(m[k])}"`;
|
|
743
|
-
html += `>${nl}`;
|
|
744
|
-
}
|
|
745
|
-
for (const l of links) {
|
|
746
|
-
html += `${indent2}<link`;
|
|
747
|
-
for (const k in l) html += ` ${k}="${this.escapeHtml(l[k])}"`;
|
|
748
|
-
html += `>${nl}`;
|
|
749
|
-
}
|
|
750
|
-
for (const s of styles) {
|
|
751
|
-
if (s.href) {
|
|
752
|
-
html += `${indent2}<link rel="stylesheet" href="${this.escapeHtml(s.href)}">${nl}`;
|
|
753
|
-
} else if (s.content) {
|
|
754
|
-
html += `${indent2}<style>${s.content}</style>${nl}`;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
if (head) html += head + nl;
|
|
758
|
-
html += `${indent}</head>${nl}${indent}<body`;
|
|
759
|
-
for (const k in bodyAttrs) html += ` ${k}="${this.escapeHtml(bodyAttrs[k])}"`;
|
|
760
|
-
html += `>${nl}`;
|
|
761
|
-
html += this.renderToString(vNode, { pretty, indent: 2 });
|
|
762
|
-
for (const script of scripts) {
|
|
763
|
-
html += `${indent2}<script`;
|
|
764
|
-
if (script.type) html += ` type="${this.escapeHtml(script.type)}"`;
|
|
765
|
-
if (script.async) html += ` async`;
|
|
766
|
-
if (script.defer) html += ` defer`;
|
|
767
|
-
if (script.src) {
|
|
768
|
-
html += ` src="${this.escapeHtml(script.src)}"></script>${nl}`;
|
|
769
|
-
} else if (script.content) {
|
|
770
|
-
html += `>${script.content}</script>${nl}`;
|
|
771
|
-
} else {
|
|
772
|
-
html += `></script>${nl}`;
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
html += `${indent}</body>${nl}</html>`;
|
|
776
|
-
return html;
|
|
902
|
+
return renderToHTMLDocument(vNode, options);
|
|
777
903
|
}
|
|
778
904
|
// Expose elementCache for reactive updates
|
|
779
905
|
getElementCache() {
|
|
@@ -781,20 +907,20 @@ var DomNode = class {
|
|
|
781
907
|
}
|
|
782
908
|
};
|
|
783
909
|
var dom = new DomNode();
|
|
784
|
-
var
|
|
785
|
-
var
|
|
910
|
+
var render2 = dom.render.bind(dom);
|
|
911
|
+
var renderToString2 = dom.renderToString.bind(dom);
|
|
786
912
|
|
|
787
|
-
// src/state.ts
|
|
788
|
-
var
|
|
789
|
-
var
|
|
790
|
-
var
|
|
791
|
-
var
|
|
792
|
-
var
|
|
793
|
-
var
|
|
794
|
-
var
|
|
795
|
-
var createVirtualList = (container, items, renderItem, itemHeight, bufferSize) => dom.createVirtualList(container, items, renderItem, itemHeight, bufferSize);
|
|
796
|
-
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);
|
|
797
921
|
var cleanupUnused = (root) => dom.cleanupUnusedElements(root);
|
|
922
|
+
|
|
923
|
+
// src/client/state/timing.ts
|
|
798
924
|
var throttle = (fn, delay) => {
|
|
799
925
|
let timer = null;
|
|
800
926
|
return (...args) => {
|
|
@@ -809,10 +935,15 @@ var throttle = (fn, delay) => {
|
|
|
809
935
|
var debounce = (fn, delay) => {
|
|
810
936
|
let timer = null;
|
|
811
937
|
return (...args) => {
|
|
812
|
-
|
|
938
|
+
if (timer) {
|
|
939
|
+
clearTimeout(timer);
|
|
940
|
+
}
|
|
813
941
|
timer = setTimeout(() => fn(...args), delay);
|
|
814
942
|
};
|
|
815
943
|
};
|
|
944
|
+
|
|
945
|
+
// src/client/state/bindings.ts
|
|
946
|
+
var ELIT_NATIVE_BINDING = /* @__PURE__ */ Symbol.for("elit.native.binding");
|
|
816
947
|
function bindValue(state) {
|
|
817
948
|
const props = {
|
|
818
949
|
value: state.value,
|
|
@@ -852,6 +983,9 @@ function bindChecked(state) {
|
|
|
852
983
|
};
|
|
853
984
|
return props;
|
|
854
985
|
}
|
|
986
|
+
|
|
987
|
+
// src/client/state/shared-state.ts
|
|
988
|
+
var ELIT_INTERNAL_WS_PATH = "/__elit_ws";
|
|
855
989
|
function resolveSharedStateWebSocketUrl(wsUrl) {
|
|
856
990
|
const protocol = typeof location !== "undefined" && location.protocol === "https:" ? "wss:" : "ws:";
|
|
857
991
|
const origin = typeof location !== "undefined" ? `${protocol}//${location.host}` : `${protocol}//localhost`;
|
|
@@ -876,33 +1010,21 @@ var SharedState = class {
|
|
|
876
1010
|
this.wsUrl = wsUrl;
|
|
877
1011
|
this.ws = null;
|
|
878
1012
|
this.pendingUpdates = [];
|
|
879
|
-
this.localState =
|
|
1013
|
+
this.localState = createState2(defaultValue);
|
|
880
1014
|
this.previousValue = defaultValue;
|
|
881
1015
|
this.connect();
|
|
882
1016
|
}
|
|
883
|
-
/**
|
|
884
|
-
* Get current value
|
|
885
|
-
*/
|
|
886
1017
|
get value() {
|
|
887
1018
|
return this.localState.value;
|
|
888
1019
|
}
|
|
889
|
-
/**
|
|
890
|
-
* Set new value and sync to server
|
|
891
|
-
*/
|
|
892
1020
|
set value(newValue) {
|
|
893
1021
|
this.previousValue = this.localState.value;
|
|
894
1022
|
this.localState.value = newValue;
|
|
895
1023
|
this.sendToServer(newValue);
|
|
896
1024
|
}
|
|
897
|
-
/**
|
|
898
|
-
* Get the underlying Elit State (for reactive binding)
|
|
899
|
-
*/
|
|
900
1025
|
get state() {
|
|
901
1026
|
return this.localState;
|
|
902
1027
|
}
|
|
903
|
-
/**
|
|
904
|
-
* Subscribe to changes (returns Elit State for reactive)
|
|
905
|
-
*/
|
|
906
1028
|
onChange(callback) {
|
|
907
1029
|
return this.localState.subscribe((newValue) => {
|
|
908
1030
|
const oldValue = this.previousValue;
|
|
@@ -910,17 +1032,13 @@ var SharedState = class {
|
|
|
910
1032
|
callback(newValue, oldValue);
|
|
911
1033
|
});
|
|
912
1034
|
}
|
|
913
|
-
/**
|
|
914
|
-
* Update value using a function
|
|
915
|
-
*/
|
|
916
1035
|
update(updater) {
|
|
917
1036
|
this.value = updater(this.value);
|
|
918
1037
|
}
|
|
919
|
-
/**
|
|
920
|
-
* Connect to WebSocket
|
|
921
|
-
*/
|
|
922
1038
|
connect() {
|
|
923
|
-
if (typeof window === "undefined")
|
|
1039
|
+
if (typeof window === "undefined") {
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
924
1042
|
const url = resolveSharedStateWebSocketUrl(this.wsUrl);
|
|
925
1043
|
this.ws = new WebSocket(url);
|
|
926
1044
|
this.ws.addEventListener("open", () => {
|
|
@@ -940,34 +1058,31 @@ var SharedState = class {
|
|
|
940
1058
|
console.error("[SharedState] WebSocket error:", error);
|
|
941
1059
|
});
|
|
942
1060
|
}
|
|
943
|
-
/**
|
|
944
|
-
* Subscribe to server state
|
|
945
|
-
*/
|
|
946
1061
|
subscribe() {
|
|
947
|
-
if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
|
|
1062
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
948
1065
|
this.ws.send(JSON.stringify({
|
|
949
1066
|
type: "state:subscribe",
|
|
950
1067
|
key: this.key
|
|
951
1068
|
}));
|
|
952
1069
|
}
|
|
953
|
-
/**
|
|
954
|
-
* Handle message from server
|
|
955
|
-
*/
|
|
956
1070
|
handleMessage(data) {
|
|
957
1071
|
try {
|
|
958
1072
|
const msg = JSON.parse(data);
|
|
959
|
-
if (msg.key !== this.key)
|
|
1073
|
+
if (msg.key !== this.key) {
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
960
1076
|
if (msg.type === "state:init" || msg.type === "state:update") {
|
|
961
1077
|
this.localState.value = msg.value;
|
|
962
1078
|
}
|
|
963
1079
|
} catch (error) {
|
|
964
1080
|
}
|
|
965
1081
|
}
|
|
966
|
-
/**
|
|
967
|
-
* Send value to server
|
|
968
|
-
*/
|
|
969
1082
|
sendToServer(value) {
|
|
970
|
-
if (!this.ws)
|
|
1083
|
+
if (!this.ws) {
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
971
1086
|
if (this.ws.readyState !== WebSocket.OPEN) {
|
|
972
1087
|
this.pendingUpdates.push(value);
|
|
973
1088
|
return;
|
|
@@ -978,18 +1093,12 @@ var SharedState = class {
|
|
|
978
1093
|
value
|
|
979
1094
|
}));
|
|
980
1095
|
}
|
|
981
|
-
/**
|
|
982
|
-
* Disconnect
|
|
983
|
-
*/
|
|
984
1096
|
disconnect() {
|
|
985
1097
|
if (this.ws) {
|
|
986
1098
|
this.ws.close();
|
|
987
1099
|
this.ws = null;
|
|
988
1100
|
}
|
|
989
1101
|
}
|
|
990
|
-
/**
|
|
991
|
-
* Destroy state and cleanup
|
|
992
|
-
*/
|
|
993
1102
|
destroy() {
|
|
994
1103
|
this.disconnect();
|
|
995
1104
|
this.localState.destroy();
|
|
@@ -1002,9 +1111,6 @@ var SharedStateManager = class {
|
|
|
1002
1111
|
constructor() {
|
|
1003
1112
|
this.states = /* @__PURE__ */ new Map();
|
|
1004
1113
|
}
|
|
1005
|
-
/**
|
|
1006
|
-
* Create or get a shared state
|
|
1007
|
-
*/
|
|
1008
1114
|
create(key, defaultValue, wsUrl) {
|
|
1009
1115
|
if (this.states.has(key)) {
|
|
1010
1116
|
return this.states.get(key);
|
|
@@ -1013,15 +1119,9 @@ var SharedStateManager = class {
|
|
|
1013
1119
|
this.states.set(key, state);
|
|
1014
1120
|
return state;
|
|
1015
1121
|
}
|
|
1016
|
-
/**
|
|
1017
|
-
* Get existing state
|
|
1018
|
-
*/
|
|
1019
1122
|
get(key) {
|
|
1020
1123
|
return this.states.get(key);
|
|
1021
1124
|
}
|
|
1022
|
-
/**
|
|
1023
|
-
* Delete a state
|
|
1024
|
-
*/
|
|
1025
1125
|
delete(key) {
|
|
1026
1126
|
const state = this.states.get(key);
|
|
1027
1127
|
if (state) {
|
|
@@ -1030,17 +1130,18 @@ var SharedStateManager = class {
|
|
|
1030
1130
|
}
|
|
1031
1131
|
return false;
|
|
1032
1132
|
}
|
|
1033
|
-
/**
|
|
1034
|
-
* Clear all states
|
|
1035
|
-
*/
|
|
1036
1133
|
clear() {
|
|
1037
1134
|
this.states.forEach((state) => state.destroy());
|
|
1038
1135
|
this.states.clear();
|
|
1039
1136
|
}
|
|
1040
1137
|
};
|
|
1041
1138
|
var sharedStateManager = new SharedStateManager();
|
|
1139
|
+
|
|
1140
|
+
// src/client/state/reactive-utils.ts
|
|
1042
1141
|
var scheduleRAFUpdate = (rafId, updateFn) => {
|
|
1043
|
-
|
|
1142
|
+
if (rafId) {
|
|
1143
|
+
cancelAnimationFrame(rafId);
|
|
1144
|
+
}
|
|
1044
1145
|
return requestAnimationFrame(() => {
|
|
1045
1146
|
updateFn();
|
|
1046
1147
|
});
|
|
@@ -1064,12 +1165,16 @@ var renderToFragment = (content, isVNode) => {
|
|
|
1064
1165
|
var updateElementProps = (element, props) => {
|
|
1065
1166
|
for (const key in props) {
|
|
1066
1167
|
const value = props[key];
|
|
1067
|
-
if (key === "ref")
|
|
1168
|
+
if (key === "ref") {
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
1068
1171
|
if (key === "class" || key === "className") {
|
|
1069
1172
|
element.className = Array.isArray(value) ? value.join(" ") : value || "";
|
|
1070
1173
|
} else if (key === "style" && typeof value === "object") {
|
|
1071
|
-
const
|
|
1072
|
-
for (const
|
|
1174
|
+
const style = element.style;
|
|
1175
|
+
for (const styleKey in value) {
|
|
1176
|
+
style[styleKey] = value[styleKey];
|
|
1177
|
+
}
|
|
1073
1178
|
} else if (key.startsWith("on")) {
|
|
1074
1179
|
element[key.toLowerCase()] = value;
|
|
1075
1180
|
} else if (value != null && value !== false) {
|
|
@@ -1079,6 +1184,8 @@ var updateElementProps = (element, props) => {
|
|
|
1079
1184
|
}
|
|
1080
1185
|
}
|
|
1081
1186
|
};
|
|
1187
|
+
|
|
1188
|
+
// src/client/state/reactive.ts
|
|
1082
1189
|
var reactive = (state, renderFn) => {
|
|
1083
1190
|
let rafId = null;
|
|
1084
1191
|
let elementRef = null;
|
|
@@ -1088,7 +1195,9 @@ var reactive = (state, renderFn) => {
|
|
|
1088
1195
|
const isVNodeResult = initialResult && typeof initialResult === "object" && "tagName" in initialResult;
|
|
1089
1196
|
const initialIsNull = initialResult == null || initialResult === false;
|
|
1090
1197
|
const updateElement = () => {
|
|
1091
|
-
if (!elementRef && !placeholder)
|
|
1198
|
+
if (!elementRef && !placeholder) {
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1092
1201
|
const newResult = renderFn(state.value);
|
|
1093
1202
|
const resultIsNull = newResult == null || newResult === false;
|
|
1094
1203
|
if (resultIsNull) {
|
|
@@ -1169,7 +1278,7 @@ var reactiveAs = (tagName, state, renderFn, props = {}) => {
|
|
|
1169
1278
|
const initialChildren = Array.isArray(initialResult) ? initialResult : [initialResult];
|
|
1170
1279
|
return { tagName, props: { ...props, ref: refCallback }, children: initialChildren };
|
|
1171
1280
|
};
|
|
1172
|
-
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);
|
|
1173
1282
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1174
1283
|
0 && (module.exports = {
|
|
1175
1284
|
ELIT_NATIVE_BINDING,
|