elit 3.6.5 → 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 (154) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/README.md +6 -0
  4. package/dist/build.cjs +421 -331
  5. package/dist/build.d.ts +1 -16
  6. package/dist/build.js +420 -330
  7. package/dist/build.mjs +420 -330
  8. package/dist/chokidar.cjs +219 -182
  9. package/dist/chokidar.d.ts +25 -10
  10. package/dist/chokidar.js +217 -182
  11. package/dist/chokidar.mjs +218 -183
  12. package/dist/cli.cjs +21608 -20241
  13. package/dist/cli.d.ts +19 -37
  14. package/dist/cli.mjs +21262 -19910
  15. package/dist/config.cjs +357 -350
  16. package/dist/config.d.ts +19 -240
  17. package/dist/config.js +520 -515
  18. package/dist/config.mjs +346 -341
  19. package/dist/contracts-BeW9k0yZ.d.ts +54 -0
  20. package/dist/contracts-D7KIS-TK.d.ts +36 -0
  21. package/dist/coverage.cjs +448 -485
  22. package/dist/coverage.d.ts +13 -59
  23. package/dist/coverage.js +447 -484
  24. package/dist/coverage.mjs +447 -484
  25. package/dist/database.cjs +819 -828
  26. package/dist/database.d.ts +8 -24
  27. package/dist/database.js +818 -829
  28. package/dist/database.mjs +818 -829
  29. package/dist/desktop-auto-render.cjs +1700 -1522
  30. package/dist/desktop-auto-render.d.ts +4 -9
  31. package/dist/desktop-auto-render.js +1695 -1517
  32. package/dist/desktop-auto-render.mjs +1696 -1518
  33. package/dist/desktop.cjs +3 -1
  34. package/dist/desktop.d.ts +4 -1
  35. package/dist/desktop.js +1 -1
  36. package/dist/desktop.mjs +1 -1
  37. package/dist/dev-build.cjs +830 -0
  38. package/dist/dev-build.d.ts +53 -0
  39. package/dist/dev-build.js +3318 -0
  40. package/dist/dev-build.mjs +797 -0
  41. package/dist/dom.cjs +717 -590
  42. package/dist/dom.d.ts +2 -15
  43. package/dist/dom.js +714 -587
  44. package/dist/dom.mjs +716 -589
  45. package/dist/el.cjs +62 -52
  46. package/dist/el.d.ts +5 -10
  47. package/dist/el.js +60 -52
  48. package/dist/el.mjs +60 -52
  49. package/dist/fs.cjs +72 -63
  50. package/dist/fs.d.ts +22 -19
  51. package/dist/fs.js +71 -62
  52. package/dist/fs.mjs +71 -62
  53. package/dist/hmr.cjs +40 -14
  54. package/dist/hmr.d.ts +11 -23
  55. package/dist/hmr.js +38 -14
  56. package/dist/hmr.mjs +38 -14
  57. package/dist/http.cjs +251 -99
  58. package/dist/http.d.ts +38 -104
  59. package/dist/http.js +249 -99
  60. package/dist/http.mjs +249 -99
  61. package/dist/https.cjs +524 -228
  62. package/dist/https.d.ts +44 -36
  63. package/dist/https.js +520 -226
  64. package/dist/https.mjs +522 -228
  65. package/dist/index.cjs +7502 -7690
  66. package/dist/index.d.ts +8 -3
  67. package/dist/index.js +7486 -7676
  68. package/dist/index.mjs +7497 -7686
  69. package/dist/mime-types.cjs +10 -4
  70. package/dist/mime-types.d.ts +8 -11
  71. package/dist/mime-types.js +9 -3
  72. package/dist/mime-types.mjs +9 -3
  73. package/dist/native.cjs +8616 -8869
  74. package/dist/native.d.ts +7 -8
  75. package/dist/native.js +8682 -8935
  76. package/dist/native.mjs +8615 -8868
  77. package/dist/path.cjs +83 -77
  78. package/dist/path.d.ts +29 -29
  79. package/dist/path.js +82 -76
  80. package/dist/path.mjs +82 -76
  81. package/dist/pm.cjs +3300 -0
  82. package/dist/pm.d.ts +256 -0
  83. package/dist/pm.js +5638 -0
  84. package/dist/pm.mjs +3196 -0
  85. package/dist/preview-build.cjs +712 -0
  86. package/dist/preview-build.d.ts +59 -0
  87. package/dist/preview-build.js +3194 -0
  88. package/dist/preview-build.mjs +676 -0
  89. package/dist/render-context.cjs +13 -2
  90. package/dist/render-context.d.ts +9 -31
  91. package/dist/render-context.js +11 -2
  92. package/dist/render-context.mjs +11 -2
  93. package/dist/router.cjs +787 -645
  94. package/dist/router.d.ts +8 -12
  95. package/dist/router.js +786 -644
  96. package/dist/router.mjs +786 -644
  97. package/dist/runtime.cjs +1 -1
  98. package/dist/runtime.js +1 -1
  99. package/dist/runtime.mjs +1 -1
  100. package/dist/server.cjs +3315 -2603
  101. package/dist/server.d.ts +49 -4
  102. package/dist/server.js +7611 -2834
  103. package/dist/server.mjs +3317 -2607
  104. package/dist/smtp-server.cjs +128 -0
  105. package/dist/smtp-server.d.ts +27 -0
  106. package/dist/smtp-server.js +4199 -0
  107. package/dist/smtp-server.mjs +100 -0
  108. package/dist/state-DvEkDehk.d.ts +195 -0
  109. package/dist/state.cjs +768 -658
  110. package/dist/state.d.ts +11 -69
  111. package/dist/state.js +760 -650
  112. package/dist/state.mjs +767 -657
  113. package/dist/style.cjs +1011 -968
  114. package/dist/style.d.ts +13 -127
  115. package/dist/style.js +1009 -970
  116. package/dist/style.mjs +1011 -971
  117. package/dist/test-reporter.cjs +332 -316
  118. package/dist/test-reporter.d.ts +28 -33
  119. package/dist/test-reporter.js +328 -312
  120. package/dist/test-reporter.mjs +328 -312
  121. package/dist/test-runtime.cjs +927 -968
  122. package/dist/test-runtime.d.ts +24 -99
  123. package/dist/test-runtime.js +922 -965
  124. package/dist/test-runtime.mjs +922 -965
  125. package/dist/test.cjs +4428 -4273
  126. package/dist/test.d.ts +2 -8
  127. package/dist/test.js +4307 -4154
  128. package/dist/test.mjs +4419 -4267
  129. package/dist/types-BONVzPtp.d.ts +59 -0
  130. package/dist/types-BR4wMiVx.d.ts +32 -0
  131. package/dist/types-C4gKykuG.d.ts +23 -0
  132. package/dist/types-CIhpN1-K.d.ts +64 -0
  133. package/dist/types-Ckj8md_j.d.ts +84 -0
  134. package/dist/types-CpjQTAkX.d.ts +24 -0
  135. package/dist/types-D0LjrYjS.d.ts +14 -0
  136. package/dist/types-DAisuVr5.d.ts +75 -0
  137. package/dist/types-tJn88E1N.d.ts +242 -0
  138. package/dist/types.d.ts +71 -226
  139. package/dist/universal.cjs +1 -1
  140. package/dist/universal.d.ts +1 -5
  141. package/dist/universal.js +1 -1
  142. package/dist/universal.mjs +1 -1
  143. package/dist/websocket-XfyK23zD.d.ts +119 -0
  144. package/dist/ws.cjs +129 -108
  145. package/dist/ws.d.ts +21 -131
  146. package/dist/ws.js +128 -109
  147. package/dist/ws.mjs +128 -109
  148. package/dist/wss.cjs +757 -479
  149. package/dist/wss.d.ts +31 -28
  150. package/dist/wss.js +755 -479
  151. package/dist/wss.mjs +758 -482
  152. package/package.json +16 -1
  153. package/vendor/epaint-0.31.1/src/image.rs +418 -0
  154. package/dist/server-CcBFc2F5.d.ts +0 -449
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,668 +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
- if (children && children.length > 0) {
472
- const resolvedChildren = children.map((c) => {
473
- const resolved = this.resolveStateValue(c);
474
- return this.unwrapReactive(resolved);
475
- });
476
- const hasComplexChildren = resolvedChildren.some(
477
- (c) => typeof c === "object" && c !== null && !Array.isArray(c) && "tagName" in c
478
- );
479
- if (pretty && hasComplexChildren) {
480
- html += newLine;
481
- for (const child of resolvedChildren) {
482
- if (shouldSkipChild(child)) continue;
483
- if (Array.isArray(child)) {
484
- for (const c of child) {
485
- if (!shouldSkipChild(c)) {
486
- html += this.renderToString(c, { pretty, indent: indent + 1 });
487
- }
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 });
488
525
  }
489
- } else {
490
- html += this.renderToString(child, { pretty, indent: indent + 1 });
491
526
  }
527
+ } else {
528
+ html += isRawText && typeof child === "string" ? child : renderToString(child, { pretty, indent: indent + 1 });
492
529
  }
