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