elit 3.6.6 → 3.6.8

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.
Files changed (155) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/README.md +20 -1
  4. package/dist/build.cjs +421 -331
  5. package/dist/build.d.ts +1 -19
  6. package/dist/build.js +420 -330
  7. package/dist/build.mjs +420 -330
  8. package/dist/chokidar.cjs +219 -182
  9. package/dist/chokidar.d.ts +25 -10
  10. package/dist/chokidar.js +217 -182
  11. package/dist/chokidar.mjs +218 -183
  12. package/dist/cli.cjs +25197 -22128
  13. package/dist/cli.d.ts +19 -37
  14. package/dist/cli.mjs +26668 -23614
  15. package/dist/config.cjs +357 -350
  16. package/dist/config.d.ts +17 -245
  17. package/dist/config.js +520 -515
  18. package/dist/config.mjs +346 -341
  19. package/dist/contracts-D7KIS-TK.d.ts +36 -0
  20. package/dist/contracts-_0p1-15U.d.ts +54 -0
  21. package/dist/coverage.cjs +448 -485
  22. package/dist/coverage.d.ts +13 -62
  23. package/dist/coverage.js +447 -484
  24. package/dist/coverage.mjs +447 -484
  25. package/dist/database.cjs +819 -828
  26. package/dist/database.d.ts +8 -24
  27. package/dist/database.js +818 -829
  28. package/dist/database.mjs +818 -829
  29. package/dist/desktop-auto-render.cjs +1700 -1523
  30. package/dist/desktop-auto-render.d.ts +4 -12
  31. package/dist/desktop-auto-render.js +1695 -1518
  32. package/dist/desktop-auto-render.mjs +1696 -1519
  33. package/dist/desktop.cjs +3 -1
  34. package/dist/desktop.d.ts +4 -1
  35. package/dist/desktop.js +1 -1
  36. package/dist/desktop.mjs +1 -1
  37. package/dist/dev-build.cjs +830 -0
  38. package/dist/dev-build.d.ts +53 -0
  39. package/dist/dev-build.js +3318 -0
  40. package/dist/dev-build.mjs +797 -0
  41. package/dist/dom.cjs +717 -591
  42. package/dist/dom.d.ts +2 -17
  43. package/dist/dom.js +714 -588
  44. package/dist/dom.mjs +716 -590
  45. package/dist/el.cjs +62 -52
  46. package/dist/el.d.ts +5 -12
  47. package/dist/el.js +60 -52
  48. package/dist/el.mjs +60 -52
  49. package/dist/fs.cjs +72 -63
  50. package/dist/fs.d.ts +22 -19
  51. package/dist/fs.js +71 -62
  52. package/dist/fs.mjs +71 -62
  53. package/dist/hmr.cjs +40 -14
  54. package/dist/hmr.d.ts +11 -23
  55. package/dist/hmr.js +38 -14
  56. package/dist/hmr.mjs +38 -14
  57. package/dist/http.cjs +411 -140
  58. package/dist/http.d.ts +40 -112
  59. package/dist/http.js +409 -140
  60. package/dist/http.mjs +409 -140
  61. package/dist/https.cjs +716 -272
  62. package/dist/https.d.ts +46 -41
  63. package/dist/https.js +712 -270
  64. package/dist/https.mjs +714 -272
  65. package/dist/index.cjs +7502 -7691
  66. package/dist/index.d.ts +6 -3
  67. package/dist/index.js +7486 -7677
  68. package/dist/index.mjs +7497 -7687
  69. package/dist/mime-types.cjs +10 -4
  70. package/dist/mime-types.d.ts +8 -11
  71. package/dist/mime-types.js +9 -3
  72. package/dist/mime-types.mjs +9 -3
  73. package/dist/native.cjs +8616 -8870
  74. package/dist/native.d.ts +7 -10
  75. package/dist/native.js +8682 -8936
  76. package/dist/native.mjs +8615 -8869
  77. package/dist/path.cjs +83 -77
  78. package/dist/path.d.ts +29 -29
  79. package/dist/path.js +82 -76
  80. package/dist/path.mjs +82 -76
  81. package/dist/pm-node-shared-listener-bootstrap.cjs +75 -0
  82. package/dist/pm.cjs +5267 -0
  83. package/dist/pm.d.ts +331 -0
  84. package/dist/pm.js +7575 -0
  85. package/dist/pm.mjs +5148 -0
  86. package/dist/preview-build.cjs +712 -0
  87. package/dist/preview-build.d.ts +59 -0
  88. package/dist/preview-build.js +3194 -0
  89. package/dist/preview-build.mjs +676 -0
  90. package/dist/render-context.cjs +13 -2
  91. package/dist/render-context.d.ts +9 -34
  92. package/dist/render-context.js +11 -2
  93. package/dist/render-context.mjs +11 -2
  94. package/dist/router.cjs +787 -646
  95. package/dist/router.d.ts +8 -14
  96. package/dist/router.js +786 -645
  97. package/dist/router.mjs +786 -645
  98. package/dist/runtime.cjs +1 -1
  99. package/dist/runtime.js +1 -1
  100. package/dist/runtime.mjs +1 -1
  101. package/dist/server.cjs +3702 -2883
  102. package/dist/server.d.ts +47 -5
  103. package/dist/server.js +4007 -3165
  104. package/dist/server.mjs +3665 -2848
  105. package/dist/smtp-server.cjs +16 -3
  106. package/dist/smtp-server.d.ts +12 -26
  107. package/dist/smtp-server.js +55 -17
  108. package/dist/smtp-server.mjs +16 -3
  109. package/dist/state.cjs +768 -659
  110. package/dist/state.d.ts +11 -71
  111. package/dist/state.js +760 -651
  112. package/dist/state.mjs +767 -658
  113. package/dist/style.cjs +1011 -968
  114. package/dist/style.d.ts +13 -127
  115. package/dist/style.js +1009 -970
  116. package/dist/style.mjs +1011 -971
  117. package/dist/test-reporter.cjs +332 -316
  118. package/dist/test-reporter.d.ts +28 -33
  119. package/dist/test-reporter.js +328 -312
  120. package/dist/test-reporter.mjs +328 -312
  121. package/dist/test-runtime.cjs +927 -968
  122. package/dist/test-runtime.d.ts +24 -99
  123. package/dist/test-runtime.js +922 -965
  124. package/dist/test-runtime.mjs +922 -965
  125. package/dist/test.cjs +4428 -4273
  126. package/dist/test.d.ts +2 -8
  127. package/dist/test.js +4307 -4154
  128. package/dist/test.mjs +4419 -4267
  129. package/dist/types-BONVzPtp.d.ts +59 -0
  130. package/dist/types-BR4wMiVx.d.ts +32 -0
  131. package/dist/types-BayMVo_k.d.ts +278 -0
  132. package/dist/types-C4gKykuG.d.ts +23 -0
  133. package/dist/types-C70T-42Z.d.ts +64 -0
  134. package/dist/types-Ckj8md_j.d.ts +84 -0
  135. package/dist/types-CpjQTAkX.d.ts +24 -0
  136. package/dist/types-D0LjrYjS.d.ts +14 -0
  137. package/dist/types-DPOgoGs-.d.ts +81 -0
  138. package/dist/types-fiLday0L.d.ts +199 -0
  139. package/dist/types.d.ts +54 -237
  140. package/dist/universal.cjs +1 -1
  141. package/dist/universal.d.ts +1 -7
  142. package/dist/universal.js +1 -1
  143. package/dist/universal.mjs +1 -1
  144. package/dist/websocket-BLBEAnhp.d.ts +119 -0
  145. package/dist/ws.cjs +129 -108
  146. package/dist/ws.d.ts +21 -131
  147. package/dist/ws.js +128 -109
  148. package/dist/ws.mjs +128 -109
  149. package/dist/wss.cjs +938 -512
  150. package/dist/wss.d.ts +31 -28
  151. package/dist/wss.js +932 -508
  152. package/dist/wss.mjs +936 -512
  153. package/package.json +18 -6
  154. package/vendor/epaint-0.31.1/src/image.rs +418 -0
  155. package/dist/server-uMQvZAll.d.ts +0 -458