493
- html += indentStr;
494
- } else {
495
- for (const child of resolvedChildren) {
496
- if (shouldSkipChild(child)) continue;
497
- if (Array.isArray(child)) {
498
- for (const c of child) {
499
- if (!shouldSkipChild(c)) {
500
- html += this.renderToString(c, { pretty: false, indent: 0 });
501
- }
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 });
502
539
  }
503
- } else {
504
- html += this.renderToString(child, { pretty: false, indent: 0 });
505
540
  }
541
+ } else {
542
+ html += isRawText && typeof child === "string" ? child : renderToString(child, { pretty: false, indent: 0 });
506
543
  }
507
544
  }
508
545
  }
509
- html += `</${tagName}>${newLine}`;
510
- return html;
511
546
  }
512
- resolveStateValue(value) {
513
- if (value && typeof value === "object" && "value" in value && "subscribe" in value) {
514
- 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])}"`;
515
573
  }
516
- return value;
574
+ html += `>${nl}`;
517
575
  }
518
- isReactiveWrapper(vNode) {
519
- if (!vNode || typeof vNode !== "object" || !vNode.tagName) {
520
- return false;
576
+ for (const linkAttrs of links) {
577
+ html += `${indent2}<link`;
578
+ for (const key in linkAttrs) {
579
+ html += ` ${key}="${escapeHtml(linkAttrs[key])}"`;
521
580
  }
522
- return vNode.tagName === "span" && vNode.props?.id && typeof vNode.props.id === "string" && vNode.props.id.match(/^r[a-z0-9]{9}$/);
581
+ html += `>${nl}`;
523
582
  }
524
- unwrapReactive(vNode) {
525
- if (!this.isReactiveWrapper(vNode)) {
526
- 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}`;
527
588
  }
528
- const children = vNode.children;
529
- if (!children || children.length === 0) {
530
- 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)}"`;
531
603
  }
532
- if (children.length === 1) {
533
- const child = children[0];
534
- if (child && typeof child === "object" && child.tagName === "span") {
535
- const props = child.props;
536
- const hasNoProps = !props || Object.keys(props).length === 0;
537
- const hasSingleStringChild = child.children && child.children.length === 1 && typeof child.children[0] === "string";
538
- if (hasNoProps && hasSingleStringChild) {
539
- return child.children[0];
540
- }
541
- }
542
- return this.unwrapReactive(child);
604
+ if (script.async) {
605
+ html += " async";
543
606
  }
544
- return children.map((c) => this.unwrapReactive(c));
545
- }
546
- escapeHtml(text2) {
547
- const htmlEscapes = {
548
- "&": "&amp;",
549
- "<": "&lt;",
550
- ">": "&gt;",
551
- '"': "&quot;",
552
- "'": "&#x27;"
553
- };
554
- return text2.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
555
- }
556
- isSelfClosingTag(tagName) {
557
- const selfClosingTags = /* @__PURE__ */ new Set([
558
- "area",
559
- "base",
560
- "br",
561
- "col",
562
- "embed",
563
- "hr",
564
- "img",
565
- "input",
566
- "link",
567
- "meta",
568
- "param",
569
- "source",
570
- "track",
571
- "wbr"
572
- ]);
573
- return selfClosingTags.has(tagName.toLowerCase());
574
- }
575
- propsToAttributes(props, tagName) {
576
- const attrs = [];
577
- for (const key in props) {
578
- if (key === "children" || key === "dangerouslySetInnerHTML" || key === "ref" || tagName === "textarea" && key === "value") {
579
- continue;
580
- }
581
- let value = props[key];
582
- value = this.resolveStateValue(value);
583
- if (value == null || value === false) continue;
584
- if (key.startsWith("on") && typeof value === "function") {
585
- continue;
586
- }
587
- if (key === "className" || key === "class") {
588
- const className = Array.isArray(value) ? value.join(" ") : value;
589
- if (className) {
590
- attrs.push(`class="${this.escapeHtml(String(className))}"`);
591
- }
592
- continue;
593
- }
594
- if (key === "style") {
595
- const styleStr = this.styleToString(value);
596
- if (styleStr) {
597
- 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
+ }
598
651
  }
599
- continue;
600
652
  }
601
- if (value === true) {
602
- attrs.push(key);
603
- 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);
604
659
  }
605
- attrs.push(`${key}="${this.escapeHtml(String(value))}"`);
660
+ } else {
661
+ childrenArray.push(children);
606
662
  }
607
- return attrs.join(" ");
608
663
  }
