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