package/dist/dom.cjs CHANGED
@@ -17,24 +17,28 @@ var __copyProps = (to, from, except, desc) => {
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
- // src/dom.ts
20
+ // src/client/dom/index.ts
21
21
  var dom_exports = {};
22
22
  __export(dom_exports, {
23
23
  DomNode: () => DomNode,
24
24
  dom: () => dom,
25
25
  mount: () => mount,
26
- render: () => render,
27
- renderToString: () => renderToString
26
+ render: () => render2,
27
+ renderToString: () => renderToString2
28
28
  });
29
29
  module.exports = __toCommonJS(dom_exports);
30
30
 
31
- // src/render-context.ts
31
+ // src/desktop/render-context/constants.ts
32
32
  var RUNTIME_TARGET_KEY = "__ELIT_RUNTIME_TARGET__";
33
33
  var CAPTURED_RENDER_KEY = "__ELIT_CAPTURED_RENDER__";
34
34
  var RUNTIME_TARGET_ENV = "ELIT_RUNTIME_TARGET";
35
+
36
+ // src/desktop/render-context/globals.ts
35
37
  function getGlobalRenderScope() {
36
38
  return globalThis;
37
39
  }
40
+
41
+ // src/desktop/render-context/runtime-target.ts
38
42
  function isRenderRuntimeTarget(value) {
39
43
  return value === "web" || value === "desktop" || value === "mobile" || value === "unknown";
40
44
  }
@@ -50,7 +54,8 @@ function detectRenderRuntimeTarget() {
50
54
  if (typeof globalScope.createWindow === "function") {
51
55
  return "desktop";
52
56
  }
53
- const argv = Array.isArray(globalScope.process?.argv) ? globalScope.process.argv.join(" ") : "";
57
+ const argvValues = globalScope.process?.argv;
58
+ const argv = Array.isArray(argvValues) ? argvValues.join(" ") : "";
54
59
  if (/\bdesktop\b/i.test(argv)) {
55
60
  return "desktop";
56
61
  }
@@ -59,6 +64,8 @@ function detectRenderRuntimeTarget() {
59
64
  }
60
65
  return "unknown";
61
66
  }
67
+
68
+ // src/desktop/render-context/captured-render.ts
62
69
  function captureRenderedVNode(rootElement, vNode, target = detectRenderRuntimeTarget()) {
63
70
  const globalScope = getGlobalRenderScope();
64
71
  globalScope[RUNTIME_TARGET_KEY] = target;
@@ -69,7 +76,7 @@ function captureRenderedVNode(rootElement, vNode, target = detectRenderRuntimeTa
69
76
  };
70
77
  }
71
78
 
72
- // src/dom.ts
79
+ // src/client/dom/helpers.ts
73
80
  function resolveElement(rootElement) {
74
81
  return typeof rootElement === "string" ? document.getElementById(rootElement.replace("#", "")) : rootElement;
75
82
  }
@@ -97,669 +104,788 @@ function resolveTextareaValue(tagName, props) {
97
104
  function hasDocumentApi() {
98
105
  return typeof document !== "undefined";
99
106
  }
100
- var DomNode = class {
101
- constructor() {
102
- this.elementCache = /* @__PURE__ */ new WeakMap();
103
- this.reactiveNodes = /* @__PURE__ */ new Map();
104
- }
105
- createElement(tagName, props = {}, children = []) {
106
- return { tagName, props, children };
107
- }
108
- renderToDOM(vNode, parent) {
109
- if (vNode == null || vNode === false) return;
110
- if (typeof vNode !== "object") {
111
- parent.appendChild(document.createTextNode(String(vNode)));
112
- return;
113
- }
114
- if (this.isState(vNode)) {
115
- const textNode = document.createTextNode(String(vNode.value ?? ""));
116
- parent.appendChild(textNode);
117
- vNode.subscribe((newValue) => {
118
- textNode.textContent = String(newValue ?? "");
119
- });
120
- return;
121
- }
122
- if (Array.isArray(vNode)) {
123
- for (const child of vNode) {
124
- this.renderToDOM(child, parent);
107
+ function isState(value) {
108
+ return value && typeof value === "object" && "value" in value && "subscribe" in value && typeof value.subscribe === "function";
109
+ }
110
+
111
+ // src/client/dom/dom-render.ts
112
+ function isSvgElement(tagName, parent) {
113
+ return tagName === "svg" || tagName[0] === "s" && tagName[1] === "v" && tagName[2] === "g" || parent.namespaceURI === "http://www.w3.org/2000/svg";
114
+ }
115
+ function applyProps(el, props, textareaValue) {
116
+ for (const key in props) {
117
+ const value = props[key];
118
+ if (value == null || value === false) continue;
119
+ const c = key.charCodeAt(0);
120
+ if (c === 99 && (key.length < 6 || key[5] === "N")) {
121
+ const classValue = Array.isArray(value) ? value.join(" ") : String(value);
122
+ if (el instanceof SVGElement) {
123
+ el.setAttribute("class", classValue);
124
+ } else {
125
+ el.className = classValue;
125
126
  }
126
- return;
127
- }
128
- const { tagName, props, children } = vNode;
129
- const textareaValue = resolveTextareaValue(tagName, props);
130
- if (!tagName) {
131
- for (const child of children) {
132
- if (shouldSkipChild(child)) continue;
133
- if (Array.isArray(child)) {
134
- for (const c of child) {
135
- !shouldSkipChild(c) && this.renderToDOM(c, parent);
136
- }
137
- } else {
138
- this.renderToDOM(child, parent);
127
+ } else if (c === 115 && key.length === 5) {
128
+ if (typeof value === "string") {
129
+ el.style.cssText = value;
130
+ } else {
131
+ const style = el.style;
132
+ for (const styleKey in value) {
133
+ style[styleKey] = value[styleKey];
139
134
  }
140
135
  }
141
- return;
142
- }
143
- const isSVG = tagName === "svg" || tagName[0] === "s" && tagName[1] === "v" && tagName[2] === "g" || parent.namespaceURI === "http://www.w3.org/2000/svg";
144
- const el = isSVG ? document.createElementNS("http://www.w3.org/2000/svg", tagName.replace("svg", "").toLowerCase() || tagName) : document.createElement(tagName);
145
- for (const key in props) {
146
- const value = props[key];
147
- if (value == null || value === false) continue;
148
- const c = key.charCodeAt(0);
149
- if (c === 99 && (key.length < 6 || key[5] === "N")) {
150
- const classValue = Array.isArray(value) ? value.join(" ") : value;
151
- isSVG ? el.setAttribute("class", classValue) : el.className = classValue;
152
- } else if (c === 115 && key.length === 5) {
153
- if (typeof value === "string") {
154
- el.style.cssText = value;
136
+ } else if (c === 111 && key.charCodeAt(1) === 110) {
137
+ el[key.toLowerCase()] = value;
138
+ } else if (c === 100 && key.length > 20) {
139
+ el.innerHTML = value.__html;
140
+ } else if (c === 114 && key === "ref") {
141
+ setTimeout(() => {
142
+ if (typeof value === "function") {
143
+ value(el);
155
144
  } else {
156
- const s = el.style;
157
- for (const k in value) s[k] = value[k];
145
+ value.current = el;
158
146
  }
159
- } else if (c === 111 && key.charCodeAt(1) === 110) {
160
- el[key.toLowerCase()] = value;
161
- } else if (c === 100 && key.length > 20) {
162
- el.innerHTML = value.__html;
163
- } else if (c === 114 && key === "ref") {
164
- setTimeout(() => {
165
- typeof value === "function" ? value(el) : value.current = el;
166
- }, 0);
167
- } else if (textareaValue !== void 0 && key === "value") {
168
- continue;
169
- } else {
170
- el.setAttribute(key, value === true ? "" : String(value));
171
- }
172
- }
173
- const renderableChildren = textareaValue === void 0 ? children : [];
174
- const len = renderableChildren.length;
175
- if (!len) {
176
- if (textareaValue !== void 0) {
177
- el.value = textareaValue;
178
- }
179
- parent.appendChild(el);
180
- return;
147
+ }, 0);
148
+ } else if (textareaValue !== void 0 && key === "value") {
149
+ continue;
150
+ } else {
151
+ el.setAttribute(key, value === true ? "" : String(value));
181
152
  }
182
- const renderChildren = (target) => {
183
- for (let i = 0; i < len; i++) {
184
- const child = renderableChildren[i];
185
- if (shouldSkipChild(child)) continue;
186
- if (Array.isArray(child)) {
187
- for (let j = 0, cLen = child.length; j < cLen; j++) {
188
- const c = child[j];
189
- !shouldSkipChild(c) && this.renderToDOM(c, target);
190
- }
191
- } else {
192
- this.renderToDOM(child, target);
153
+ }
154
+ }
155
+ function renderChildren(children, target) {
156
+ const len = children.length;
157
+ for (let i = 0; i < len; i++) {
158
+ const child = children[i];
159
+ if (shouldSkipChild(child)) continue;
160
+ if (Array.isArray(child)) {
161
+ for (let j = 0, childLen = child.length; j < childLen; j++) {
162
+ const nestedChild = child[j];
163
+ if (!shouldSkipChild(nestedChild)) {
164
+ renderToDOM(nestedChild, target);
193
165
  }
194
166
  }
195
- };
196
- if (len > 30) {
197
- const fragment = document.createDocumentFragment();
198
- renderChildren(fragment);
199
- el.appendChild(fragment);
200
167
  } else {
201
- renderChildren(el);
168
+ renderToDOM(child, target);
202
169
  }
203
- parent.appendChild(el);
204
170
  }
205
- render(rootElement, vNode) {
206
- if (!hasDocumentApi()) {
207
- const runtimeTarget = detectRenderRuntimeTarget();
208
- if (runtimeTarget === "desktop" || runtimeTarget === "mobile") {
209
- captureRenderedVNode(rootElement, vNode, runtimeTarget);
210
- return {};
211
- }
212
- throw new Error("render() requires a DOM or an Elit desktop/mobile runtime target.");
213
- }
214
- const el = ensureElement(resolveElement(rootElement), rootElement);
215
- el.innerHTML = "";
216
- if (vNode.children && vNode.children.length > 500) {
217
- const fragment = document.createDocumentFragment();
218
- this.renderToDOM(vNode, fragment);
219
- el.appendChild(fragment);
220
- } else {
221
- this.renderToDOM(vNode, el);
171
+ }
172
+ function renderToDOM(vNode, parent) {
173
+ if (vNode == null || vNode === false) return;
174
+ if (typeof vNode !== "object") {
175
+ parent.appendChild(document.createTextNode(String(vNode)));
176
+ return;
177
+ }
178
+ if (isState(vNode)) {
179
+ const textNode = document.createTextNode(String(vNode.value ?? ""));
180
+ parent.appendChild(textNode);
181
+ vNode.subscribe((newValue) => {
182
+ textNode.textContent = String(newValue ?? "");
183
+ });
184
+ return;
185
+ }
186
+ if (Array.isArray(vNode)) {
187
+ for (const child of vNode) {
188
+ renderToDOM(child, parent);
222
189
  }
223
- return el;
190
+ return;
224
191
  }
225
- batchRender(rootElement, vNodes) {
226
- const el = ensureElement(resolveElement(rootElement), rootElement);
227
- const len = vNodes.length;
228
- if (len > 3e3) {
229
- const fragment = document.createDocumentFragment();
230
- let processed = 0;
231
- const chunkSize = 1500;
232
- const processChunk = () => {
233
- const end = Math.min(processed + chunkSize, len);
234
- for (let i = processed; i < end; i++) {
235
- this.renderToDOM(vNodes[i], fragment);
236
- }
237
- processed = end;
238
- if (processed >= len) {
239
- el.appendChild(fragment);
240
- } else {
241
- requestAnimationFrame(processChunk);
242
- }
243
- };
244
- processChunk();
245
- } else {
246
- const fragment = document.createDocumentFragment();
247
- for (let i = 0; i < len; i++) {
248
- this.renderToDOM(vNodes[i], fragment);
249
- }
250
- el.appendChild(fragment);
192
+ const { tagName, props, children } = vNode;
193
+ const textareaValue = resolveTextareaValue(tagName, props);
194
+ if (!tagName) {
195
+ renderChildren(children, parent);
196
+ return;
197
+ }
198
+ const el = isSvgElement(tagName, parent) ? document.createElementNS("http://www.w3.org/2000/svg", tagName.replace("svg", "").toLowerCase() || tagName) : document.createElement(tagName);
199
+ applyProps(el, props, textareaValue);
200
+ const renderableChildren = textareaValue === void 0 ? children : [];
201
+ if (!renderableChildren.length) {
202
+ if (textareaValue !== void 0) {
203
+ el.value = textareaValue;
251
204
  }
252
- return el;
205
+ parent.appendChild(el);
206
+ return;
253
207
  }
254
- renderChunked(rootElement, vNodes, chunkSize = 5e3, onProgress) {
255
- const el = ensureElement(resolveElement(rootElement), rootElement);
256
- const len = vNodes.length;
257
- let index = 0;
258
- const renderChunk = () => {
259
- const end = Math.min(index + chunkSize, len);
260
- const fragment = document.createDocumentFragment();
261
- for (let i = index; i < end; i++) {
262
- this.renderToDOM(vNodes[i], fragment);
208
+ if (renderableChildren.length > 30) {
209
+ const fragment = document.createDocumentFragment();
210
+ renderChildren(renderableChildren, fragment);
211
+ el.appendChild(fragment);
212
+ } else {
213
+ renderChildren(renderableChildren, el);
214
+ }
215
+ parent.appendChild(el);
216
+ }
217
+ function render(rootElement, vNode) {
218
+ if (!hasDocumentApi()) {
219
+ const runtimeTarget = detectRenderRuntimeTarget();
220
+ if (runtimeTarget === "desktop" || runtimeTarget === "mobile") {
221
+ captureRenderedVNode(rootElement, vNode, runtimeTarget);
222
+ return {};
223
+ }
224
+ throw new Error("render() requires a DOM or an Elit desktop/mobile runtime target.");
225
+ }
226
+ const el = ensureElement(resolveElement(rootElement), rootElement);
227
+ el.innerHTML = "";
228
+ if (vNode.children && vNode.children.length > 500) {
229
+ const fragment = document.createDocumentFragment();
230
+ renderToDOM(vNode, fragment);
231
+ el.appendChild(fragment);
232
+ } else {
233
+ renderToDOM(vNode, el);
234
+ }
235
+ return el;
236
+ }
237
+ function batchRender(rootElement, vNodes) {
238
+ const el = ensureElement(resolveElement(rootElement), rootElement);
239
+ const len = vNodes.length;
240
+ if (len > 3e3) {
241
+ const fragment = document.createDocumentFragment();
242
+ let processed = 0;
243
+ const chunkSize = 1500;
244
+ const processChunk = () => {
245
+ const end = Math.min(processed + chunkSize, len);
246
+ for (let i = processed; i < end; i++) {
247
+ renderToDOM(vNodes[i], fragment);
263
248
  }
264
- el.appendChild(fragment);
265
- index = end;
266
- if (onProgress) onProgress(index, len);
267
- if (index < len) {
268
- requestAnimationFrame(renderChunk);
249
+ processed = end;
250
+ if (processed >= len) {
251
+ el.appendChild(fragment);
252
+ } else {
253
+ requestAnimationFrame(processChunk);
269
254
  }
270
255
  };
271
- requestAnimationFrame(renderChunk);
272
- return el;
256
+ processChunk();
257
+ } else {
258
+ const fragment = document.createDocumentFragment();
259
+ for (let i = 0; i < len; i++) {
260
+ renderToDOM(vNodes[i], fragment);
261
+ }
262
+ el.appendChild(fragment);
273
263
  }
274
- renderToHead(...vNodes) {
275
- const head = document.head;
276
- if (head) {
277
- for (const vNode of vNodes.flat()) {
278
- vNode && this.renderToDOM(vNode, head);
264
+ return el;
265
+ }
266
+ function renderChunked(rootElement, vNodes, chunkSize = 5e3, onProgress) {
267
+ const el = ensureElement(resolveElement(rootElement), rootElement);
268
+ const len = vNodes.length;
269
+ let index = 0;
270
+ const renderChunkFrame = () => {
271
+ const end = Math.min(index + chunkSize, len);
272
+ const fragment = document.createDocumentFragment();
273
+ for (let i = index; i < end; i++) {
274
+ renderToDOM(vNodes[i], fragment);
275
+ }
276
+ el.appendChild(fragment);
277
+ index = end;
278
+ if (onProgress) {
279
+ onProgress(index, len);
280
+ }
281
+ if (index < len) {
282
+ requestAnimationFrame(renderChunkFrame);
283
+ }
284
+ };
285
+ requestAnimationFrame(renderChunkFrame);
286
+ return el;
287
+ }
288
+ function renderToHead(...vNodes) {
289
+ const head = document.head;
290
+ if (head) {
291
+ for (const vNode of vNodes.flat()) {
292
+ if (vNode) {
293
+ renderToDOM(vNode, head);
279
294
  }
280
295
  }
281
- return head;
282
- }
283
- addStyle(cssText) {
284
- const el = document.createElement("style");
285
- el.textContent = cssText;
286
- return document.head.appendChild(el);
287
296
  }
288
- addMeta(attrs) {
289
- const el = document.createElement("meta");
290
- for (const k in attrs) el.setAttribute(k, attrs[k]);
291
- return document.head.appendChild(el);
297
+ return head;
298
+ }
299
+ function addStyle(cssText) {
300
+ const el = document.createElement("style");
301
+ el.textContent = cssText;
302
+ return document.head.appendChild(el);
303
+ }
304
+ function addMeta(attrs) {
305
+ const el = document.createElement("meta");
306
+ for (const key in attrs) {
307
+ el.setAttribute(key, attrs[key]);
292
308
  }
293
- addLink(attrs) {
294
- const el = document.createElement("link");
295
- for (const k in attrs) el.setAttribute(k, attrs[k]);
296
- return document.head.appendChild(el);
309
+ return document.head.appendChild(el);
310
+ }
311
+ function addLink(attrs) {
312
+ const el = document.createElement("link");
313
+ for (const key in attrs) {
314
+ el.setAttribute(key, attrs[key]);
297
315
  }
298
- setTitle(text) {
299
- return document.title = text;
316
+ return document.head.appendChild(el);
317
+ }
318
+ function setTitle(text) {
319
+ return document.title = text;
320
+ }
321
+ function cleanupUnusedElements(root, elementCache) {
322
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
323
+ const toRemove = [];
324
+ while (walker.nextNode()) {
325
+ const node = walker.currentNode;
326
+ if (node.id && node.id.startsWith("r") && !elementCache.has(node)) {
327
+ toRemove.push(node);
328
+ }
300
329
  }
301
- // Reactive State Management
302
- createState(initialValue, options = {}) {
303
- let value = initialValue;
304
- const listeners = /* @__PURE__ */ new Set();
305
- let updateTimer = null;
306
- const { throttle = 0, deep = false } = options;
307
- const notify = () => listeners.forEach((fn) => fn(value));
308
- const scheduleUpdate = () => {
309
- if (throttle > 0) {
310
- if (!updateTimer) {
311
- updateTimer = setTimeout(() => {
312
- updateTimer = null;
313
- notify();
314
- }, throttle);
315
- }
316
- } else {
317
- notify();
318
- }
319
- };
320
- return {
321
- get value() {
322
- return value;
323
- },
324
- set value(newValue) {
325
- const changed = deep ? JSON.stringify(value) !== JSON.stringify(newValue) : value !== newValue;
326
- if (changed) {
327
- value = newValue;
328
- scheduleUpdate();
329
- }
330
- },
331
- subscribe(fn) {
332
- listeners.add(fn);
333
- return () => listeners.delete(fn);
334
- },
335
- destroy() {
336
- listeners.clear();
337
- updateTimer && clearTimeout(updateTimer);
330
+ toRemove.forEach((el) => el.remove());
331
+ return toRemove.length;
332
+ }
333
+
334
+ // src/client/dom/reactive.ts
335
+ function createReactiveChild(state, reactiveNodes, renderFn) {
336
+ const currentValue = renderFn(state.value);
337
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
338
+ const entry = { node: null, renderFn };
339
+ reactiveNodes.set(state, entry);
340
+ state.subscribe(() => {
341
+ if (entry.node && entry.node.parentNode) {
342
+ const newValue = renderFn(state.value);
343
+ entry.node.textContent = String(newValue ?? "");
338
344
  }
339
- };
340
- }
341
- computed(states, computeFn) {
342
- const values = states.map((s) => s.value);
343
- const result = this.createState(computeFn(...values));
344
- states.forEach((state, index) => {
345
- state.subscribe((newValue) => {
346
- values[index] = newValue;
347
- result.value = computeFn(...values);
348
- });
349
345
  });
350
- return result;
351
346
  }
352
- effect(stateFn) {
353
- stateFn();
347
+ return currentValue;
348
+ }
349
+
350
+ // src/client/dom/string-render.ts
351
+ var SELF_CLOSING_TAGS = /* @__PURE__ */ new Set([
352
+ "area",
353
+ "base",
354
+ "br",
355
+ "col",
356
+ "embed",
357
+ "hr",
358
+ "img",
359
+ "input",
360
+ "link",
361
+ "meta",
362
+ "param",
363
+ "source",
364
+ "track",
365
+ "wbr"
366
+ ]);
367
+ function resolveStateValue(value) {
368
+ return isState(value) ? value.value : value;
369
+ }
370
+ function isReactiveWrapper(vNode) {
371
+ if (!vNode || typeof vNode !== "object" || !vNode.tagName) {
372
+ return false;
354
373
  }
355
- // Virtual scrolling helper for large lists
356
- createVirtualList(container, items, renderItem, itemHeight = 50, bufferSize = 5) {
357
- const viewportHeight = container.clientHeight;
358
- const totalHeight = items.length * itemHeight;
359
- let scrollTop = 0;
360
- const getVisibleRange = () => {
361
- const start = Math.max(0, Math.floor(scrollTop / itemHeight) - bufferSize);
362
- const end = Math.min(items.length, Math.ceil((scrollTop + viewportHeight) / itemHeight) + bufferSize);
363
- return { start, end };
364
- };
365
- const render2 = () => {
366
- const { start, end } = getVisibleRange();
367
- const wrapper = document.createElement("div");
368
- wrapper.style.cssText = `height:${totalHeight}px;position:relative`;
369
- for (let i = start; i < end; i++) {
370
- const itemEl = document.createElement("div");
371
- itemEl.style.cssText = `position:absolute;top:${i * itemHeight}px;height:${itemHeight}px;width:100%`;
372
- this.renderToDOM(renderItem(items[i], i), itemEl);
373
- wrapper.appendChild(itemEl);
374
- }
375
- container.innerHTML = "";
376
- container.appendChild(wrapper);
377
- };
378
- const scrollHandler = () => {
379
- scrollTop = container.scrollTop;
380
- requestAnimationFrame(render2);
381
- };
382
- container.addEventListener("scroll", scrollHandler);
383
- render2();
384
- return {
385
- render: render2,
386
- destroy: () => {
387
- container.removeEventListener("scroll", scrollHandler);
388
- container.innerHTML = "";
389
- }
390
- };
374
+ return vNode.tagName === "span" && vNode.props?.id && typeof vNode.props.id === "string" && /^r[a-z0-9]{9}$/.test(vNode.props.id);
375
+ }
376
+ function unwrapReactive(vNode) {
377
+ if (!isReactiveWrapper(vNode)) {
378
+ return vNode;
391
379
  }
392
- // Lazy load components
393
- lazy(loadFn) {
394
- let component = null;
395
- let loading = false;
396
- return async (...args) => {
397
- if (!component && !loading) {
398
- loading = true;
399
- component = await loadFn();
400
- loading = false;
401
- }
402
- return component ? component(...args) : { tagName: "div", props: { class: "loading" }, children: ["Loading..."] };
403
- };
380
+ const children = vNode.children;
381
+ if (!children || children.length === 0) {
382
+ return "";
404
383
  }
405
- // Memory management - cleanup unused elements
406
- cleanupUnusedElements(root) {
407
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
408
- const toRemove = [];
409
- while (walker.nextNode()) {
410
- const node = walker.currentNode;
411
- if (node.id && node.id.startsWith("r") && !this.elementCache.has(node)) {
412
- toRemove.push(node);
384
+ if (children.length === 1) {
385
+ const child = children[0];
386
+ if (child && typeof child === "object" && child.tagName === "span") {
387
+ const props = child.props;
388
+ const hasNoProps = !props || Object.keys(props).length === 0;
389
+ const hasSingleStringChild = child.children && child.children.length === 1 && typeof child.children[0] === "string";
390
+ if (hasNoProps && hasSingleStringChild) {
391
+ return child.children[0];
413
392
  }
414
393
  }
415
- toRemove.forEach((el) => el.remove());
416
- return toRemove.length;
394
+ return unwrapReactive(child);
417
395
  }
418
- // Server-Side Rendering - convert VNode to HTML string
419
- renderToString(vNode, options = {}) {
420
- const { pretty = false, indent = 0 } = options;
421
- const indentStr = pretty ? " ".repeat(indent) : "";
422
- const newLine = pretty ? "\n" : "";
423
- let resolvedVNode = this.resolveStateValue(vNode);
424
- resolvedVNode = this.unwrapReactive(resolvedVNode);
425
- if (Array.isArray(resolvedVNode)) {
426
- return resolvedVNode.map((child) => this.renderToString(child, options)).join("");
427
- }
428
- if (typeof resolvedVNode !== "object" || resolvedVNode === null) {
429
- if (resolvedVNode === null || resolvedVNode === void 0 || resolvedVNode === false) {
430
- return "";
396
+ return children.map((child) => unwrapReactive(child));
397
+ }
398
+ function escapeHtml(text) {
399
+ const htmlEscapes = {
400
+ "&": "&amp;",
401
+ "<": "&lt;",
402
+ ">": "&gt;",
403
+ '"': "&quot;",
404
+ "'": "&#x27;"
405
+ };
406
+ return text.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
407
+ }
408
+ function isSelfClosingTag(tagName) {
409
+ return SELF_CLOSING_TAGS.has(tagName.toLowerCase());
410
+ }
411
+ function styleToString(style) {
412
+ if (typeof style === "string") {
413
+ return style;
414
+ }
415
+ if (typeof style === "object" && style !== null) {
416
+ const styles = [];
417
+ for (const key in style) {
418
+ const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
419
+ styles.push(`${cssKey}:${style[key]}`);
420
+ }
421
+ return styles.join(";");
422
+ }
423
+ return "";
424
+ }
425
+ function propsToAttributes(props, tagName) {
426
+ const attrs = [];
427
+ for (const key in props) {
428
+ if (key === "children" || key === "dangerouslySetInnerHTML" || key === "ref" || tagName === "textarea" && key === "value") {
429
+ continue;
430
+ }
431
+ let value = props[key];
432
+ value = resolveStateValue(value);
433
+ if (value == null || value === false) continue;
434
+ if (key.startsWith("on") && typeof value === "function") {
435
+ continue;
436
+ }
437
+ if (key === "className" || key === "class") {
438
+ const className = Array.isArray(value) ? value.join(" ") : value;
439
+ if (className) {
440
+ attrs.push(`class="${escapeHtml(String(className))}"`);
431
441
  }
432
- return this.escapeHtml(String(resolvedVNode));
442
+ continue;
433
443
  }
434
- const { tagName, props, children } = resolvedVNode;
435
- const textareaValue = resolveTextareaValue(tagName, props);
436
- const isSelfClosing = this.isSelfClosingTag(tagName);
437
- let html = `${indentStr}<${tagName}`;
438
- const attrs = this.propsToAttributes(props, tagName);
439
- if (attrs) {
440
- html += ` ${attrs}`;
444
+ if (key === "style") {
445
+ const styleStr = styleToString(value);
446
+ if (styleStr) {
447
+ attrs.push(`style="${escapeHtml(styleStr)}"`);
448
+ }
449
+ continue;
441
450
  }
442
- if (isSelfClosing) {
443
- html += ` />${newLine}`;
444
- return html;
451
+ if (value === true) {
452
+ attrs.push(key);
453
+ continue;
445
454
  }
446
- html += ">";
447
- if (textareaValue !== void 0) {
448
- html += this.escapeHtml(textareaValue);
449
- html += `</${tagName}>${newLine}`;
450
- return html;
451
- }
452
- if (props.dangerouslySetInnerHTML) {
453
- html += props.dangerouslySetInnerHTML.__html;
454
- html += `</${tagName}>${newLine}`;
455
- return html;
456
- }
457
- const isRawText = tagName === "script" || tagName === "style";
458
- if (children && children.length > 0) {
459
- const resolvedChildren = children.map((c) => {
460
- const resolved = this.resolveStateValue(c);
461
- return this.unwrapReactive(resolved);
462
- });
463
- const hasComplexChildren = resolvedChildren.some(
464
- (c) => typeof c === "object" && c !== null && !Array.isArray(c) && "tagName" in c
465
- );
466
- if (pretty && hasComplexChildren) {
467
- html += newLine;
468
- for (const child of resolvedChildren) {
469
- if (shouldSkipChild(child)) continue;
470
- if (Array.isArray(child)) {
471
- for (const c of child) {
472
- if (!shouldSkipChild(c)) {
473
- html += isRawText && typeof c === "string" ? c : this.renderToString(c, { pretty, indent: indent + 1 });
474
- }
455
+ attrs.push(`${key}="${escapeHtml(String(value))}"`);
456
+ }
457
+ return attrs.join(" ");
458
+ }
459
+ function renderToString(vNode, options = {}) {
460
+ const { pretty = false, indent = 0 } = options;
461
+ const indentStr = pretty ? " ".repeat(indent) : "";
462
+ const newLine = pretty ? "\n" : "";
463
+ let resolvedVNode = resolveStateValue(vNode);
464
+ resolvedVNode = unwrapReactive(resolvedVNode);
465
+ if (Array.isArray(resolvedVNode)) {
466
+ return resolvedVNode.map((child) => renderToString(child, options)).join("");
467
+ }
468
+ if (typeof resolvedVNode !== "object" || resolvedVNode === null) {
469
+ if (resolvedVNode === null || resolvedVNode === void 0 || resolvedVNode === false) {
470
+ return "";
471
+ }
472
+ return escapeHtml(String(resolvedVNode));
473
+ }
474
+ const { tagName, props, children } = resolvedVNode;
475
+ const textareaValue = resolveTextareaValue(tagName, props);
476
+ const selfClosing = isSelfClosingTag(tagName);
477
+ let html = `${indentStr}<${tagName}`;
478
+ const attrs = propsToAttributes(props, tagName);
479
+ if (attrs) {
480
+ html += ` ${attrs}`;
481
+ }
482
+ if (selfClosing) {
483
+ html += ` />${newLine}`;
484
+ return html;
485
+ }
486
+ html += ">";
487
+ if (textareaValue !== void 0) {
488
+ html += escapeHtml(textareaValue);
489
+ html += `</${tagName}>${newLine}`;
490
+ return html;
491
+ }
492
+ if (props.dangerouslySetInnerHTML) {
493
+ html += props.dangerouslySetInnerHTML.__html;
494
+ html += `</${tagName}>${newLine}`;
495
+ return html;
496
+ }
497
+ const isRawText = tagName === "script" || tagName === "style";
498
+ if (children && children.length > 0) {
499
+ const resolvedChildren = children.map((child) => unwrapReactive(resolveStateValue(child)));
500
+ const hasComplexChildren = resolvedChildren.some(
501
+ (child) => typeof child === "object" && child !== null && !Array.isArray(child) && "tagName" in child
502
+ );
503
+ if (pretty && hasComplexChildren) {
504
+ html += newLine;
505
+ for (const child of resolvedChildren) {
506
+ if (shouldSkipChild(child)) continue;
507
+ if (Array.isArray(child)) {
508
+ for (const nestedChild of child) {
509
+ if (!shouldSkipChild(nestedChild)) {
510
+ html += isRawText && typeof nestedChild === "string" ? nestedChild : renderToString(nestedChild, { pretty, indent: indent + 1 });
475
511
  }
476
- } else {
477
- html += isRawText && typeof child === "string" ? child : this.renderToString(child, { pretty, indent: indent + 1 });
478
512
  }
513
+ } else {
514
+ html += isRawText && typeof child === "string" ? child : renderToString(child, { pretty, indent: indent + 1 });
479
515
  }
480
- html += indentStr;
481
- } else {
482
- for (const child of resolvedChildren) {
483
- if (shouldSkipChild(child)) continue;
484
- if (Array.isArray(child)) {
485
- for (const c of child) {
486
- if (!shouldSkipChild(c)) {
487
- html += isRawText && typeof c === "string" ? c : this.renderToString(c, { pretty: false, indent: 0 });
488
- }
516
+ }
517
+ html += indentStr;
518
+ } else {
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: false, indent: 0 });
489
525
  }
490
- } else {
491
- html += isRawText && typeof child === "string" ? child : this.renderToString(child, { pretty: false, indent: 0 });
492
526
  }
527
+ } else {
528
+ html += isRawText && typeof child === "string" ? child : renderToString(child, { pretty: false, indent: 0 });
493
529
  }
494
530
  }
495
531
  }
496
- html += `</${tagName}>${newLine}`;
497
- return html;
498
532
  }
499
- resolveStateValue(value) {
500
- if (value && typeof value === "object" && "value" in value && "subscribe" in value) {
501
- return value.value;
533
+ html += `</${tagName}>${newLine}`;
534
+ return html;
535
+ }
536
+ function renderToHTMLDocument(vNode, options = {}) {
537
+ const {
538
+ title = "",
539
+ meta = [],
540
+ links = [],
541
+ scripts = [],
542
+ styles = [],
543
+ lang = "en",
544
+ head = "",
545
+ bodyAttrs = {},
546
+ pretty = false
547
+ } = options;
548
+ const nl = pretty ? "\n" : "";
549
+ const indent = pretty ? " " : "";
550
+ const indent2 = pretty ? " " : "";
551
+ 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}`;
552
+ if (title) {
553
+ html += `${indent2}<title>${escapeHtml(title)}</title>${nl}`;
554
+ }
555
+ for (const metaAttrs of meta) {
556
+ html += `${indent2}<meta`;
557
+ for (const key in metaAttrs) {
558
+ html += ` ${key}="${escapeHtml(metaAttrs[key])}"`;
502
559
  }
503
- return value;
560
+ html += `>${nl}`;
504
561
  }
505
- isReactiveWrapper(vNode) {
506
- if (!vNode || typeof vNode !== "object" || !vNode.tagName) {
507
- return false;
562
+ for (const linkAttrs of links) {
563
+ html += `${indent2}<link`;
564
+ for (const key in linkAttrs) {
565
+ html += ` ${key}="${escapeHtml(linkAttrs[key])}"`;
508
566
  }
509
- return vNode.tagName === "span" && vNode.props?.id && typeof vNode.props.id === "string" && vNode.props.id.match(/^r[a-z0-9]{9}$/);
567
+ html += `>${nl}`;
510
568
  }
511
- unwrapReactive(vNode) {
512
- if (!this.isReactiveWrapper(vNode)) {
513
- return vNode;
569
+ for (const style of styles) {
570
+ if (style.href) {
571
+ html += `${indent2}<link rel="stylesheet" href="${escapeHtml(style.href)}">${nl}`;
572
+ } else if (style.content) {
573
+ html += `${indent2}<style>${style.content}</style>${nl}`;
514
574
  }
515
- const children = vNode.children;
516
- if (!children || children.length === 0) {
517
- return "";
575
+ }
576
+ if (head) {
577
+ html += head + nl;
578
+ }
579
+ html += `${indent}</head>${nl}${indent}<body`;
580
+ for (const key in bodyAttrs) {
581
+ html += ` ${key}="${escapeHtml(bodyAttrs[key])}"`;
582
+ }
583
+ html += `>${nl}`;
584
+ html += renderToString(vNode, { pretty, indent: 2 });
585
+ for (const script of scripts) {
586
+ html += `${indent2}<script`;
587
+ if (script.type) {
588
+ html += ` type="${escapeHtml(script.type)}"`;
518
589
  }
519
- if (children.length === 1) {
520
- const child = children[0];
521
- if (child && typeof child === "object" && child.tagName === "span") {
522
- const props = child.props;
523
- const hasNoProps = !props || Object.keys(props).length === 0;
524
- const hasSingleStringChild = child.children && child.children.length === 1 && typeof child.children[0] === "string";
525
- if (hasNoProps && hasSingleStringChild) {
526
- return child.children[0];
527
- }
528
- }
529
- return this.unwrapReactive(child);
590
+ if (script.async) {
591
+ html += " async";
592
+ }
593
+ if (script.defer) {
594
+ html += " defer";
595
+ }
596
+ if (script.src) {
597
+ html += ` src="${escapeHtml(script.src)}"></script>${nl}`;
598
+ } else if (script.content) {
599
+ html += `>${script.content}</script>${nl}`;
600
+ } else {
601
+ html += `></script>${nl}`;
530
602
  }
531
- return children.map((c) => this.unwrapReactive(c));
532
603
  }
533
- escapeHtml(text) {
534
- const htmlEscapes = {
535
- "&": "&amp;",
536
- "<": "&lt;",
537
- ">": "&gt;",
538
- '"': "&quot;",
539
- "'": "&#x27;"
540
- };
541
- return text.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
542
- }
543
- isSelfClosingTag(tagName) {
544
- const selfClosingTags = /* @__PURE__ */ new Set([
545
- "area",
546
- "base",
547
- "br",
548
- "col",
549
- "embed",
550
- "hr",
551
- "img",
552
- "input",
553
- "link",
554
- "meta",
555
- "param",
556
- "source",
557
- "track",
558
- "wbr"
559
- ]);
560
- return selfClosingTags.has(tagName.toLowerCase());
561
- }
562
- propsToAttributes(props, tagName) {
563
- const attrs = [];
564
- for (const key in props) {
565
- if (key === "children" || key === "dangerouslySetInnerHTML" || key === "ref" || tagName === "textarea" && key === "value") {
566
- continue;
567
- }
568
- let value = props[key];
569
- value = this.resolveStateValue(value);
570
- if (value == null || value === false) continue;
571
- if (key.startsWith("on") && typeof value === "function") {
572
- continue;
573
- }
574
- if (key === "className" || key === "class") {
575
- const className = Array.isArray(value) ? value.join(" ") : value;
576
- if (className) {
577
- attrs.push(`class="${this.escapeHtml(String(className))}"`);
578
- }
579
- continue;
580
- }
581
- if (key === "style") {
582
- const styleStr = this.styleToString(value);
583
- if (styleStr) {
584
- attrs.push(`style="${this.escapeHtml(styleStr)}"`);
604
+ html += `${indent}</body>${nl}</html>`;
605
+ return html;
606
+ }
607
+
608
+ // src/client/dom/json.ts
609
+ function jsonToVNode(json, reactiveNodes) {
610
+ if (isState(json)) {
611
+ return createReactiveChild(json, reactiveNodes, (value) => value);
612
+ }
613
+ if (isPrimitiveJson(json)) {
614
+ return json;
615
+ }
616
+ const { tag, attributes = {}, children } = json;
617
+ const props = {};
618
+ for (const key in attributes) {
619
+ const value = attributes[key];
620
+ if (key === "class") {
621
+ props.className = isState(value) ? value.value : value;
622
+ } else {
623
+ props[key] = isState(value) ? value.value : value;
624
+ }
625
+ }
626
+ const childrenArray = [];
627
+ if (children != null) {
628
+ if (Array.isArray(children)) {
629
+ for (const child of children) {
630
+ if (isState(child)) {
631
+ childrenArray.push(createReactiveChild(child, reactiveNodes, (value) => value));
632
+ } else {
633
+ const converted = jsonToVNode(child, reactiveNodes);
634
+ if (converted != null && converted !== false) {
635
+ childrenArray.push(converted);
636
+ }
585
637
  }
586
- continue;
587
638
  }
588
- if (value === true) {
589
- attrs.push(key);
590
- continue;
639
+ } else if (isState(children)) {
640
+ childrenArray.push(createReactiveChild(children, reactiveNodes, (value) => value));
641
+ } else if (typeof children === "object" && children !== null && "tag" in children) {
642
+ const converted = jsonToVNode(children, reactiveNodes);
643
+ if (converted != null && converted !== false) {
644
+ childrenArray.push(converted);
591
645
  }
592
- attrs.push(`${key}="${this.escapeHtml(String(value))}"`);
646
+ } else {
647
+ childrenArray.push(children);
593
648
  }
594
- return attrs.join(" ");
595
649
  }
596
- styleToString(style) {
597
- if (typeof style === "string") {
598
- return style;
599
- }
600
- if (typeof style === "object" && style !== null) {
601
- const styles = [];
602
- for (const key in style) {
603
- const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
604
- styles.push(`${cssKey}:${style[key]}`);
650
+ return { tagName: tag, props, children: childrenArray };
651
+ }
652
+ function vNodeJsonToVNode(json, reactiveNodes) {
653
+ if (isState(json)) {
654
+ return createReactiveChild(json, reactiveNodes, (value) => value);
655
+ }
656
+ if (isPrimitiveJson(json)) {
657
+ return json;
658
+ }
659
+ const { tagName, props = {}, children = [] } = json;
660
+ const resolvedProps = {};
661
+ for (const key in props) {
662
+ const value = props[key];
663
+ resolvedProps[key] = isState(value) ? value.value : value;
664
+ }
665
+ const childrenArray = [];
666
+ for (const child of children) {
667
+ if (isState(child)) {
668
+ childrenArray.push(createReactiveChild(child, reactiveNodes, (value) => value));
669
+ } else {
670
+ const converted = vNodeJsonToVNode(child, reactiveNodes);
671
+ if (converted != null && converted !== false) {
672
+ childrenArray.push(converted);
605
673
  }
606
- return styles.join(";");
607
674
  }
608
- return "";
609
675
  }
610
- isState(value) {
611
- return value && typeof value === "object" && "value" in value && "subscribe" in value && typeof value.subscribe === "function";
612
- }
613
- createReactiveChild(state, renderFn) {
614
- const currentValue = renderFn(state.value);
615
- if (typeof window !== "undefined" && typeof document !== "undefined") {
616
- const entry = { node: null, renderFn };
617
- this.reactiveNodes.set(state, entry);
618
- state.subscribe(() => {
619
- if (entry.node && entry.node.parentNode) {
620
- const newValue = renderFn(state.value);
621
- entry.node.textContent = String(newValue ?? "");
622
- }
623
- });
624
- }
625
- return currentValue;
676
+ return { tagName, props: resolvedProps, children: childrenArray };
677
+ }
678
+ function renderJson(rootElement, json, reactiveNodes) {
679
+ const vNode = jsonToVNode(json, reactiveNodes);
680
+ if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
681
+ throw new Error("Invalid JSON structure");
626
682
  }
627
- jsonToVNode(json) {
628
- if (this.isState(json)) {
629
- return this.createReactiveChild(json, (v) => v);
630
- }
631
- if (isPrimitiveJson(json)) {
632
- return json;
633
- }
634
- const { tag, attributes = {}, children } = json;
635
- const props = {};
636
- for (const key in attributes) {
637
- const value = attributes[key];
638
- if (key === "class") {
639
- props.className = this.isState(value) ? value.value : value;
640
- } else {
641
- props[key] = this.isState(value) ? value.value : value;
683
+ return render(rootElement, vNode);
684
+ }
685
+ function renderVNode(rootElement, json, reactiveNodes) {
686
+ const vNode = vNodeJsonToVNode(json, reactiveNodes);
687
+ if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
688
+ throw new Error("Invalid VNode JSON structure");
689
+ }
690
+ return render(rootElement, vNode);
691
+ }
692
+ function renderJsonToString(json, reactiveNodes, options = {}) {
693
+ const vNode = jsonToVNode(json, reactiveNodes);
694
+ return renderToString(vNode, options);
695
+ }
696
+ function renderVNodeToString(json, reactiveNodes, options = {}) {
697
+ const vNode = vNodeJsonToVNode(json, reactiveNodes);
698
+ return renderToString(vNode, options);
699
+ }
700
+
701
+ // src/client/dom/state-utils.ts
702
+ function createState(initialValue, options = {}) {
703
+ let value = initialValue;
704
+ const listeners = /* @__PURE__ */ new Set();
705
+ let updateTimer = null;
706
+ const { throttle = 0, deep = false } = options;
707
+ const notify = () => listeners.forEach((listener) => listener(value));
708
+ const scheduleUpdate = () => {
709
+ if (throttle > 0) {
710
+ if (!updateTimer) {
711
+ updateTimer = setTimeout(() => {
712
+ updateTimer = null;
713
+ notify();
714
+ }, throttle);
642
715
  }
716
+ } else {
717
+ notify();
643
718
  }
644
- const childrenArray = [];
645
- if (children != null) {
646
- if (Array.isArray(children)) {
647
- for (const child of children) {
648
- if (this.isState(child)) {
649
- childrenArray.push(this.createReactiveChild(child, (v) => v));
650
- } else {
651
- const converted = this.jsonToVNode(child);
652
- if (converted != null && converted !== false) {
653
- childrenArray.push(converted);
654
- }
655
- }
656
- }
657
- } else if (this.isState(children)) {
658
- childrenArray.push(this.createReactiveChild(children, (v) => v));
659
- } else if (typeof children === "object" && "tag" in children) {
660
- const converted = this.jsonToVNode(children);
661
- if (converted != null && converted !== false) {
662
- childrenArray.push(converted);
663
- }
664
- } else {
665
- childrenArray.push(children);
719
+ };
720
+ return {
721
+ get value() {
722
+ return value;
723
+ },
724
+ set value(newValue) {
725
+ const changed = deep ? JSON.stringify(value) !== JSON.stringify(newValue) : value !== newValue;
726
+ if (changed) {
727
+ value = newValue;
728
+ scheduleUpdate();
729
+ }
730
+ },
731
+ subscribe(fn) {
732
+ listeners.add(fn);
733
+ return () => listeners.delete(fn);
734
+ },
735
+ destroy() {
736
+ listeners.clear();
737
+ if (updateTimer) {
738
+ clearTimeout(updateTimer);
666
739
  }
667
740
  }
668
- return { tagName: tag, props, children: childrenArray };
741
+ };
742
+ }
743
+ function computed(states, computeFn) {
744
+ const values = states.map((state) => state.value);
745
+ const result = createState(computeFn(...values));
746
+ states.forEach((state, index) => {
747
+ state.subscribe((newValue) => {
748
+ values[index] = newValue;
749
+ result.value = computeFn(...values);
750
+ });
751
+ });
752
+ return result;
753
+ }
754
+ function effect(stateFn) {
755
+ stateFn();
756
+ }
757
+ function createVirtualList(container, items, renderItem, itemHeight = 50, bufferSize = 5) {
758
+ const viewportHeight = container.clientHeight;
759
+ const totalHeight = items.length * itemHeight;
760
+ let scrollTop = 0;
761
+ const getVisibleRange = () => {
762
+ const start = Math.max(0, Math.floor(scrollTop / itemHeight) - bufferSize);
763
+ const end = Math.min(items.length, Math.ceil((scrollTop + viewportHeight) / itemHeight) + bufferSize);
764
+ return { start, end };
765
+ };
766
+ const render3 = () => {
767
+ const { start, end } = getVisibleRange();
768
+ const wrapper = document.createElement("div");
769
+ wrapper.style.cssText = `height:${totalHeight}px;position:relative`;
770
+ for (let i = start; i < end; i++) {
771
+ const itemEl = document.createElement("div");
772
+ itemEl.style.cssText = `position:absolute;top:${i * itemHeight}px;height:${itemHeight}px;width:100%`;
773
+ renderToDOM(renderItem(items[i], i), itemEl);
774
+ wrapper.appendChild(itemEl);
775
+ }
776
+ container.innerHTML = "";
777
+ container.appendChild(wrapper);
778
+ };
779
+ const scrollHandler = () => {
780
+ scrollTop = container.scrollTop;
781
+ requestAnimationFrame(render3);
782
+ };
783
+ container.addEventListener("scroll", scrollHandler);
784
+ render3();
785
+ return {
786
+ render: render3,
787
+ destroy: () => {
788
+ container.removeEventListener("scroll", scrollHandler);
789
+ container.innerHTML = "";
790
+ }
791
+ };
792
+ }
793
+ function lazy(loadFn) {
794
+ let component = null;
795
+ let loading = false;
796
+ return async (...args) => {
797
+ if (!component && !loading) {
798
+ loading = true;
799
+ component = await loadFn();
800
+ loading = false;
801
+ }
802
+ return component ? component(...args) : { tagName: "div", props: { class: "loading" }, children: ["Loading..."] };
803
+ };
804
+ }
805
+
806
+ // src/client/dom/index.ts
807
+ var DomNode = class {
808
+ constructor() {
809
+ this.elementCache = /* @__PURE__ */ new WeakMap();
810
+ this.reactiveNodes = /* @__PURE__ */ new Map();
811
+ }
812
+ createElement(tagName, props = {}, children = []) {
813
+ return { tagName, props, children };
814
+ }
815
+ renderToDOM(vNode, parent) {
816
+ return renderToDOM(vNode, parent);
817
+ }
818
+ render(rootElement, vNode) {
819
+ return render(rootElement, vNode);
820
+ }
821
+ batchRender(rootElement, vNodes) {
822
+ return batchRender(rootElement, vNodes);
823
+ }
824
+ renderChunked(rootElement, vNodes, chunkSize = 5e3, onProgress) {
825
+ return renderChunked(rootElement, vNodes, chunkSize, onProgress);
826
+ }
827
+ renderToHead(...vNodes) {
828
+ return renderToHead(...vNodes);
829
+ }
830
+ addStyle(cssText) {
831
+ return addStyle(cssText);
832
+ }
833
+ addMeta(attrs) {
834
+ return addMeta(attrs);
835
+ }
836
+ addLink(attrs) {
837
+ return addLink(attrs);
838
+ }
839
+ setTitle(text) {
840
+ return setTitle(text);
841
+ }
842
+ // Reactive State Management
843
+ createState(initialValue, options = {}) {
844
+ return createState(initialValue, options);
845
+ }
846
+ computed(states, computeFn) {
847
+ return computed(states, computeFn);
848
+ }
849
+ effect(stateFn) {
850
+ effect(stateFn);
851
+ }
852
+ // Virtual scrolling helper for large lists
853
+ createVirtualList(container, items, renderItem, itemHeight = 50, bufferSize = 5) {
854
+ return createVirtualList(container, items, renderItem, itemHeight, bufferSize);
855
+ }
856
+ // Lazy load components
857
+ lazy(loadFn) {
858
+ return lazy(loadFn);
859
+ }
860
+ // Memory management - cleanup unused elements
861
+ cleanupUnusedElements(root) {
862
+ return cleanupUnusedElements(root, this.elementCache);
863
+ }
864
+ // Server-Side Rendering - convert VNode to HTML string
865
+ renderToString(vNode, options = {}) {
866
+ return renderToString(vNode, options);
867
+ }
868
+ jsonToVNode(json) {
869
+ return jsonToVNode(json, this.reactiveNodes);
669
870
  }
670
871
  vNodeJsonToVNode(json) {
671
- if (this.isState(json)) {
672
- return this.createReactiveChild(json, (v) => v);
673
- }
674
- if (isPrimitiveJson(json)) {
675
- return json;
676
- }
677
- const { tagName, props = {}, children = [] } = json;
678
- const resolvedProps = {};
679
- for (const key in props) {
680
- const value = props[key];
681
- resolvedProps[key] = this.isState(value) ? value.value : value;
682
- }
683
- const childrenArray = [];
684
- for (const child of children) {
685
- if (this.isState(child)) {
686
- childrenArray.push(this.createReactiveChild(child, (v) => v));
687
- } else {
688
- const converted = this.vNodeJsonToVNode(child);
689
- if (converted != null && converted !== false) {
690
- childrenArray.push(converted);
691
- }
692
- }
693
- }
694
- return { tagName, props: resolvedProps, children: childrenArray };
872
+ return vNodeJsonToVNode(json, this.reactiveNodes);
695
873
  }
696
874
  renderJson(rootElement, json) {
697
- const vNode = this.jsonToVNode(json);
698
- if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
699
- throw new Error("Invalid JSON structure");
700
- }
701
- return this.render(rootElement, vNode);
875
+ return renderJson(rootElement, json, this.reactiveNodes);
702
876
  }
703
877
  renderVNode(rootElement, json) {
704
- const vNode = this.vNodeJsonToVNode(json);
705
- if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
706
- throw new Error("Invalid VNode JSON structure");
707
- }
708
- return this.render(rootElement, vNode);
878
+ return renderVNode(rootElement, json, this.reactiveNodes);
709
879
  }
710
880
  renderJsonToString(json, options = {}) {
711
- const vNode = this.jsonToVNode(json);
712
- return this.renderToString(vNode, options);
881
+ return renderJsonToString(json, this.reactiveNodes, options);
713
882
  }
714
883
  renderVNodeToString(json, options = {}) {
715
- const vNode = this.vNodeJsonToVNode(json);
716
- return this.renderToString(vNode, options);
884
+ return renderVNodeToString(json, this.reactiveNodes, options);
717
885
  }
718
886
  // Generate complete HTML document as string (for SSR)
719
887
  renderToHTMLDocument(vNode, options = {}) {
720
- const { title = "", meta = [], links = [], scripts = [], styles = [], lang = "en", head = "", bodyAttrs = {}, pretty = false } = options;
721
- const nl = pretty ? "\n" : "";
722
- const indent = pretty ? " " : "";
723
- const indent2 = pretty ? " " : "";
724
- 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}`;
725
- if (title) html += `${indent2}<title>${this.escapeHtml(title)}</title>${nl}`;
726
- for (const m of meta) {
727
- html += `${indent2}<meta`;
728
- for (const k in m) html += ` ${k}="${this.escapeHtml(m[k])}"`;
729
- html += `>${nl}`;
730
- }
731
- for (const l of links) {
732
- html += `${indent2}<link`;
733
- for (const k in l) html += ` ${k}="${this.escapeHtml(l[k])}"`;
734
- html += `>${nl}`;
735
- }
736
- for (const s of styles) {
737
- if (s.href) {
738
- html += `${indent2}<link rel="stylesheet" href="${this.escapeHtml(s.href)}">${nl}`;
739
- } else if (s.content) {
740
- html += `${indent2}<style>${s.content}</style>${nl}`;
741
- }
742
- }
743
- if (head) html += head + nl;
744
- html += `${indent}</head>${nl}${indent}<body`;
745
- for (const k in bodyAttrs) html += ` ${k}="${this.escapeHtml(bodyAttrs[k])}"`;
746
- html += `>${nl}`;
747
- html += this.renderToString(vNode, { pretty, indent: 2 });
748
- for (const script of scripts) {
749
- html += `${indent2}<script`;
750
- if (script.type) html += ` type="${this.escapeHtml(script.type)}"`;
751
- if (script.async) html += ` async`;
752
- if (script.defer) html += ` defer`;
753
- if (script.src) {
754
- html += ` src="${this.escapeHtml(script.src)}"></script>${nl}`;
755
- } else if (script.content) {
756
- html += `>${script.content}</script>${nl}`;
757
- } else {
758
- html += `></script>${nl}`;
759
- }
760
- }
761
- html += `${indent}</body>${nl}</html>`;
762
- return html;
888
+ return renderToHTMLDocument(vNode, options);
763
889
  }
764
890
  // Expose elementCache for reactive updates
765
891
  getElementCache() {
@@ -767,9 +893,9 @@ var DomNode = class {
767
893
  }
768
894
  };
769
895
  var dom = new DomNode();
770
- var render = dom.render.bind(dom);
771
- var renderToString = dom.renderToString.bind(dom);
772
- var mount = render;
896
+ var render2 = dom.render.bind(dom);
897
+ var renderToString2 = dom.renderToString.bind(dom);
898
+ var mount = render2;
773
899
  // Annotate the CommonJS export names for ESM import in node:
774
900
  0 && (module.exports = {
775
901
  DomNode,