609
- styleToString(style) {
610
- if (typeof style === "string") {
611
- return style;
612
- }
613
- if (typeof style === "object" && style !== null) {
614
- const styles = [];
615
- for (const key in style) {
616
- const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
617
- 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);
618
687
  }
619
- return styles.join(";");
620
688
  }
621
- return "";
622
689
  }
623
- isState(value) {
624
- return value && typeof value === "object" && "value" in value && "subscribe" in value && typeof value.subscribe === "function";
625
- }
626
- createReactiveChild(state, renderFn) {
627
- const currentValue = renderFn(state.value);
628
- if (typeof window !== "undefined" && typeof document !== "undefined") {
629
- const entry = { node: null, renderFn };
630
- this.reactiveNodes.set(state, entry);
631
- state.subscribe(() => {
632
- if (entry.node && entry.node.parentNode) {
633
- const newValue = renderFn(state.value);
634
- entry.node.textContent = String(newValue ?? "");
635
- }
636
- });
637
- }
638
- 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");
639
696
  }
640
- jsonToVNode(json) {
641
- if (this.isState(json)) {
642
- return this.createReactiveChild(json, (v) => v);
643
- }
644
- if (isPrimitiveJson(json)) {
645
- return json;
646
- }
647
- const { tag, attributes = {}, children } = json;
648
- const props = {};
649
- for (const key in attributes) {
650
- const value = attributes[key];
651
- if (key === "class") {
652
- props.className = this.isState(value) ? value.value : value;
653
- } else {
654
- 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);
655
729
  }
730
+ } else {
731
+ notify();
656
732
  }
