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