657
- const childrenArray = [];
658
- if (children != null) {
659
- if (Array.isArray(children)) {
660
- for (const child of children) {
661
- if (this.isState(child)) {
662
- childrenArray.push(this.createReactiveChild(child, (v) => v));
663
- } else {
664
- const converted = this.jsonToVNode(child);
665
- if (converted != null && converted !== false) {
666
- childrenArray.push(converted);
667
- }
668
- }
669
- }
670
- } else if (this.isState(children)) {
671
- childrenArray.push(this.createReactiveChild(children, (v) => v));
672
- } else if (typeof children === "object" && "tag" in children) {
673
- const converted = this.jsonToVNode(children);
674
- if (converted != null && converted !== false) {
675
- childrenArray.push(converted);
676
- }
677
- } else {
678
- 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);
679
753
  }
680
754
  }
681
- return { tagName: tag, props, children: childrenArray };
682
- }
683
- vNodeJsonToVNode(json) {
684
- if (this.isState(json)) {
685
- return this.createReactiveChild(json, (v) => v);
686
- }
687
- if (isPrimitiveJson(json)) {
688
- 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);
689
789
  }
690
- const { tagName, props = {}, children = [] } = json;
691
- const resolvedProps = {};
692
- for (const key in props) {
693
- const value = props[key];
694
- 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 = "";
695
804
  }
696
- const childrenArray = [];
697
- for (const child of children) {
698
- if (this.isState(child)) {
699
- childrenArray.push(this.createReactiveChild(child, (v) => v));
700
- } else {
701
- const converted = this.vNodeJsonToVNode(child);
702
- if (converted != null && converted !== false) {
703
- childrenArray.push(converted);
704
- }
705
- }
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;
706
815
  }
707
- 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);
708
887
  }
709
888
  renderJson(rootElement, json) {
710
- const vNode = this.jsonToVNode(json);
711
- if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
712
- throw new Error("Invalid JSON structure");
713
- }
714
- return this.render(rootElement, vNode);
889
+ return renderJson(rootElement, json, this.reactiveNodes);
715
890
  }
716
891
  renderVNode(rootElement, json) {
717
- const vNode = this.vNodeJsonToVNode(json);
718
- if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
719
- throw new Error("Invalid VNode JSON structure");
720
- }
721
- return this.render(rootElement, vNode);
892
+ return renderVNode(rootElement, json, this.reactiveNodes);
722
893
  }
723
894
  renderJsonToString(json, options = {}) {
724
- const vNode = this.jsonToVNode(json);
725
- return this.renderToString(vNode, options);
895
+ return renderJsonToString(json, this.reactiveNodes, options);
726
896
  }
727
897
  renderVNodeToString(json, options = {}) {
728
- const vNode = this.vNodeJsonToVNode(json);
729
- return this.renderToString(vNode, options);
898
+ return renderVNodeToString(json, this.reactiveNodes, options);
730
899
  }
731
900
  // Generate complete HTML document as string (for SSR)
732
901
  renderToHTMLDocument(vNode, options = {}) {
733
- const { title = "", meta = [], links = [], scripts = [], styles = [], lang = "en", head = "", bodyAttrs = {}, pretty = false } = options;
734
- const nl = pretty ? "\n" : "";
735
- const indent = pretty ? " " : "";
736
- const indent2 = pretty ? " " : "";
737
- 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}`;
738
- if (title) html += `${indent2}<title>${this.escapeHtml(title)}</title>${nl}`;
739
- for (const m of meta) {
740
- html += `${indent2}<meta`;
741
- for (const k in m) html += ` ${k}="${this.escapeHtml(m[k])}"`;
742
- html += `>${nl}`;
743
- }
744
- for (const l of links) {
745
- html += `${indent2}<link`;
746
- for (const k in l) html += ` ${k}="${this.escapeHtml(l[k])}"`;
747
- html += `>${nl}`;
748
- }
749
- for (const s of styles) {
750
- if (s.href) {
751
- html += `${indent2}<link rel="stylesheet" href="${this.escapeHtml(s.href)}">${nl}`;
752
- } else if (s.content) {
753
- html += `${indent2}<style>${s.content}</style>${nl}`;
754
- }
755
- }
756
- if (head) html += head + nl;
757
- html += `${indent}</head>${nl}${indent}<body`;
758
- for (const k in bodyAttrs) html += ` ${k}="${this.escapeHtml(bodyAttrs[k])}"`;
759
- html += `>${nl}`;
760
- html += this.renderToString(vNode, { pretty, indent: 2 });
761
- for (const script of scripts) {
762
- html += `${indent2}<script`;
763
- if (script.type) html += ` type="${this.escapeHtml(script.type)}"`;
764
- if (script.async) html += ` async`;
765
- if (script.defer) html += ` defer`;
766
- if (script.src) {
767
- html += ` src="${this.escapeHtml(script.src)}"></script>${nl}`;
768
- } else if (script.content) {
769
- html += `>${script.content}</script>${nl}`;
770
- } else {
771
- html += `></script>${nl}`;
772
- }
773
- }
774
- html += `${indent}</body>${nl}</html>`;
775
- return html;
902
+ return renderToHTMLDocument(vNode, options);
776
903
  }
777
904
  // Expose elementCache for reactive updates
778
905
  getElementCache() {
@@ -780,20 +907,20 @@ var DomNode = class {
780
907
  }
781
908
  };
782
909
  var dom = new DomNode();
783
- var render = dom.render.bind(dom);
784
- var renderToString = dom.renderToString.bind(dom);
910
+ var render2 = dom.render.bind(dom);
911
+ var renderToString2 = dom.renderToString.bind(dom);
785
912
 
786
- // src/state.ts
787
- var ELIT_NATIVE_BINDING = /* @__PURE__ */ Symbol.for("elit.native.binding");
788
- var ELIT_INTERNAL_WS_PATH = "/__elit_ws";
789
- var createState = (initial, options) => dom.createState(initial, options);
790
- var computed = (states, fn) => dom.computed(states, fn);
791
- var effect = (fn) => dom.effect(fn);
792
- var batchRender = (container, vNodes) => dom.batchRender(container, vNodes);
793
- var renderChunked = (container, vNodes, chunkSize, onProgress) => dom.renderChunked(container, vNodes, chunkSize, onProgress);
794
- var createVirtualList = (container, items, renderItem, itemHeight, bufferSize) => dom.createVirtualList(container, items, renderItem, itemHeight, bufferSize);
795
- 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);
796
921
  var cleanupUnused = (root) => dom.cleanupUnusedElements(root);
922
+
923
+ // src/client/state/timing.ts
797
924
  var throttle = (fn, delay) => {
798
925
  let timer = null;
799
926
  return (...args) => {
@@ -808,10 +935,15 @@ var throttle = (fn, delay) => {
808
935
  var debounce = (fn, delay) => {
809
936
  let timer = null;
810
937
  return (...args) => {
811
- timer && clearTimeout(timer);
938
+ if (timer) {
939
+ clearTimeout(timer);
940
+ }
812
941
  timer = setTimeout(() => fn(...args), delay);
813
942
  };
814
943
  };
944
+
945
+ // src/client/state/bindings.ts
946
+ var ELIT_NATIVE_BINDING = /* @__PURE__ */ Symbol.for("elit.native.binding");
815
947
  function bindValue(state) {
816
948
  const props = {
817
949
  value: state.value,
@@ -851,6 +983,9 @@ function bindChecked(state) {
851
983
  };
852
984
  return props;
853
985
  }
986
+
987
+ // src/client/state/shared-state.ts
988
+ var ELIT_INTERNAL_WS_PATH = "/__elit_ws";
854
989
  function resolveSharedStateWebSocketUrl(wsUrl) {
855
990
  const protocol = typeof location !== "undefined" && location.protocol === "https:" ? "wss:" : "ws:";
856
991
  const origin = typeof location !== "undefined" ? `${protocol}//${location.host}` : `${protocol}//localhost`;
@@ -875,33 +1010,21 @@ var SharedState = class {
875
1010
  this.wsUrl = wsUrl;
876
1011
  this.ws = null;
877
1012
  this.pendingUpdates = [];
878
- this.localState = createState(defaultValue);
1013
+ this.localState = createState2(defaultValue);
879
1014
  this.previousValue = defaultValue;
880
1015
  this.connect();
881
1016
  }
882
- /**
883
- * Get current value
884
- */
885
1017
  get value() {
886
1018
  return this.localState.value;
887
1019
  }
888
- /**
889
- * Set new value and sync to server
890
- */
891
1020
  set value(newValue) {
892
1021
  this.previousValue = this.localState.value;
893
1022
  this.localState.value = newValue;
894
1023
  this.sendToServer(newValue);
895
1024
  }
896
- /**
897
- * Get the underlying Elit State (for reactive binding)
898
- */
899
1025
  get state() {
900
1026
  return this.localState;
901
1027
  }
902
- /**
903
- * Subscribe to changes (returns Elit State for reactive)
904
- */
905
1028
  onChange(callback) {
906
1029
  return this.localState.subscribe((newValue) => {
907
1030
  const oldValue = this.previousValue;
@@ -909,17 +1032,13 @@ var SharedState = class {
909
1032
  callback(newValue, oldValue);
910
1033
  });
911
1034
  }
912
- /**
913
- * Update value using a function
914
- */
915
1035
  update(updater) {
916
1036
  this.value = updater(this.value);
917
1037
  }
918
- /**
919
- * Connect to WebSocket
920
- */
921
1038
  connect() {
922
- if (typeof window === "undefined") return;
1039
+ if (typeof window === "undefined") {
1040
+ return;
1041
+ }
923
1042
  const url = resolveSharedStateWebSocketUrl(this.wsUrl);
924
1043
  this.ws = new WebSocket(url);
925
1044
  this.ws.addEventListener("open", () => {
@@ -939,34 +1058,31 @@ var SharedState = class {
939
1058
  console.error("[SharedState] WebSocket error:", error);
940
1059
  });
941
1060
  }
942
- /**
943
- * Subscribe to server state
944
- */
945
1061
  subscribe() {
946
- if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
1062
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
1063
+ return;
1064
+ }
947
1065
  this.ws.send(JSON.stringify({
948
1066
  type: "state:subscribe",
949
1067
  key: this.key
950
1068
  }));
951
1069
  }
952
- /**
953
- * Handle message from server
954
- */
955
1070
  handleMessage(data) {
956
1071
  try {
957
1072
  const msg = JSON.parse(data);
958
- if (msg.key !== this.key) return;
1073
+ if (msg.key !== this.key) {
1074
+ return;
1075
+ }
959
1076
  if (msg.type === "state:init" || msg.type === "state:update") {
960
1077
  this.localState.value = msg.value;
961
1078
  }
962
1079
  } catch (error) {
963
1080
  }
964
1081
  }
965
- /**
966
- * Send value to server
967
- */
968
1082
  sendToServer(value) {
969
- if (!this.ws) return;
1083
+ if (!this.ws) {
1084
+ return;
1085
+ }
970
1086
  if (this.ws.readyState !== WebSocket.OPEN) {
971
1087
  this.pendingUpdates.push(value);
972
1088
  return;
@@ -977,18 +1093,12 @@ var SharedState = class {
977
1093
  value
978
1094
  }));
979
1095
  }
980
- /**
981
- * Disconnect
982
- */
983
1096
  disconnect() {
984
1097
  if (this.ws) {
985
1098
  this.ws.close();
986
1099
  this.ws = null;
987
1100
  }
988
1101
  }
989
- /**
990
- * Destroy state and cleanup
991
- */
992
1102
  destroy() {
993
1103
  this.disconnect();
994
1104
  this.localState.destroy();
@@ -1001,9 +1111,6 @@ var SharedStateManager = class {
1001
1111
  constructor() {
1002
1112
  this.states = /* @__PURE__ */ new Map();
1003
1113
  }
1004
- /**
1005
- * Create or get a shared state
1006
- */
1007
1114
  create(key, defaultValue, wsUrl) {
1008
1115
  if (this.states.has(key)) {
1009
1116
  return this.states.get(key);
@@ -1012,15 +1119,9 @@ var SharedStateManager = class {
1012
1119
  this.states.set(key, state);
1013
1120
  return state;
1014
1121
  }
1015
- /**
1016
- * Get existing state
1017
- */
1018
1122
  get(key) {
1019
1123
  return this.states.get(key);
1020
1124
  }
1021
- /**
1022
- * Delete a state
1023
- */
1024
1125
  delete(key) {
1025
1126
  const state = this.states.get(key);
1026
1127
  if (state) {
@@ -1029,17 +1130,18 @@ var SharedStateManager = class {
1029
1130
  }
1030
1131
  return false;
1031
1132
  }
1032
- /**
1033
- * Clear all states
1034
- */
1035
1133
  clear() {
1036
1134
  this.states.forEach((state) => state.destroy());
1037
1135
  this.states.clear();
1038
1136
  }
1039
1137
  };
1040
1138
  var sharedStateManager = new SharedStateManager();
1139
+
1140
+ // src/client/state/reactive-utils.ts
1041
1141
  var scheduleRAFUpdate = (rafId, updateFn) => {
1042
- rafId && cancelAnimationFrame(rafId);
1142
+ if (rafId) {
1143
+ cancelAnimationFrame(rafId);
1144
+ }
1043
1145
  return requestAnimationFrame(() => {
1044
1146
  updateFn();
1045
1147
  });
@@ -1063,12 +1165,16 @@ var renderToFragment = (content, isVNode) => {
1063
1165
  var updateElementProps = (element, props) => {
1064
1166
  for (const key in props) {
1065
1167
  const value = props[key];
1066
- if (key === "ref") continue;
1168
+ if (key === "ref") {
1169
+ continue;
1170
+ }
1067
1171
  if (key === "class" || key === "className") {
1068
1172
  element.className = Array.isArray(value) ? value.join(" ") : value || "";
1069
1173
  } else if (key === "style" && typeof value === "object") {
1070
- const s = element.style;
1071
- 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
+ }
1072
1178
  } else if (key.startsWith("on")) {
1073
1179
  element[key.toLowerCase()] = value;
1074
1180
  } else if (value != null && value !== false) {
@@ -1078,6 +1184,8 @@ var updateElementProps = (element, props) => {
1078
1184
  }
1079
1185
  }
1080
1186
  };
1187
+
1188
+ // src/client/state/reactive.ts
1081
1189
  var reactive = (state, renderFn) => {
1082
1190
  let rafId = null;
1083
1191
  let elementRef = null;
@@ -1087,7 +1195,9 @@ var reactive = (state, renderFn) => {
1087
1195
  const isVNodeResult = initialResult && typeof initialResult === "object" && "tagName" in initialResult;
1088
1196
  const initialIsNull = initialResult == null || initialResult === false;
1089
1197
  const updateElement = () => {
1090
- if (!elementRef && !placeholder) return;
1198
+ if (!elementRef && !placeholder) {
1199
+ return;
1200
+ }
1091
1201
  const newResult = renderFn(state.value);
1092
1202
  const resultIsNull = newResult == null || newResult === false;
1093
1203
  if (resultIsNull) {
@@ -1168,7 +1278,7 @@ var reactiveAs = (tagName, state, renderFn, props = {}) => {
1168
1278
  const initialChildren = Array.isArray(initialResult) ? initialResult : [initialResult];
1169
1279
  return { tagName, props: { ...props, ref: refCallback }, children: initialChildren };
1170
1280
  };
1171
- 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);
1172
1282
  // Annotate the CommonJS export names for ESM import in node:
1173
1283
  0 && (module.exports = {
1174
1284
  ELIT_NATIVE_BINDING,