sinwan 0.1.0 → 1.1.0

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 (90) hide show
  1. package/README.md +66 -39
  2. package/dist/cjs/index.development.js +2373 -842
  3. package/dist/cjs/index.development.js.map +22 -18
  4. package/dist/cjs/index.production.min.js +2 -2
  5. package/dist/cjs/index.production.min.js.map +22 -18
  6. package/dist/cjs/jsx/jsx-dev-runtime.development.js +6 -16
  7. package/dist/cjs/jsx/jsx-dev-runtime.development.js.map +3 -3
  8. package/dist/cjs/jsx/jsx-dev-runtime.production.min.js +2 -2
  9. package/dist/cjs/jsx/jsx-dev-runtime.production.min.js.map +3 -3
  10. package/dist/cjs/jsx/jsx-runtime.development.js +6 -16
  11. package/dist/cjs/jsx/jsx-runtime.development.js.map +3 -3
  12. package/dist/cjs/jsx/jsx-runtime.production.min.js +2 -2
  13. package/dist/cjs/jsx/jsx-runtime.production.min.js.map +3 -3
  14. package/dist/cjs/renderer/index.development.js +1581 -0
  15. package/dist/cjs/renderer/index.development.js.map +25 -0
  16. package/dist/cjs/renderer/index.production.min.js +3 -0
  17. package/dist/cjs/renderer/index.production.min.js.map +25 -0
  18. package/dist/cjs/server/index.development.js +1210 -362
  19. package/dist/cjs/server/index.development.js.map +13 -10
  20. package/dist/cjs/server/index.production.min.js +2 -2
  21. package/dist/cjs/server/index.production.min.js.map +13 -10
  22. package/dist/component/control-flow.d.ts +71 -0
  23. package/dist/component/control-flow.d.ts.map +1 -0
  24. package/dist/component/index.d.ts +3 -1
  25. package/dist/component/index.d.ts.map +1 -1
  26. package/dist/component/instance.d.ts +7 -1
  27. package/dist/component/instance.d.ts.map +1 -1
  28. package/dist/component/lifecycle.d.ts +2 -1
  29. package/dist/component/lifecycle.d.ts.map +1 -1
  30. package/dist/component/provide-inject.d.ts +11 -5
  31. package/dist/component/provide-inject.d.ts.map +1 -1
  32. package/dist/esm/index.development.js +2253 -744
  33. package/dist/esm/index.development.js.map +22 -18
  34. package/dist/esm/index.production.min.js +2 -2
  35. package/dist/esm/index.production.min.js.map +22 -18
  36. package/dist/esm/jsx/jsx-dev-runtime.development.js +6 -16
  37. package/dist/esm/jsx/jsx-dev-runtime.development.js.map +3 -3
  38. package/dist/esm/jsx/jsx-dev-runtime.production.min.js +2 -2
  39. package/dist/esm/jsx/jsx-dev-runtime.production.min.js.map +3 -3
  40. package/dist/esm/jsx/jsx-runtime.development.js +6 -16
  41. package/dist/esm/jsx/jsx-runtime.development.js.map +3 -3
  42. package/dist/esm/jsx/jsx-runtime.production.min.js +2 -2
  43. package/dist/esm/jsx/jsx-runtime.production.min.js.map +3 -3
  44. package/dist/esm/renderer/index.development.js +1530 -0
  45. package/dist/esm/renderer/index.development.js.map +25 -0
  46. package/dist/esm/renderer/index.production.min.js +4 -0
  47. package/dist/esm/renderer/index.production.min.js.map +25 -0
  48. package/dist/esm/server/index.development.js +1210 -362
  49. package/dist/esm/server/index.development.js.map +13 -10
  50. package/dist/esm/server/index.production.min.js +2 -2
  51. package/dist/esm/server/index.production.min.js.map +13 -10
  52. package/dist/hydration/walk.d.ts.map +1 -1
  53. package/dist/index.d.ts +6 -6
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/jsx/jsx-runtime.d.ts +13 -0
  56. package/dist/jsx/jsx-runtime.d.ts.map +1 -1
  57. package/dist/jsx/jsx-types.d.ts +122 -57
  58. package/dist/jsx/jsx-types.d.ts.map +1 -1
  59. package/dist/renderer/attributes.d.ts +11 -0
  60. package/dist/renderer/attributes.d.ts.map +1 -1
  61. package/dist/renderer/dom-ops.d.ts +4 -1
  62. package/dist/renderer/dom-ops.d.ts.map +1 -1
  63. package/dist/renderer/index.d.ts +2 -2
  64. package/dist/renderer/index.d.ts.map +1 -1
  65. package/dist/renderer/mount.d.ts +2 -5
  66. package/dist/renderer/mount.d.ts.map +1 -1
  67. package/dist/renderer/render-children.d.ts +2 -2
  68. package/dist/renderer/render-children.d.ts.map +1 -1
  69. package/dist/renderer/render-control-flow.d.ts +13 -0
  70. package/dist/renderer/render-control-flow.d.ts.map +1 -0
  71. package/dist/renderer/render-element.d.ts +1 -1
  72. package/dist/renderer/render-element.d.ts.map +1 -1
  73. package/dist/renderer/types.d.ts +10 -1
  74. package/dist/renderer/types.d.ts.map +1 -1
  75. package/dist/renderer/unmount.d.ts +20 -0
  76. package/dist/renderer/unmount.d.ts.map +1 -0
  77. package/dist/renderer.d.ts +1 -0
  78. package/dist/renderer.js +7 -0
  79. package/dist/renderer.mjs +4 -0
  80. package/dist/server/attribute-utils.d.ts +2 -0
  81. package/dist/server/attribute-utils.d.ts.map +1 -0
  82. package/dist/server/hydration-markers.d.ts.map +1 -1
  83. package/dist/server/index.d.ts +1 -1
  84. package/dist/server/index.d.ts.map +1 -1
  85. package/dist/server/renderer.d.ts.map +1 -1
  86. package/dist/server/stream.d.ts +9 -1
  87. package/dist/server/stream.d.ts.map +1 -1
  88. package/dist/types.d.ts +8 -2
  89. package/dist/types.d.ts.map +1 -1
  90. package/package.json +19 -5
@@ -40,22 +40,12 @@ function buildElement(type, props, children) {
40
40
  if (type === Fragment) {
41
41
  return { tag: "", props: {}, children };
42
42
  }
43
- if (typeof type === "function") {
44
- if (type._SinwanComponent || type._SinwanPage) {
45
- const result2 = type(props);
46
- if (result2 && typeof result2 === "object" && "tag" in result2) {
47
- return result2;
48
- }
49
- return { tag: "", props: {}, children: normalizeChildren(result2) };
50
- }
51
- const result = type(props);
52
- if (result && typeof result === "object" && "tag" in result) {
53
- return result;
43
+ if (typeof type === "function" || typeof type === "string") {
44
+ const finalProps = props ?? {};
45
+ if (children.length > 0 && finalProps.children === undefined) {
46
+ finalProps.children = children.length === 1 ? children[0] : children;
54
47
  }
55
- return { tag: "", props: {}, children: normalizeChildren(result) };
56
- }
57
- if (typeof type === "string") {
58
- return { tag: type, props: props || {}, children };
48
+ return { tag: type, props: finalProps, children };
59
49
  }
60
50
  return { tag: "", props: {}, children };
61
51
  }
@@ -75,255 +65,68 @@ function jsxDEV(type, props, key, isStaticChildren, source, self) {
75
65
  return element;
76
66
  }
77
67
 
78
- // src/escaper.ts
79
- var _bun = globalThis.Bun;
80
- var _nativeEscape = typeof _bun?.escapeHTML === "function" ? _bun.escapeHTML.bind(_bun) : undefined;
81
- var HTML_ESCAPE_RE = /[&<>"']/g;
82
- var HTML_ESCAPE_MAP = {
83
- "&": "&amp;",
84
- "<": "&lt;",
85
- ">": "&gt;",
86
- '"': "&quot;",
87
- "'": "&#39;"
88
- };
89
- function portableEscape(str) {
90
- HTML_ESCAPE_RE.lastIndex = 0;
91
- if (!HTML_ESCAPE_RE.test(str))
92
- return str;
93
- return str.replace(HTML_ESCAPE_RE, (c) => HTML_ESCAPE_MAP[c]);
94
- }
95
- function escapeHtml(value) {
96
- if (value == null || typeof value === "boolean")
97
- return "";
98
- if (typeof value === "number")
99
- return String(value);
100
- if (value instanceof HtmlEscapedString)
101
- return value.value;
102
- const s = String(value);
103
- return _nativeEscape ? _nativeEscape(s) : portableEscape(s);
104
- }
105
- function safeHtml(html) {
106
- return raw(html);
107
- }
108
- function isSafeHtml(value) {
109
- return value instanceof HtmlEscapedString;
110
- }
111
-
112
- // src/server/renderer.ts
113
- var componentCache = new WeakMap;
114
- var pageRegistry = new Map;
115
- function registerPage(name, page) {
116
- pageRegistry.set(name, page);
117
- }
118
- function getPage(name) {
119
- return pageRegistry.get(name);
120
- }
121
- function hasPage(name) {
122
- return pageRegistry.has(name);
123
- }
124
- async function renderPage(name, data) {
125
- const page = getPage(name);
126
- if (!page) {
127
- throw new Error(`Page "${name}" not found in registry`);
128
- }
129
- const element = await page(data);
130
- return renderToString(element);
131
- }
132
- async function renderToString(node) {
133
- if (node == null || typeof node === "boolean") {
134
- return "";
135
- }
136
- if (typeof node === "string") {
137
- return escapeHtml(node);
138
- }
139
- if (typeof node === "number") {
140
- return String(node);
141
- }
142
- if (node instanceof HtmlEscapedString) {
143
- return node.value;
144
- }
145
- if (Array.isArray(node)) {
146
- const results = await Promise.all(node.map((child) => renderToString(child)));
147
- return results.join("");
148
- }
149
- if (node instanceof Promise) {
150
- return renderElement(await node);
151
- }
152
- return renderElement(node);
153
- }
154
- async function renderElement(element) {
155
- const { tag, props, children } = element;
156
- if (typeof tag === "function") {
157
- const result = await tag(props);
158
- return renderToString(result);
159
- }
160
- if (typeof tag === "string") {
161
- return renderIntrinsicElement(tag, props, children);
162
- }
163
- return renderToString(children);
164
- }
165
- var VOID_ELEMENTS2 = new Set([
166
- "area",
167
- "base",
168
- "br",
169
- "col",
170
- "embed",
171
- "hr",
172
- "img",
173
- "input",
174
- "link",
175
- "meta",
176
- "param",
177
- "source",
178
- "track",
179
- "wbr"
180
- ]);
181
- async function renderIntrinsicElement(tag, props, children) {
182
- const attrs = renderAttributes(props);
183
- if (VOID_ELEMENTS2.has(tag)) {
184
- return attrs ? `<${tag}${attrs}>` : `<${tag}>`;
185
- }
186
- const childrenHtml = await renderChildren(children, props);
187
- return attrs ? `<${tag}${attrs}>${childrenHtml}</${tag}>` : `<${tag}>${childrenHtml}</${tag}>`;
188
- }
189
- function renderAttributes(props) {
190
- let attrs = "";
191
- for (const [key, value] of Object.entries(props)) {
192
- if (key === "children")
193
- continue;
194
- if (value == null || value === false)
195
- continue;
196
- if (value === true) {
197
- attrs += ` ${key}`;
198
- continue;
199
- }
200
- if (key === "dangerouslySetInnerHTML") {
201
- continue;
202
- }
203
- const attrName = key === "className" ? "class" : key;
204
- const finalName = attrName === "htmlFor" ? "for" : attrName;
205
- const attrValue = escapeHtml(String(value));
206
- attrs += ` ${finalName}="${attrValue}"`;
207
- }
208
- return attrs;
209
- }
210
- async function renderChildren(children, props) {
211
- const dangerous = props.dangerouslySetInnerHTML;
212
- if (dangerous && typeof dangerous.__html === "string") {
213
- return dangerous.__html;
214
- }
215
- return renderToString(children);
216
- }
217
- function isSlots(children) {
218
- return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
219
- }
220
- // src/server/stream.ts
221
- var VOID_ELEMENTS3 = new Set([
222
- "area",
223
- "base",
224
- "br",
225
- "col",
226
- "embed",
227
- "hr",
228
- "img",
229
- "input",
230
- "link",
231
- "meta",
232
- "param",
233
- "source",
234
- "track",
235
- "wbr"
236
- ]);
237
- function streamPage(page, data) {
238
- const encoder = new TextEncoder;
239
- return new ReadableStream({
240
- async start(controller) {
241
- try {
242
- const element = await page(data);
243
- await streamNode(element, controller, encoder);
244
- controller.close();
245
- } catch (error) {
246
- controller.error(error);
247
- }
248
- }
249
- });
250
- }
251
- async function streamNode(node, controller, encoder) {
252
- if (node == null || typeof node === "boolean") {
253
- return;
254
- }
255
- if (typeof node === "string") {
256
- controller.enqueue(encoder.encode(escapeHtml(node)));
257
- return;
258
- }
259
- if (typeof node === "number") {
260
- controller.enqueue(encoder.encode(String(node)));
261
- return;
262
- }
263
- if (node instanceof HtmlEscapedString) {
264
- controller.enqueue(encoder.encode(node.value));
265
- return;
266
- }
267
- if (Array.isArray(node)) {
268
- for (const child of node) {
269
- await streamNode(child, controller, encoder);
68
+ // src/renderer/dom-ops.ts
69
+ function createDefaultDOMOps() {
70
+ return {
71
+ createElement(tag) {
72
+ return document.createElement(tag);
73
+ },
74
+ createElementNS(namespace, tag) {
75
+ return document.createElementNS(namespace, tag);
76
+ },
77
+ createTextNode(text) {
78
+ return document.createTextNode(text);
79
+ },
80
+ createComment(text) {
81
+ return document.createComment(text);
82
+ },
83
+ setAttribute(el, key, value) {
84
+ el.setAttribute(key, value);
85
+ },
86
+ removeAttribute(el, key) {
87
+ el.removeAttribute(key);
88
+ },
89
+ setProperty(el, key, value) {
90
+ el[key] = value;
91
+ },
92
+ insertBefore(parent, child, anchor) {
93
+ parent.insertBefore(child, anchor);
94
+ },
95
+ appendChild(parent, child) {
96
+ parent.appendChild(child);
97
+ },
98
+ remove(node) {
99
+ node.parentNode?.removeChild(node);
100
+ },
101
+ setTextContent(node, text) {
102
+ node.data = text;
103
+ },
104
+ addEventListener(el, event, handler) {
105
+ el.addEventListener(event, handler);
106
+ },
107
+ removeEventListener(el, event, handler) {
108
+ el.removeEventListener(event, handler);
109
+ },
110
+ parentNode(node) {
111
+ return node.parentNode;
112
+ },
113
+ nextSibling(node) {
114
+ return node.nextSibling;
270
115
  }
271
- return;
272
- }
273
- if (node instanceof Promise) {
274
- const resolved = await node;
275
- await streamElement(resolved, controller, encoder);
276
- return;
277
- }
278
- await streamElement(node, controller, encoder);
279
- }
280
- async function streamElement(element, controller, encoder) {
281
- const { tag, props, children } = element;
282
- if (typeof tag === "function") {
283
- const result = await tag(props);
284
- await streamNode(result, controller, encoder);
285
- return;
286
- }
287
- if (typeof tag === "string") {
288
- await streamIntrinsicElement(tag, props, children, controller, encoder);
289
- return;
290
- }
291
- await streamNode(children, controller, encoder);
116
+ };
292
117
  }
293
- async function streamIntrinsicElement(tag, props, children, controller, encoder) {
294
- const attrs = renderAttributes2(props);
295
- const dangerous = props.dangerouslySetInnerHTML;
296
- if (VOID_ELEMENTS3.has(tag)) {
297
- const html = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
298
- controller.enqueue(encoder.encode(html));
299
- return;
300
- }
301
- const openTag = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
302
- controller.enqueue(encoder.encode(openTag));
303
- if (dangerous && typeof dangerous.__html === "string") {
304
- controller.enqueue(encoder.encode(dangerous.__html));
305
- } else {
306
- await streamNode(children, controller, encoder);
307
- }
308
- controller.enqueue(encoder.encode(`</${tag}>`));
118
+ var defaultDOMOps = createDefaultDOMOps();
119
+ var domOps = { ...defaultDOMOps };
120
+ function setDOMOps(overrides) {
121
+ Object.assign(domOps, overrides);
309
122
  }
310
- function renderAttributes2(props) {
311
- let attrs = "";
312
- for (const [key, value] of Object.entries(props)) {
313
- if (key === "children" || key === "dangerouslySetInnerHTML")
314
- continue;
315
- if (value == null || value === false)
316
- continue;
317
- if (value === true) {
318
- attrs += ` ${key}`;
319
- continue;
320
- }
321
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
322
- const attrValue = escapeHtml(String(value));
323
- attrs += ` ${attrName}="${attrValue}"`;
123
+ function resetDOMOps() {
124
+ for (const key of Object.keys(domOps)) {
125
+ delete domOps[key];
324
126
  }
325
- return attrs;
127
+ Object.assign(domOps, defaultDOMOps);
326
128
  }
129
+
327
130
  // src/reactivity/scheduler.ts
328
131
  var pendingEffects = new Set;
329
132
  var flushScheduled = false;
@@ -566,85 +369,12 @@ function isComputed(value) {
566
369
  return value != null && typeof value === "object" && COMPUTED_BRAND in value;
567
370
  }
568
371
 
569
- // src/hydration/markers.ts
570
- var COMP_ID_ATTR = "data-sinwan-id";
571
- var COMP_ID_PREFIX = "c";
572
- var TEXT_MARKER_OPEN = "sinwan-t:";
573
- var TEXT_MARKER_CLOSE = "/sinwan-t";
574
- var EVENT_ATTR = "data-sinwan-ev";
575
- function compId(index) {
576
- return `${COMP_ID_PREFIX}${index}`;
577
- }
578
- function textMarkerOpen(index) {
579
- return `<!--${TEXT_MARKER_OPEN}${index}-->`;
372
+ // src/renderer/events.ts
373
+ function isEventProp(key) {
374
+ return key.length > 2 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z";
580
375
  }
581
- function textMarkerCloseStr() {
582
- return `<!--${TEXT_MARKER_CLOSE}-->`;
583
- }
584
- function parseTextOpenMarker(node) {
585
- const data = node.data;
586
- if (data.startsWith(TEXT_MARKER_OPEN)) {
587
- const idx = parseInt(data.slice(TEXT_MARKER_OPEN.length), 10);
588
- return Number.isNaN(idx) ? -1 : idx;
589
- }
590
- return -1;
591
- }
592
- function isTextCloseMarker(node) {
593
- return node.data === TEXT_MARKER_CLOSE;
594
- }
595
-
596
- // src/renderer/dom-ops.ts
597
- var domOps = {
598
- createElement(tag) {
599
- return document.createElement(tag);
600
- },
601
- createTextNode(text) {
602
- return document.createTextNode(text);
603
- },
604
- createComment(text) {
605
- return document.createComment(text);
606
- },
607
- setAttribute(el, key, value) {
608
- el.setAttribute(key, value);
609
- },
610
- removeAttribute(el, key) {
611
- el.removeAttribute(key);
612
- },
613
- setProperty(el, key, value) {
614
- el[key] = value;
615
- },
616
- insertBefore(parent, child, anchor) {
617
- parent.insertBefore(child, anchor);
618
- },
619
- appendChild(parent, child) {
620
- parent.appendChild(child);
621
- },
622
- remove(node) {
623
- node.parentNode?.removeChild(node);
624
- },
625
- setTextContent(node, text) {
626
- node.data = text;
627
- },
628
- addEventListener(el, event, handler) {
629
- el.addEventListener(event, handler);
630
- },
631
- removeEventListener(el, event, handler) {
632
- el.removeEventListener(event, handler);
633
- },
634
- parentNode(node) {
635
- return node.parentNode;
636
- },
637
- nextSibling(node) {
638
- return node.nextSibling;
639
- }
640
- };
641
-
642
- // src/renderer/events.ts
643
- function isEventProp(key) {
644
- return key.length > 2 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z";
645
- }
646
- function toEventName(key) {
647
- return key.slice(2).toLowerCase();
376
+ function toEventName(key) {
377
+ return key.slice(2).toLowerCase();
648
378
  }
649
379
  function bindEvent(el, eventName, handler) {
650
380
  domOps.addEventListener(el, eventName, handler);
@@ -695,7 +425,18 @@ function setCurrentInstance(instance) {
695
425
  currentInstance = instance;
696
426
  return prev;
697
427
  }
428
+ function withInstance(instance, fn) {
429
+ const prev = setCurrentInstance(instance);
430
+ try {
431
+ return fn();
432
+ } finally {
433
+ setCurrentInstance(prev);
434
+ }
435
+ }
698
436
  function fireMountedHooks(instance) {
437
+ if (instance.isUnmounted) {
438
+ return;
439
+ }
699
440
  for (const child of instance.children) {
700
441
  fireMountedHooks(child);
701
442
  }
@@ -722,6 +463,24 @@ function fireUnmountedHooks(instance) {
722
463
  instance.effects.length = 0;
723
464
  }
724
465
  }
466
+ function fireUpdatedHooks(instance) {
467
+ for (const hook of instance._updatedHooks) {
468
+ hook();
469
+ }
470
+ }
471
+ var queuedUpdatedHooks = new Set;
472
+ function queueUpdatedHooks(instance) {
473
+ if (!instance || !instance.isMounted || instance.isUnmounted || instance._updatedHooks.length === 0 || queuedUpdatedHooks.has(instance)) {
474
+ return;
475
+ }
476
+ queuedUpdatedHooks.add(instance);
477
+ nextTick(() => {
478
+ queuedUpdatedHooks.delete(instance);
479
+ if (instance.isMounted && !instance.isUnmounted) {
480
+ fireUpdatedHooks(instance);
481
+ }
482
+ });
483
+ }
725
484
  function handleComponentError(instance, err) {
726
485
  let current = instance;
727
486
  while (current) {
@@ -736,212 +495,6 @@ function handleComponentError(instance, err) {
736
495
  console.error("[Sinwan] Unhandled component error:", err);
737
496
  }
738
497
 
739
- // src/server/hydration-markers.ts
740
- function createHydrationContext() {
741
- return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
742
- }
743
- async function renderToHydratableString(component, props) {
744
- const ctx = createHydrationContext();
745
- const mergedProps = props ?? {};
746
- const instance = createComponentInstance(component, mergedProps, null);
747
- setCurrentInstance(instance);
748
- const result = await component(mergedProps);
749
- setCurrentInstance(null);
750
- if (result && typeof result === "object" && "tag" in result) {
751
- return renderElementH(result, ctx, true);
752
- }
753
- return renderNodeH(result, ctx);
754
- }
755
- async function renderNodeToHydratableString(node) {
756
- const ctx = createHydrationContext();
757
- return renderNodeH(node, ctx);
758
- }
759
- var VOID_ELEMENTS4 = new Set([
760
- "area",
761
- "base",
762
- "br",
763
- "col",
764
- "embed",
765
- "hr",
766
- "img",
767
- "input",
768
- "link",
769
- "meta",
770
- "param",
771
- "source",
772
- "track",
773
- "wbr"
774
- ]);
775
- function renderNodeH(node, ctx) {
776
- if (node == null || typeof node === "boolean")
777
- return "";
778
- if (typeof node === "string")
779
- return escapeHtml(node);
780
- if (typeof node === "number")
781
- return String(node);
782
- if (node instanceof HtmlEscapedString)
783
- return node.value;
784
- if (isSignal(node) || isComputed(node)) {
785
- const value = node.value;
786
- const idx = ctx.textIndex++;
787
- return `${textMarkerOpen(idx)}${escapeHtml(String(value))}${textMarkerCloseStr()}`;
788
- }
789
- if (Array.isArray(node)) {
790
- return node.map((child) => renderNodeH(child, ctx)).join("");
791
- }
792
- if (node instanceof Promise) {
793
- return "";
794
- }
795
- if (typeof node === "object" && "tag" in node) {
796
- return renderElementH(node, ctx, false);
797
- }
798
- return escapeHtml(String(node));
799
- }
800
- function renderElementH(element, ctx, isComponentRoot) {
801
- const { tag, props, children } = element;
802
- if (tag === "") {
803
- return children.map((child) => renderNodeH(child, ctx)).join("");
804
- }
805
- if (typeof tag === "function") {
806
- return renderComponentH(tag, props, ctx);
807
- }
808
- if (typeof tag === "string") {
809
- return renderIntrinsicH(tag, props, children, ctx, isComponentRoot);
810
- }
811
- return children.map((child) => renderNodeH(child, ctx)).join("");
812
- }
813
- function renderComponentH(component, props, ctx) {
814
- const parentInstance = globalThis.__SinwanCurrentInstance;
815
- const instance = createComponentInstance(component, props, null);
816
- const prev = setCurrentInstance(instance);
817
- const result = component(props);
818
- setCurrentInstance(prev);
819
- if (result && typeof result === "object" && "tag" in result) {
820
- return renderElementH(result, ctx, true);
821
- }
822
- return renderNodeH(result, ctx);
823
- }
824
- function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
825
- let attrs = "";
826
- if (isComponentRoot) {
827
- attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
828
- }
829
- const eventParts = [];
830
- for (const [key, value] of Object.entries(props)) {
831
- if (key === "children" || key === "dangerouslySetInnerHTML")
832
- continue;
833
- if (isEventProp(key)) {
834
- const eventName = toEventName(key);
835
- eventParts.push(`${eventName}:${ctx.eventIndex++}`);
836
- continue;
837
- }
838
- if (value == null || value === false)
839
- continue;
840
- let resolvedValue = value;
841
- if (isSignal(value) || isComputed(value)) {
842
- resolvedValue = value.value;
843
- }
844
- if (resolvedValue === true) {
845
- const attrName2 = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
846
- attrs += ` ${attrName2}`;
847
- continue;
848
- }
849
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
850
- attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
851
- }
852
- if (eventParts.length > 0) {
853
- attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
854
- }
855
- if (VOID_ELEMENTS4.has(tag)) {
856
- return `<${tag}${attrs}>`;
857
- }
858
- const dangerous = props.dangerouslySetInnerHTML;
859
- if (dangerous && typeof dangerous.__html === "string") {
860
- return `<${tag}${attrs}>${dangerous.__html}</${tag}>`;
861
- }
862
- const childrenHtml = children.map((child) => renderNodeH(child, ctx)).join("");
863
- return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
864
- }
865
- // src/reactivity/batch.ts
866
- var batchDepth = 0;
867
- function batch(fn) {
868
- batchDepth++;
869
- try {
870
- fn();
871
- } finally {
872
- batchDepth--;
873
- if (batchDepth === 0) {
874
- flushSync();
875
- }
876
- }
877
- }
878
- // src/component/lifecycle.ts
879
- function onMounted(fn) {
880
- const instance = getCurrentInstance();
881
- if (!instance) {
882
- throw new Error("onMounted() called outside of component setup.");
883
- }
884
- instance._mountedHooks.push(fn);
885
- }
886
- function onUnmounted(fn) {
887
- const instance = getCurrentInstance();
888
- if (!instance) {
889
- throw new Error("onUnmounted() called outside of component setup.");
890
- }
891
- instance._unmountedHooks.push(fn);
892
- }
893
- function onUpdated(fn) {
894
- const instance = getCurrentInstance();
895
- if (!instance) {
896
- throw new Error("onUpdated() called outside of component setup.");
897
- }
898
- instance._updatedHooks.push(fn);
899
- }
900
- function onError(fn) {
901
- const instance = getCurrentInstance();
902
- if (!instance) {
903
- throw new Error("onError() called outside of component setup.");
904
- }
905
- instance._errorHooks.push(fn);
906
- }
907
- // src/component/create.ts
908
- function createComponent(fn) {
909
- const component = (props) => fn(props);
910
- component._SinwanComponent = true;
911
- component._displayName = fn.name || "AnonymousComponent";
912
- return component;
913
- }
914
- function createPage(fn) {
915
- const page = (data) => fn(data);
916
- page._SinwanPage = true;
917
- page._displayName = fn.name || "AnonymousPage";
918
- return page;
919
- }
920
- function createLayout(fn) {
921
- return createComponent(fn);
922
- }
923
- // src/component/provide-inject.ts
924
- function provide(key, value) {
925
- const instance = getCurrentInstance();
926
- if (!instance) {
927
- throw new Error("provide() called outside of component setup.");
928
- }
929
- instance.provides[key] = value;
930
- }
931
- function inject(key, defaultValue) {
932
- const instance = getCurrentInstance();
933
- if (!instance) {
934
- throw new Error("inject() called outside of component setup.");
935
- }
936
- if (key in instance.provides) {
937
- return instance.provides[key];
938
- }
939
- if (arguments.length >= 2) {
940
- return defaultValue;
941
- }
942
- console.warn(`[Sinwan] inject() key "${String(key)}" not found and no default provided.`);
943
- return;
944
- }
945
498
  // src/renderer/attributes.ts
946
499
  var SKIP_PROPS = new Set(["children", "key", "ref", "dangerouslySetInnerHTML"]);
947
500
  var DOM_PROPERTIES = new Set(["value", "checked", "selected", "disabled", "readOnly", "multiple", "indeterminate"]);
@@ -953,12 +506,19 @@ var PROP_ALIASES = {
953
506
  };
954
507
  function applyAttributes(el, props) {
955
508
  const disposers = [];
509
+ const owner = getCurrentInstance();
956
510
  for (const [key, value] of Object.entries(props)) {
957
511
  if (SKIP_PROPS.has(key) || isEventProp(key))
958
512
  continue;
959
513
  if (isSignal(value) || isComputed(value)) {
514
+ const state = { previousStyleProps: new Set };
515
+ let initialized = false;
960
516
  const dispose = effect(() => {
961
- setSingleAttribute(el, key, value.value);
517
+ setSingleAttribute(el, key, value.value, state);
518
+ if (initialized) {
519
+ queueUpdatedHooks(owner);
520
+ }
521
+ initialized = true;
962
522
  });
963
523
  disposers.push(dispose);
964
524
  } else {
@@ -967,10 +527,10 @@ function applyAttributes(el, props) {
967
527
  }
968
528
  return disposers;
969
529
  }
970
- function setSingleAttribute(el, key, value) {
971
- const attrName = PROP_ALIASES[key] ?? key;
530
+ function setSingleAttribute(el, key, value, state) {
531
+ const attrName = resolveAttributeName(key);
972
532
  if (attrName === "style" && typeof value === "object" && value !== null) {
973
- applyStyle(el, value);
533
+ applyStyle(el, value, state);
974
534
  return;
975
535
  }
976
536
  if (attrName === "class" && typeof value === "object" && value !== null) {
@@ -979,6 +539,9 @@ function setSingleAttribute(el, key, value) {
979
539
  }
980
540
  if (value == null || value === false) {
981
541
  domOps.removeAttribute(el, attrName);
542
+ if (attrName === "style" && state) {
543
+ state.previousStyleProps.clear();
544
+ }
982
545
  if (DOM_PROPERTIES.has(attrName)) {
983
546
  domOps.setProperty(el, attrName, attrName === "value" ? "" : false);
984
547
  }
@@ -986,25 +549,59 @@ function setSingleAttribute(el, key, value) {
986
549
  }
987
550
  if (value === true) {
988
551
  domOps.setAttribute(el, attrName, "");
552
+ if (attrName === "style" && state) {
553
+ state.previousStyleProps.clear();
554
+ }
989
555
  if (DOM_PROPERTIES.has(attrName)) {
990
556
  domOps.setProperty(el, attrName, true);
991
557
  }
992
558
  return;
993
559
  }
994
560
  if (DOM_PROPERTIES.has(attrName)) {
561
+ if (attrName === "style" && state) {
562
+ state.previousStyleProps.clear();
563
+ }
995
564
  domOps.setProperty(el, attrName, value);
996
565
  return;
997
566
  }
567
+ if (attrName === "style" && state) {
568
+ state.previousStyleProps.clear();
569
+ }
998
570
  domOps.setAttribute(el, attrName, String(value));
999
571
  }
1000
- function applyStyle(el, styles) {
572
+ function resolveAttributeName(key) {
573
+ return PROP_ALIASES[key] ?? key;
574
+ }
575
+ function applyStyle(el, styles, state) {
576
+ const nextProps = new Set;
1001
577
  for (const [prop, val] of Object.entries(styles)) {
578
+ nextProps.add(prop);
579
+ if (val == null) {
580
+ removeStyleProperty(el, prop);
581
+ continue;
582
+ }
1002
583
  if (prop.includes("-")) {
1003
- el.style.setProperty(prop, val);
584
+ el.style.setProperty(prop, String(val));
1004
585
  } else {
1005
586
  el.style[prop] = val;
1006
587
  }
1007
588
  }
589
+ if (!state) {
590
+ return;
591
+ }
592
+ for (const previousProp of state.previousStyleProps) {
593
+ if (!nextProps.has(previousProp)) {
594
+ removeStyleProperty(el, previousProp);
595
+ }
596
+ }
597
+ state.previousStyleProps = nextProps;
598
+ }
599
+ function removeStyleProperty(el, prop) {
600
+ if (prop.includes("-")) {
601
+ el.style.removeProperty(prop);
602
+ } else {
603
+ el.style[prop] = "";
604
+ }
1008
605
  }
1009
606
  function applyClass(el, value) {
1010
607
  let classStr;
@@ -1017,48 +614,662 @@ function applyClass(el, value) {
1017
614
  }
1018
615
  domOps.setAttribute(el, "class", classStr);
1019
616
  }
1020
-
1021
- // src/renderer/render-element.ts
1022
- var VOID_ELEMENTS5 = new Set([
1023
- "area",
1024
- "base",
1025
- "br",
1026
- "col",
1027
- "embed",
1028
- "hr",
1029
- "img",
1030
- "input",
1031
- "link",
1032
- "meta",
1033
- "param",
1034
- "source",
1035
- "track",
1036
- "wbr"
1037
- ]);
1038
- function renderElementToDOM(element, parent, anchor = null) {
1039
- const { tag, props, children } = element;
1040
- if (tag === "" || tag === Fragment) {
1041
- return renderFragmentToDOM(children, parent, anchor);
617
+ // src/reactivity/batch.ts
618
+ var batchDepth = 0;
619
+ function batch(fn) {
620
+ batchDepth++;
621
+ try {
622
+ fn();
623
+ } finally {
624
+ batchDepth--;
625
+ if (batchDepth === 0) {
626
+ flushSync();
627
+ }
628
+ }
629
+ }
630
+ // src/component/control-flow.ts
631
+ var SHOW_TYPE = Symbol.for("Sinwan.Show");
632
+ var FOR_TYPE = Symbol.for("Sinwan.For");
633
+ var SWITCH_TYPE = Symbol.for("Sinwan.Switch");
634
+ var MATCH_TYPE = Symbol.for("Sinwan.Match");
635
+ var INDEX_TYPE = Symbol.for("Sinwan.Index");
636
+ var KEY_TYPE = Symbol.for("Sinwan.Key");
637
+ var DYNAMIC_TYPE = Symbol.for("Sinwan.Dynamic");
638
+ var PORTAL_TYPE = Symbol.for("Sinwan.Portal");
639
+ function Show(props) {
640
+ return {
641
+ tag: SHOW_TYPE,
642
+ props,
643
+ children: []
644
+ };
645
+ }
646
+ function For(props) {
647
+ return {
648
+ tag: FOR_TYPE,
649
+ props,
650
+ children: []
651
+ };
652
+ }
653
+ function Switch(props) {
654
+ return {
655
+ tag: SWITCH_TYPE,
656
+ props,
657
+ children: []
658
+ };
659
+ }
660
+ function Match(props) {
661
+ return {
662
+ tag: MATCH_TYPE,
663
+ props,
664
+ children: []
665
+ };
666
+ }
667
+ function Index(props) {
668
+ return {
669
+ tag: INDEX_TYPE,
670
+ props,
671
+ children: []
672
+ };
673
+ }
674
+ function Key(props) {
675
+ return {
676
+ tag: KEY_TYPE,
677
+ props,
678
+ children: []
679
+ };
680
+ }
681
+ function Dynamic(props) {
682
+ return {
683
+ tag: DYNAMIC_TYPE,
684
+ props,
685
+ children: []
686
+ };
687
+ }
688
+ function Visible(props) {
689
+ const {
690
+ when,
691
+ as = "span",
692
+ style,
693
+ children,
694
+ ...rest
695
+ } = props;
696
+ const visibleStyle = computed(() => {
697
+ const base = readReactive(style);
698
+ const visible = Boolean(readReactive(when));
699
+ if (typeof base === "string") {
700
+ return visible ? base : appendHiddenDisplay(base);
701
+ }
702
+ const styleObject = base && typeof base === "object" ? { ...base } : {};
703
+ styleObject.display = visible ? styleObject.display : "none";
704
+ return styleObject;
705
+ });
706
+ return {
707
+ tag: as,
708
+ props: {
709
+ ...rest,
710
+ style: visibleStyle,
711
+ children
712
+ },
713
+ children: normalizeChildren2(children)
714
+ };
715
+ }
716
+ function Portal(props) {
717
+ return {
718
+ tag: PORTAL_TYPE,
719
+ props,
720
+ children: []
721
+ };
722
+ }
723
+ function isShowElement(element) {
724
+ return element.tag === SHOW_TYPE;
725
+ }
726
+ function isForElement(element) {
727
+ return element.tag === FOR_TYPE;
728
+ }
729
+ function isSwitchElement(element) {
730
+ return element.tag === SWITCH_TYPE;
731
+ }
732
+ function isMatchElement(element) {
733
+ return element.tag === MATCH_TYPE;
734
+ }
735
+ function isIndexElement(element) {
736
+ return element.tag === INDEX_TYPE;
737
+ }
738
+ function isKeyElement(element) {
739
+ return element.tag === KEY_TYPE;
740
+ }
741
+ function isDynamicElement(element) {
742
+ return element.tag === DYNAMIC_TYPE;
743
+ }
744
+ function isPortalElement(element) {
745
+ return element.tag === PORTAL_TYPE;
746
+ }
747
+ function normalizeChildren2(children) {
748
+ if (children == null || typeof children === "boolean") {
749
+ return [];
750
+ }
751
+ return Array.isArray(children) ? children : [children];
752
+ }
753
+ function readReactive(value) {
754
+ return isSignal(value) || isComputed(value) ? value.value : value;
755
+ }
756
+ function appendHiddenDisplay(style) {
757
+ const trimmed = style.trim();
758
+ const separator = trimmed.length > 0 && !trimmed.endsWith(";") ? ";" : "";
759
+ return `${trimmed}${separator}display:none`;
760
+ }
761
+
762
+ // src/renderer/unmount.ts
763
+ function getMountedDomNodes(node) {
764
+ switch (node.type) {
765
+ case "text":
766
+ case "reactive-text":
767
+ return [node.node];
768
+ case "element":
769
+ return [node.node];
770
+ case "fragment":
771
+ return [
772
+ node.anchor,
773
+ ...node.children.flatMap((child) => getMountedDomNodes(child))
774
+ ];
775
+ case "reactive-block":
776
+ return [
777
+ node.startAnchor,
778
+ ...node.children.flatMap((child) => getMountedDomNodes(child)),
779
+ node.endAnchor
780
+ ];
781
+ case "component":
782
+ return node.children.flatMap((child) => getMountedDomNodes(child));
783
+ case "portal":
784
+ return [node.anchor];
785
+ }
786
+ }
787
+ function unmountNode(node) {
788
+ switch (node.type) {
789
+ case "text":
790
+ break;
791
+ case "reactive-text":
792
+ node.dispose();
793
+ break;
794
+ case "element":
795
+ for (const dispose of node.attrDisposers) {
796
+ dispose();
797
+ }
798
+ for (const cleanup of node.eventCleanups) {
799
+ cleanup();
800
+ }
801
+ node.refCleanup?.();
802
+ for (const child of node.children) {
803
+ unmountNode(child);
804
+ }
805
+ break;
806
+ case "fragment":
807
+ for (const child of node.children) {
808
+ unmountNode(child);
809
+ }
810
+ break;
811
+ case "reactive-block":
812
+ node.dispose();
813
+ for (const child of node.children) {
814
+ unmountNode(child);
815
+ }
816
+ break;
817
+ case "component":
818
+ if (node.instance) {
819
+ fireUnmountedHooks(node.instance);
820
+ } else {
821
+ for (const dispose of node.disposers) {
822
+ dispose();
823
+ }
824
+ }
825
+ for (const child of node.children) {
826
+ unmountNode(child);
827
+ }
828
+ break;
829
+ case "portal":
830
+ node.dispose();
831
+ for (const child of node.children) {
832
+ removeMountedNode(child);
833
+ }
834
+ node.children = [];
835
+ break;
836
+ }
837
+ }
838
+ function removeMountedNode(node) {
839
+ const domNodes = getMountedDomNodes(node);
840
+ unmountNode(node);
841
+ for (const domNode of domNodes) {
842
+ if (domNode.parentNode) {
843
+ domOps.remove(domNode);
844
+ }
845
+ }
846
+ }
847
+
848
+ // src/renderer/render-control-flow.ts
849
+ function renderControlFlowToDOM(element, parent, anchor, namespace) {
850
+ if (isPortalElement(element)) {
851
+ return renderPortal(element, parent, anchor, namespace);
852
+ }
853
+ const startAnchor = domOps.createComment("Sinwan-b");
854
+ const endAnchor = domOps.createComment("/Sinwan-b");
855
+ insertNode(parent, startAnchor, anchor);
856
+ insertNode(parent, endAnchor, anchor);
857
+ const owner = getCurrentInstance();
858
+ let disposeEffect = () => {};
859
+ const block = {
860
+ type: "reactive-block",
861
+ dispose: () => disposeEffect(),
862
+ children: [],
863
+ startAnchor,
864
+ endAnchor
865
+ };
866
+ if (isShowElement(element)) {
867
+ disposeEffect = renderShowBlock(element, block, parent, namespace, owner);
868
+ } else if (isForElement(element)) {
869
+ disposeEffect = renderForBlock(element, block, parent, namespace, owner);
870
+ } else if (isSwitchElement(element)) {
871
+ disposeEffect = renderSwitchBlock(element, block, parent, namespace, owner);
872
+ } else if (isIndexElement(element)) {
873
+ disposeEffect = renderIndexBlock(element, block, parent, namespace, owner);
874
+ } else if (isKeyElement(element)) {
875
+ disposeEffect = renderKeyBlock(element, block, parent, namespace, owner);
876
+ } else if (isDynamicElement(element)) {
877
+ disposeEffect = renderDynamicBlock(element, block, parent, namespace, owner);
878
+ }
879
+ return block;
880
+ }
881
+ function renderShowBlock(element, block, parent, namespace, owner) {
882
+ let initialized = false;
883
+ return effect(() => {
884
+ clearChildren(block);
885
+ const when = readReactive2(element.props.when);
886
+ const content = withOptionalInstance(owner, () => when ? resolveShowChildren(element, when) : element.props.fallback);
887
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
888
+ if (initialized) {
889
+ fireMountedAndQueueUpdated(owner);
890
+ }
891
+ initialized = true;
892
+ });
893
+ }
894
+ function renderForBlock(element, block, parent, namespace, owner) {
895
+ let initialized = false;
896
+ let records = [];
897
+ return effect(() => {
898
+ const props = element.props;
899
+ const items = readReactive2(props.each);
900
+ const list = Array.isArray(items) ? items : [];
901
+ const renderChild = props.children;
902
+ if (typeof renderChild !== "function") {
903
+ clearChildren(block);
904
+ records = [];
905
+ if (initialized) {
906
+ queueUpdatedHooks(owner);
907
+ }
908
+ initialized = true;
909
+ return;
910
+ }
911
+ if (list.length === 0) {
912
+ clearChildren(block);
913
+ records = [];
914
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
915
+ if (initialized) {
916
+ fireMountedAndQueueUpdated(owner);
917
+ }
918
+ initialized = true;
919
+ return;
920
+ }
921
+ if (records.length === 0 && block.children.length > 0) {
922
+ clearChildren(block);
923
+ }
924
+ const oldByKey = new Map;
925
+ for (const record of records) {
926
+ oldByKey.set(record.key, record);
927
+ }
928
+ const nextRecords = [];
929
+ list.forEach((item, index) => {
930
+ const key = props.key ? props.key(item, index) : item;
931
+ const old = oldByKey.get(key);
932
+ if (old && old.item === item) {
933
+ old.index = index;
934
+ moveBeforeEnd(parent, old.mounted, block.endAnchor);
935
+ nextRecords.push(old);
936
+ oldByKey.delete(key);
937
+ return;
938
+ }
939
+ if (old) {
940
+ removeMountedNode(old.mounted);
941
+ oldByKey.delete(key);
942
+ }
943
+ const record = {
944
+ key,
945
+ item,
946
+ index,
947
+ mounted: { type: "text", node: domOps.createTextNode("") }
948
+ };
949
+ record.mounted = withOptionalInstance(owner, () => renderNodeToDOM(renderChild(item, () => record.index), parent, block.endAnchor, namespace));
950
+ nextRecords.push(record);
951
+ });
952
+ for (const record of oldByKey.values()) {
953
+ removeMountedNode(record.mounted);
954
+ }
955
+ records = nextRecords;
956
+ block.children = nextRecords.map((record) => record.mounted);
957
+ if (initialized) {
958
+ fireMountedAndQueueUpdated(owner);
959
+ }
960
+ initialized = true;
961
+ });
962
+ }
963
+ function renderSwitchBlock(element, block, parent, namespace, owner) {
964
+ let initialized = false;
965
+ return effect(() => {
966
+ clearChildren(block);
967
+ const content = withOptionalInstance(owner, () => resolveSwitchContent(element));
968
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
969
+ if (initialized) {
970
+ fireMountedAndQueueUpdated(owner);
971
+ }
972
+ initialized = true;
973
+ });
974
+ }
975
+ function renderIndexBlock(element, block, parent, namespace, owner) {
976
+ let initialized = false;
977
+ let records = [];
978
+ return effect(() => {
979
+ const props = element.props;
980
+ const items = readReactive2(props.each);
981
+ const list = Array.isArray(items) ? items : [];
982
+ const renderChild = props.children;
983
+ if (typeof renderChild !== "function") {
984
+ clearChildren(block);
985
+ records = [];
986
+ if (initialized) {
987
+ queueUpdatedHooks(owner);
988
+ }
989
+ initialized = true;
990
+ return;
991
+ }
992
+ if (list.length === 0) {
993
+ clearChildren(block);
994
+ records = [];
995
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
996
+ if (initialized) {
997
+ fireMountedAndQueueUpdated(owner);
998
+ }
999
+ initialized = true;
1000
+ return;
1001
+ }
1002
+ if (records.length === 0 && block.children.length > 0) {
1003
+ clearChildren(block);
1004
+ }
1005
+ for (let index = 0;index < list.length; index++) {
1006
+ const existing = records[index];
1007
+ if (existing) {
1008
+ existing.item.value = list[index];
1009
+ continue;
1010
+ }
1011
+ const itemSignal = signal(list[index]);
1012
+ const record = {
1013
+ item: itemSignal,
1014
+ mounted: withOptionalInstance(owner, () => renderNodeToDOM(renderChild(() => itemSignal.value, index), parent, block.endAnchor, namespace))
1015
+ };
1016
+ records.push(record);
1017
+ }
1018
+ while (records.length > list.length) {
1019
+ const removed = records.pop();
1020
+ removeMountedNode(removed.mounted);
1021
+ }
1022
+ block.children = records.map((record) => record.mounted);
1023
+ if (initialized) {
1024
+ fireMountedAndQueueUpdated(owner);
1025
+ }
1026
+ initialized = true;
1027
+ });
1028
+ }
1029
+ function renderKeyBlock(element, block, parent, namespace, owner) {
1030
+ let initialized = false;
1031
+ let hasKey = false;
1032
+ let currentKey;
1033
+ return effect(() => {
1034
+ const key = readReactive2(element.props.when);
1035
+ if (hasKey && Object.is(currentKey, key)) {
1036
+ return;
1037
+ }
1038
+ currentKey = key;
1039
+ hasKey = true;
1040
+ clearChildren(block);
1041
+ const content = withOptionalInstance(owner, () => resolveKeyChildren(element, key));
1042
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1043
+ if (initialized) {
1044
+ fireMountedAndQueueUpdated(owner);
1045
+ }
1046
+ initialized = true;
1047
+ });
1048
+ }
1049
+ function renderDynamicBlock(element, block, parent, namespace, owner) {
1050
+ let initialized = false;
1051
+ let hasTag = false;
1052
+ let currentTag;
1053
+ return effect(() => {
1054
+ const tag = readReactive2(element.props.component);
1055
+ if (hasTag && Object.is(currentTag, tag)) {
1056
+ return;
1057
+ }
1058
+ currentTag = tag;
1059
+ hasTag = true;
1060
+ clearChildren(block);
1061
+ const content = tag ? createDynamicElement(element, tag) : null;
1062
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1063
+ if (initialized) {
1064
+ fireMountedAndQueueUpdated(owner);
1065
+ }
1066
+ initialized = true;
1067
+ });
1068
+ }
1069
+ function renderPortal(element, parent, anchor, namespace) {
1070
+ const placeholder = domOps.createComment("Sinwan-p");
1071
+ insertNode(parent, placeholder, anchor);
1072
+ const owner = getCurrentInstance();
1073
+ let disposeEffect = () => {};
1074
+ const portal = {
1075
+ type: "portal",
1076
+ anchor: placeholder,
1077
+ children: [],
1078
+ dispose: () => disposeEffect()
1079
+ };
1080
+ let initialized = false;
1081
+ disposeEffect = effect(() => {
1082
+ clearPortalChildren(portal);
1083
+ const target = resolvePortalTarget(element.props.mount);
1084
+ if (target) {
1085
+ portal.children = renderBlockContent(element.props.children ?? element.children, target, null, namespace, owner);
1086
+ }
1087
+ if (initialized) {
1088
+ fireMountedAndQueueUpdated(owner);
1089
+ }
1090
+ initialized = true;
1091
+ });
1092
+ return portal;
1093
+ }
1094
+ function resolveShowChildren(element, value) {
1095
+ const children = element.props.children ?? element.children;
1096
+ if (typeof children === "function") {
1097
+ return children(value);
1098
+ }
1099
+ return children;
1100
+ }
1101
+ function resolveSwitchContent(element) {
1102
+ const props = element.props;
1103
+ const children = normalizeContent(props.children ?? element.children);
1104
+ for (const child of children) {
1105
+ const match = getMatchElement(child);
1106
+ if (!match) {
1107
+ continue;
1108
+ }
1109
+ const when = readReactive2(match.props.when);
1110
+ if (when) {
1111
+ return resolveMatchChildren(match, when);
1112
+ }
1113
+ }
1114
+ return props.fallback;
1115
+ }
1116
+ function resolveMatchChildren(element, value) {
1117
+ const children = element.props.children ?? element.children;
1118
+ if (typeof children === "function") {
1119
+ return children(value);
1120
+ }
1121
+ return children;
1122
+ }
1123
+ function resolveKeyChildren(element, value) {
1124
+ const children = element.props.children ?? element.children;
1125
+ if (typeof children === "function") {
1126
+ return children(value);
1127
+ }
1128
+ return children;
1129
+ }
1130
+ function createDynamicElement(element, tag) {
1131
+ if (typeof tag !== "string" && typeof tag !== "function") {
1132
+ return null;
1133
+ }
1134
+ const { component, ...props } = element.props;
1135
+ const children = normalizeContent(props.children ?? element.children);
1136
+ return {
1137
+ tag,
1138
+ props,
1139
+ children
1140
+ };
1141
+ }
1142
+ function renderBlockContent(content, parent, anchor, namespace, owner) {
1143
+ if (content == null || typeof content === "boolean") {
1144
+ return [];
1145
+ }
1146
+ const nodes = Array.isArray(content) ? content : [content];
1147
+ return nodes.map((node) => withOptionalInstance(owner, () => renderNodeToDOM(node, parent, anchor, namespace)));
1148
+ }
1149
+ function clearChildren(block) {
1150
+ for (const child of block.children) {
1151
+ removeMountedNode(child);
1152
+ }
1153
+ block.children = [];
1154
+ }
1155
+ function clearPortalChildren(portal) {
1156
+ for (const child of portal.children) {
1157
+ removeMountedNode(child);
1158
+ }
1159
+ portal.children = [];
1160
+ }
1161
+ function moveBeforeEnd(parent, mounted, endAnchor) {
1162
+ for (const node of getMountedDomNodes(mounted)) {
1163
+ domOps.insertBefore(parent, node, endAnchor);
1164
+ }
1165
+ }
1166
+ function fireMountedAndQueueUpdated(owner) {
1167
+ if (owner) {
1168
+ fireMountedHooks(owner);
1169
+ }
1170
+ queueUpdatedHooks(owner);
1171
+ }
1172
+ function withOptionalInstance(owner, fn) {
1173
+ return owner ? withInstance(owner, fn) : fn();
1174
+ }
1175
+ function readReactive2(value) {
1176
+ return isSignal(value) || isComputed(value) ? value.value : value;
1177
+ }
1178
+ function normalizeContent(content) {
1179
+ if (content == null || typeof content === "boolean") {
1180
+ return [];
1181
+ }
1182
+ return Array.isArray(content) ? content : [content];
1183
+ }
1184
+ function isElementLike(value) {
1185
+ return value != null && typeof value === "object" && "tag" in value;
1186
+ }
1187
+ function getMatchElement(value) {
1188
+ if (!isElementLike(value)) {
1189
+ return null;
1190
+ }
1191
+ if (isMatchElement(value)) {
1192
+ return value;
1193
+ }
1194
+ return value.tag === Match ? Match(value.props) : null;
1195
+ }
1196
+ function resolvePortalTarget(value) {
1197
+ const target = readReactive2(value);
1198
+ if (target == null) {
1199
+ return typeof document === "undefined" ? null : document.body;
1200
+ }
1201
+ if (typeof target === "string") {
1202
+ return document.querySelector(target);
1203
+ }
1204
+ if (typeof target === "function") {
1205
+ return target();
1206
+ }
1207
+ if (typeof target === "object" && "nodeType" in target) {
1208
+ return target;
1209
+ }
1210
+ return null;
1211
+ }
1212
+ function insertNode(parent, child, anchor) {
1213
+ if (anchor) {
1214
+ domOps.insertBefore(parent, child, anchor);
1215
+ } else {
1216
+ domOps.appendChild(parent, child);
1217
+ }
1218
+ }
1219
+
1220
+ // src/renderer/render-element.ts
1221
+ var VOID_ELEMENTS2 = new Set([
1222
+ "area",
1223
+ "base",
1224
+ "br",
1225
+ "col",
1226
+ "embed",
1227
+ "hr",
1228
+ "img",
1229
+ "input",
1230
+ "link",
1231
+ "meta",
1232
+ "param",
1233
+ "source",
1234
+ "track",
1235
+ "wbr"
1236
+ ]);
1237
+ var SVG_NS = "http://www.w3.org/2000/svg";
1238
+ var MATH_NS = "http://www.w3.org/1998/Math/MathML";
1239
+ function renderElementToDOM(element, parent, anchor = null, namespace = null) {
1240
+ const { tag, props, children } = element;
1241
+ if (tag === "" || tag === Fragment) {
1242
+ return renderFragmentToDOM(children, parent, anchor, namespace);
1243
+ }
1244
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1245
+ return renderElementToDOM(tag(props), parent, anchor, namespace);
1246
+ }
1247
+ if (tag === Visible) {
1248
+ return renderElementToDOM(tag(props), parent, anchor, namespace);
1249
+ }
1250
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element) || isPortalElement(element)) {
1251
+ return renderControlFlowToDOM(element, parent, anchor, namespace);
1042
1252
  }
1043
1253
  if (typeof tag === "function") {
1044
- return renderComponentToDOM(tag, props, parent, anchor);
1254
+ return renderComponentToDOM(tag, props, parent, anchor, namespace);
1045
1255
  }
1046
1256
  if (typeof tag === "string") {
1047
- return renderIntrinsicToDOM(tag, props, children, parent, anchor);
1257
+ return renderIntrinsicToDOM(tag, props, children, parent, anchor, namespace);
1048
1258
  }
1049
- return renderFragmentToDOM(children, parent, anchor);
1259
+ return renderFragmentToDOM(children, parent, anchor, namespace);
1050
1260
  }
1051
- function renderIntrinsicToDOM(tag, props, children, parent, anchor) {
1052
- const el = domOps.createElement(tag);
1261
+ function renderIntrinsicToDOM(tag, props, children, parent, anchor, parentNamespace) {
1262
+ const namespace = getElementNamespace(tag, parentNamespace);
1263
+ const el = namespace ? domOps.createElementNS(namespace, tag) : domOps.createElement(tag);
1053
1264
  const attrDisposers = applyAttributes(el, props);
1054
1265
  const eventCleanups = bindEvents(el, props);
1055
1266
  let mountedChildren = [];
1056
- if (!VOID_ELEMENTS5.has(tag)) {
1267
+ if (!VOID_ELEMENTS2.has(tag)) {
1057
1268
  const dangerous = props.dangerouslySetInnerHTML;
1058
1269
  if (dangerous && typeof dangerous.__html === "string") {
1059
1270
  el.innerHTML = dangerous.__html;
1060
1271
  } else {
1061
- mountedChildren = renderChildrenToDOM(children, el);
1272
+ mountedChildren = renderChildrenToDOM(children, el, getChildNamespace(tag, namespace));
1062
1273
  }
1063
1274
  }
1064
1275
  if (anchor) {
@@ -1066,15 +1277,17 @@ function renderIntrinsicToDOM(tag, props, children, parent, anchor) {
1066
1277
  } else {
1067
1278
  domOps.appendChild(parent, el);
1068
1279
  }
1280
+ const refCleanup = applyRef(el, props.ref);
1069
1281
  return {
1070
1282
  type: "element",
1071
1283
  node: el,
1072
1284
  children: mountedChildren,
1073
1285
  eventCleanups,
1074
- attrDisposers
1286
+ attrDisposers,
1287
+ refCleanup
1075
1288
  };
1076
1289
  }
1077
- function renderComponentToDOM(component, props, parent, anchor) {
1290
+ function renderComponentToDOM(component, props, parent, anchor, namespace) {
1078
1291
  const parentInstance = getCurrentInstance();
1079
1292
  const instance = createComponentInstance(component, props, parentInstance);
1080
1293
  if (parentInstance) {
@@ -1086,9 +1299,9 @@ function renderComponentToDOM(component, props, parent, anchor) {
1086
1299
  try {
1087
1300
  result = component(props);
1088
1301
  if (result && typeof result === "object" && "tag" in result) {
1089
- child = renderElementToDOM(result, parent, anchor);
1302
+ child = renderElementToDOM(result, parent, anchor, namespace);
1090
1303
  } else {
1091
- child = renderNodeToDOM(result, parent, anchor);
1304
+ child = renderNodeToDOM(result, parent, anchor, namespace);
1092
1305
  }
1093
1306
  } catch (err) {
1094
1307
  setCurrentInstance(prevInstance);
@@ -1115,7 +1328,7 @@ function renderComponentToDOM(component, props, parent, anchor) {
1115
1328
  instance
1116
1329
  };
1117
1330
  }
1118
- function renderFragmentToDOM(children, parent, anchor) {
1331
+ function renderFragmentToDOM(children, parent, anchor, namespace) {
1119
1332
  const anchorComment = domOps.createComment("Sinwan-f");
1120
1333
  if (anchor) {
1121
1334
  domOps.insertBefore(parent, anchorComment, anchor);
@@ -1124,184 +1337,1313 @@ function renderFragmentToDOM(children, parent, anchor) {
1124
1337
  }
1125
1338
  const mounted = [];
1126
1339
  for (const child of children) {
1127
- mounted.push(renderNodeToDOM(child, parent, anchor));
1340
+ mounted.push(renderNodeToDOM(child, parent, anchor, namespace));
1128
1341
  }
1129
1342
  return { type: "fragment", children: mounted, anchor: anchorComment };
1130
1343
  }
1131
-
1132
- // src/renderer/render-children.ts
1133
- function renderNodeToDOM(node, parent, anchor = null) {
1134
- if (node == null || typeof node === "boolean") {
1135
- const text2 = domOps.createTextNode("");
1136
- insertNode(parent, text2, anchor);
1137
- return { type: "text", node: text2 };
1344
+ function getElementNamespace(tag, parentNamespace) {
1345
+ if (tag === "svg")
1346
+ return SVG_NS;
1347
+ if (tag === "math")
1348
+ return MATH_NS;
1349
+ return parentNamespace;
1350
+ }
1351
+ function getChildNamespace(tag, namespace) {
1352
+ if (namespace === SVG_NS && tag === "foreignObject") {
1353
+ return null;
1138
1354
  }
1139
- if (typeof node === "string") {
1140
- const text2 = domOps.createTextNode(node);
1141
- insertNode(parent, text2, anchor);
1355
+ return namespace;
1356
+ }
1357
+ function applyRef(el, ref) {
1358
+ const value = ref;
1359
+ if (!value) {
1360
+ return null;
1361
+ }
1362
+ if (typeof value === "function") {
1363
+ value(el);
1364
+ return () => value(null);
1365
+ }
1366
+ if (typeof value === "object" && "current" in value) {
1367
+ value.current = el;
1368
+ return () => {
1369
+ value.current = null;
1370
+ };
1371
+ }
1372
+ return null;
1373
+ }
1374
+
1375
+ // src/renderer/render-children.ts
1376
+ function renderNodeToDOM(node, parent, anchor = null, namespace = null) {
1377
+ if (node == null || typeof node === "boolean") {
1378
+ const text2 = domOps.createTextNode("");
1379
+ insertNode2(parent, text2, anchor);
1380
+ return { type: "text", node: text2 };
1381
+ }
1382
+ if (typeof node === "string") {
1383
+ const text2 = domOps.createTextNode(node);
1384
+ insertNode2(parent, text2, anchor);
1142
1385
  return { type: "text", node: text2 };
1143
1386
  }
1144
1387
  if (typeof node === "number") {
1145
1388
  const text2 = domOps.createTextNode(String(node));
1146
- insertNode(parent, text2, anchor);
1389
+ insertNode2(parent, text2, anchor);
1390
+ return { type: "text", node: text2 };
1391
+ }
1392
+ if (node instanceof HtmlEscapedString) {
1393
+ const text2 = domOps.createTextNode(node.value);
1394
+ insertNode2(parent, text2, anchor);
1147
1395
  return { type: "text", node: text2 };
1148
1396
  }
1149
- if (node instanceof HtmlEscapedString) {
1150
- const text2 = domOps.createTextNode(node.value);
1151
- insertNode(parent, text2, anchor);
1152
- return { type: "text", node: text2 };
1397
+ if (isSignal(node) || isComputed(node)) {
1398
+ const text2 = domOps.createTextNode(String(node.value));
1399
+ insertNode2(parent, text2, anchor);
1400
+ const owner = getCurrentInstance();
1401
+ let initialized = false;
1402
+ const dispose = effect(() => {
1403
+ domOps.setTextContent(text2, String(node.value));
1404
+ if (initialized) {
1405
+ queueUpdatedHooks(owner);
1406
+ }
1407
+ initialized = true;
1408
+ });
1409
+ return { type: "reactive-text", node: text2, dispose };
1410
+ }
1411
+ if (Array.isArray(node)) {
1412
+ return renderArrayToDOM(node, parent, anchor, namespace);
1413
+ }
1414
+ if (node instanceof Promise) {
1415
+ const placeholder = domOps.createTextNode("");
1416
+ insertNode2(parent, placeholder, anchor);
1417
+ node.then((resolved) => {
1418
+ const mounted = renderNodeToDOM(resolved, parent, placeholder, namespace);
1419
+ domOps.remove(placeholder);
1420
+ });
1421
+ return { type: "text", node: placeholder };
1422
+ }
1423
+ if (typeof node === "object" && "tag" in node) {
1424
+ return renderElementToDOM(node, parent, anchor, namespace);
1425
+ }
1426
+ const text = domOps.createTextNode(String(node));
1427
+ insertNode2(parent, text, anchor);
1428
+ return { type: "text", node: text };
1429
+ }
1430
+ function renderArrayToDOM(nodes, parent, anchor, namespace) {
1431
+ const anchorComment = domOps.createComment("Sinwan-f");
1432
+ insertNode2(parent, anchorComment, anchor);
1433
+ const children = [];
1434
+ for (const child of nodes) {
1435
+ children.push(renderNodeToDOM(child, parent, anchor, namespace));
1436
+ }
1437
+ return { type: "fragment", children, anchor: anchorComment };
1438
+ }
1439
+ function renderChildrenToDOM(children, parent, namespace = null) {
1440
+ const mounted = [];
1441
+ for (const child of children) {
1442
+ mounted.push(renderNodeToDOM(child, parent, null, namespace));
1443
+ }
1444
+ return mounted;
1445
+ }
1446
+ function insertNode2(parent, child, anchor) {
1447
+ if (anchor) {
1448
+ domOps.insertBefore(parent, child, anchor);
1449
+ } else {
1450
+ domOps.appendChild(parent, child);
1451
+ }
1452
+ }
1453
+
1454
+ // src/renderer/mount.ts
1455
+ function mount(component, container, props) {
1456
+ container.innerHTML = "";
1457
+ const mergedProps = props ?? {};
1458
+ const instance = createComponentInstance(component, mergedProps, null);
1459
+ let result;
1460
+ let root;
1461
+ setCurrentInstance(instance);
1462
+ try {
1463
+ result = component(mergedProps);
1464
+ if (result instanceof Promise) {
1465
+ const placeholder = document.createTextNode("");
1466
+ container.appendChild(placeholder);
1467
+ root = { type: "text", node: placeholder };
1468
+ result.then((resolved) => {
1469
+ container.innerHTML = "";
1470
+ setCurrentInstance(instance);
1471
+ root = renderElementToDOM(resolved, container);
1472
+ setCurrentInstance(null);
1473
+ instance.element = root;
1474
+ fireMountedHooks(instance);
1475
+ });
1476
+ } else if (result && typeof result === "object" && "tag" in result) {
1477
+ root = renderElementToDOM(result, container);
1478
+ } else {
1479
+ root = renderNodeToDOM(result, container);
1480
+ }
1481
+ } catch (err) {
1482
+ setCurrentInstance(null);
1483
+ handleComponentError(instance, err);
1484
+ return {
1485
+ root: { type: "text", node: document.createTextNode("") },
1486
+ unmount() {}
1487
+ };
1488
+ }
1489
+ setCurrentInstance(null);
1490
+ instance.element = root;
1491
+ fireMountedHooks(instance);
1492
+ return {
1493
+ root,
1494
+ unmount() {
1495
+ fireUnmountedHooks(instance);
1496
+ unmountNode(root);
1497
+ container.innerHTML = "";
1498
+ }
1499
+ };
1500
+ }
1501
+ function render(node, container) {
1502
+ container.innerHTML = "";
1503
+ const root = renderNodeToDOM(node, container);
1504
+ return {
1505
+ root,
1506
+ unmount() {
1507
+ unmountNode(root);
1508
+ container.innerHTML = "";
1509
+ }
1510
+ };
1511
+ }
1512
+ // src/escaper.ts
1513
+ var _bun = globalThis.Bun;
1514
+ var _nativeEscape = typeof _bun?.escapeHTML === "function" ? _bun.escapeHTML.bind(_bun) : undefined;
1515
+ var HTML_ESCAPE_RE = /[&<>"']/g;
1516
+ var HTML_ESCAPE_MAP = {
1517
+ "&": "&amp;",
1518
+ "<": "&lt;",
1519
+ ">": "&gt;",
1520
+ '"': "&quot;",
1521
+ "'": "&#39;"
1522
+ };
1523
+ function portableEscape(str) {
1524
+ HTML_ESCAPE_RE.lastIndex = 0;
1525
+ if (!HTML_ESCAPE_RE.test(str))
1526
+ return str;
1527
+ return str.replace(HTML_ESCAPE_RE, (c) => HTML_ESCAPE_MAP[c]);
1528
+ }
1529
+ function escapeHtml(value) {
1530
+ if (value == null || typeof value === "boolean")
1531
+ return "";
1532
+ if (typeof value === "number")
1533
+ return String(value);
1534
+ if (value instanceof HtmlEscapedString)
1535
+ return value.value;
1536
+ const s = String(value);
1537
+ return _nativeEscape ? _nativeEscape(s) : portableEscape(s);
1538
+ }
1539
+ function safeHtml(html) {
1540
+ return raw(html);
1541
+ }
1542
+ function isSafeHtml(value) {
1543
+ return value instanceof HtmlEscapedString;
1544
+ }
1545
+
1546
+ // src/server/attribute-utils.ts
1547
+ var PROP_ALIASES2 = {
1548
+ className: "class",
1549
+ htmlFor: "for",
1550
+ tabIndex: "tabindex",
1551
+ crossOrigin: "crossorigin"
1552
+ };
1553
+ function renderServerAttribute(key, value) {
1554
+ const attrName = PROP_ALIASES2[key] ?? key;
1555
+ if (value == null || value === false) {
1556
+ return "";
1557
+ }
1558
+ if (value === true) {
1559
+ return ` ${attrName}`;
1560
+ }
1561
+ const attrValue = attrName === "class" && typeof value === "object" ? stringifyClass(value) : attrName === "style" && typeof value === "object" ? stringifyStyle(value) : String(value);
1562
+ return ` ${attrName}="${escapeHtml(attrValue)}"`;
1563
+ }
1564
+ function stringifyClass(value) {
1565
+ if (Array.isArray(value)) {
1566
+ return value.filter(Boolean).join(" ");
1567
+ }
1568
+ return Object.entries(value).filter(([, enabled]) => Boolean(enabled)).map(([name]) => name).join(" ");
1569
+ }
1570
+ function stringifyStyle(value) {
1571
+ return Object.entries(value).filter(([, val]) => val != null && val !== false).map(([prop, val]) => `${toKebabCase(prop)}:${String(val)}`).join(";");
1572
+ }
1573
+ function toKebabCase(value) {
1574
+ return value.includes("-") ? value : value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
1575
+ }
1576
+
1577
+ // src/server/renderer.ts
1578
+ var componentCache = new WeakMap;
1579
+ var pageRegistry = new Map;
1580
+ function registerPage(name, page) {
1581
+ pageRegistry.set(name, page);
1582
+ }
1583
+ function getPage(name) {
1584
+ return pageRegistry.get(name);
1585
+ }
1586
+ function hasPage(name) {
1587
+ return pageRegistry.has(name);
1588
+ }
1589
+ async function renderPage(name, data) {
1590
+ const page = getPage(name);
1591
+ if (!page) {
1592
+ throw new Error(`Page "${name}" not found in registry`);
1593
+ }
1594
+ const element = await page(data);
1595
+ return renderToString(element);
1596
+ }
1597
+ async function renderToString(node) {
1598
+ if (node == null || typeof node === "boolean") {
1599
+ return "";
1600
+ }
1601
+ if (typeof node === "string") {
1602
+ return escapeHtml(node);
1603
+ }
1604
+ if (typeof node === "number") {
1605
+ return String(node);
1606
+ }
1607
+ if (node instanceof HtmlEscapedString) {
1608
+ return node.value;
1609
+ }
1610
+ if (isSignal(node) || isComputed(node)) {
1611
+ return escapeHtml(String(node.value));
1612
+ }
1613
+ if (Array.isArray(node)) {
1614
+ const results = await Promise.all(node.map((child) => renderToString(child)));
1615
+ return results.join("");
1616
+ }
1617
+ if (node instanceof Promise) {
1618
+ return renderElement(await node);
1619
+ }
1620
+ return renderElement(node);
1621
+ }
1622
+ async function renderElement(element) {
1623
+ const { tag, props, children } = element;
1624
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1625
+ return renderElement(tag(props));
1626
+ }
1627
+ if (tag === Visible) {
1628
+ return renderElement(tag(props));
1629
+ }
1630
+ if (isShowElement(element)) {
1631
+ const when = readReactive3(props.when);
1632
+ return renderToString(when ? resolveShowChildren2(element, when) : props.fallback);
1633
+ }
1634
+ if (isForElement(element)) {
1635
+ return renderForElement(element);
1636
+ }
1637
+ if (isSwitchElement(element)) {
1638
+ return renderToString(resolveSwitchContent2(element));
1639
+ }
1640
+ if (isMatchElement(element)) {
1641
+ const when = readReactive3(props.when);
1642
+ return renderToString(when ? resolveMatchChildren2(element, when) : null);
1643
+ }
1644
+ if (isIndexElement(element)) {
1645
+ return renderIndexElement(element);
1646
+ }
1647
+ if (isKeyElement(element)) {
1648
+ const key = readReactive3(props.when);
1649
+ return renderToString(resolveKeyChildren2(element, key));
1650
+ }
1651
+ if (isDynamicElement(element)) {
1652
+ const tag2 = readReactive3(props.component);
1653
+ const dynamic = createDynamicElement2(element, tag2);
1654
+ return dynamic ? renderElement(dynamic) : "";
1655
+ }
1656
+ if (isPortalElement(element)) {
1657
+ return "";
1658
+ }
1659
+ if (typeof tag === "function") {
1660
+ const result = await tag(props);
1661
+ return renderToString(result);
1662
+ }
1663
+ if (typeof tag === "string") {
1664
+ return renderIntrinsicElement(tag, props, children);
1665
+ }
1666
+ return renderToString(children);
1667
+ }
1668
+ var VOID_ELEMENTS3 = new Set([
1669
+ "area",
1670
+ "base",
1671
+ "br",
1672
+ "col",
1673
+ "embed",
1674
+ "hr",
1675
+ "img",
1676
+ "input",
1677
+ "link",
1678
+ "meta",
1679
+ "param",
1680
+ "source",
1681
+ "track",
1682
+ "wbr"
1683
+ ]);
1684
+ async function renderIntrinsicElement(tag, props, children) {
1685
+ const attrs = renderAttributes(props);
1686
+ if (VOID_ELEMENTS3.has(tag)) {
1687
+ return attrs ? `<${tag}${attrs}>` : `<${tag}>`;
1688
+ }
1689
+ const childrenHtml = await renderChildren(children, props);
1690
+ return attrs ? `<${tag}${attrs}>${childrenHtml}</${tag}>` : `<${tag}>${childrenHtml}</${tag}>`;
1691
+ }
1692
+ function renderAttributes(props) {
1693
+ let attrs = "";
1694
+ for (const [key, value] of Object.entries(props)) {
1695
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
1696
+ continue;
1697
+ }
1698
+ const resolvedValue = readReactive3(value);
1699
+ if (resolvedValue == null || resolvedValue === false)
1700
+ continue;
1701
+ attrs += renderServerAttribute(key, resolvedValue);
1702
+ }
1703
+ return attrs;
1704
+ }
1705
+ async function renderChildren(children, props) {
1706
+ const dangerous = props.dangerouslySetInnerHTML;
1707
+ if (dangerous && typeof dangerous.__html === "string") {
1708
+ return dangerous.__html;
1709
+ }
1710
+ return renderToString(children);
1711
+ }
1712
+ function isSlots(children) {
1713
+ return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
1714
+ }
1715
+ async function renderForElement(element) {
1716
+ const props = element.props;
1717
+ const each = readReactive3(props.each);
1718
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1719
+ return props.fallback ? renderToString(props.fallback) : "";
1720
+ }
1721
+ if (each.length === 0) {
1722
+ return props.fallback ? renderToString(props.fallback) : "";
1723
+ }
1724
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
1725
+ return rendered.join("");
1726
+ }
1727
+ async function renderIndexElement(element) {
1728
+ const props = element.props;
1729
+ const each = readReactive3(props.each);
1730
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1731
+ return props.fallback ? renderToString(props.fallback) : "";
1732
+ }
1733
+ if (each.length === 0) {
1734
+ return props.fallback ? renderToString(props.fallback) : "";
1735
+ }
1736
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(() => item, index))));
1737
+ return rendered.join("");
1738
+ }
1739
+ function resolveSwitchContent2(element) {
1740
+ const props = element.props;
1741
+ const children = normalizeContent2(props.children ?? element.children);
1742
+ for (const child of children) {
1743
+ const match = getMatchElement2(child);
1744
+ if (!match) {
1745
+ continue;
1746
+ }
1747
+ const when = readReactive3(match.props.when);
1748
+ if (when) {
1749
+ return resolveMatchChildren2(match, when);
1750
+ }
1751
+ }
1752
+ return props.fallback;
1753
+ }
1754
+ function resolveMatchChildren2(element, value) {
1755
+ const children = element.props.children ?? element.children;
1756
+ if (typeof children === "function") {
1757
+ return children(value);
1758
+ }
1759
+ return children;
1760
+ }
1761
+ function resolveKeyChildren2(element, value) {
1762
+ const children = element.props.children ?? element.children;
1763
+ if (typeof children === "function") {
1764
+ return children(value);
1765
+ }
1766
+ return children;
1767
+ }
1768
+ function createDynamicElement2(element, tag) {
1769
+ if (typeof tag !== "string" && typeof tag !== "function") {
1770
+ return null;
1771
+ }
1772
+ const { component, ...props } = element.props;
1773
+ const children = normalizeContent2(props.children ?? element.children);
1774
+ return {
1775
+ tag,
1776
+ props,
1777
+ children
1778
+ };
1779
+ }
1780
+ function resolveShowChildren2(element, value) {
1781
+ const children = element.props.children ?? element.children;
1782
+ if (typeof children === "function") {
1783
+ return children(value);
1784
+ }
1785
+ return children;
1786
+ }
1787
+ function readReactive3(value) {
1788
+ return isSignal(value) || isComputed(value) ? value.value : value;
1789
+ }
1790
+ function normalizeContent2(content) {
1791
+ if (content == null || typeof content === "boolean") {
1792
+ return [];
1793
+ }
1794
+ return Array.isArray(content) ? content : [content];
1795
+ }
1796
+ function isElementLike2(value) {
1797
+ return value != null && typeof value === "object" && "tag" in value;
1798
+ }
1799
+ function getMatchElement2(value) {
1800
+ if (!isElementLike2(value)) {
1801
+ return null;
1802
+ }
1803
+ if (isMatchElement(value)) {
1804
+ return value;
1805
+ }
1806
+ return value.tag === Match ? Match(value.props) : null;
1807
+ }
1808
+ // src/hydration/markers.ts
1809
+ var COMP_ID_ATTR = "data-sinwan-id";
1810
+ var COMP_ID_PREFIX = "c";
1811
+ var TEXT_MARKER_OPEN = "sinwan-t:";
1812
+ var TEXT_MARKER_CLOSE = "/sinwan-t";
1813
+ var EVENT_ATTR = "data-sinwan-ev";
1814
+ function compId(index) {
1815
+ return `${COMP_ID_PREFIX}${index}`;
1816
+ }
1817
+ function textMarkerOpen(index) {
1818
+ return `<!--${TEXT_MARKER_OPEN}${index}-->`;
1819
+ }
1820
+ function textMarkerCloseStr() {
1821
+ return `<!--${TEXT_MARKER_CLOSE}-->`;
1822
+ }
1823
+ function parseTextOpenMarker(node) {
1824
+ const data = node.data;
1825
+ if (data.startsWith(TEXT_MARKER_OPEN)) {
1826
+ const idx = parseInt(data.slice(TEXT_MARKER_OPEN.length), 10);
1827
+ return Number.isNaN(idx) ? -1 : idx;
1828
+ }
1829
+ return -1;
1830
+ }
1831
+ function isTextCloseMarker(node) {
1832
+ return node.data === TEXT_MARKER_CLOSE;
1833
+ }
1834
+
1835
+ // src/server/stream.ts
1836
+ function createHydratableStreamContext() {
1837
+ return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
1838
+ }
1839
+ var VOID_ELEMENTS4 = new Set([
1840
+ "area",
1841
+ "base",
1842
+ "br",
1843
+ "col",
1844
+ "embed",
1845
+ "hr",
1846
+ "img",
1847
+ "input",
1848
+ "link",
1849
+ "meta",
1850
+ "param",
1851
+ "source",
1852
+ "track",
1853
+ "wbr"
1854
+ ]);
1855
+ function streamPage(page, data) {
1856
+ const encoder = new TextEncoder;
1857
+ return new ReadableStream({
1858
+ async start(controller) {
1859
+ try {
1860
+ const element = await page(data);
1861
+ await streamNode(element, controller, encoder);
1862
+ controller.close();
1863
+ } catch (error) {
1864
+ controller.error(error);
1865
+ }
1866
+ }
1867
+ });
1868
+ }
1869
+ function streamHydratablePage(component, props) {
1870
+ const encoder = new TextEncoder;
1871
+ const ctx = createHydratableStreamContext();
1872
+ return new ReadableStream({
1873
+ async start(controller) {
1874
+ try {
1875
+ await streamHydratableComponent(component, props ?? {}, controller, encoder, ctx, true);
1876
+ controller.close();
1877
+ } catch (error) {
1878
+ controller.error(error);
1879
+ }
1880
+ }
1881
+ });
1882
+ }
1883
+ function streamHydratableNode(node) {
1884
+ const encoder = new TextEncoder;
1885
+ const ctx = createHydratableStreamContext();
1886
+ return new ReadableStream({
1887
+ async start(controller) {
1888
+ try {
1889
+ await streamHydratableNodeToController(node, controller, encoder, ctx);
1890
+ controller.close();
1891
+ } catch (error) {
1892
+ controller.error(error);
1893
+ }
1894
+ }
1895
+ });
1896
+ }
1897
+ async function streamNode(node, controller, encoder) {
1898
+ if (node == null || typeof node === "boolean") {
1899
+ return;
1900
+ }
1901
+ if (typeof node === "string") {
1902
+ controller.enqueue(encoder.encode(escapeHtml(node)));
1903
+ return;
1904
+ }
1905
+ if (typeof node === "number") {
1906
+ controller.enqueue(encoder.encode(String(node)));
1907
+ return;
1908
+ }
1909
+ if (node instanceof HtmlEscapedString) {
1910
+ controller.enqueue(encoder.encode(node.value));
1911
+ return;
1912
+ }
1913
+ if (isSignal(node) || isComputed(node)) {
1914
+ controller.enqueue(encoder.encode(escapeHtml(String(node.value))));
1915
+ return;
1916
+ }
1917
+ if (Array.isArray(node)) {
1918
+ for (const child of node) {
1919
+ await streamNode(child, controller, encoder);
1920
+ }
1921
+ return;
1922
+ }
1923
+ if (node instanceof Promise) {
1924
+ const resolved = await node;
1925
+ await streamElement(resolved, controller, encoder);
1926
+ return;
1927
+ }
1928
+ await streamElement(node, controller, encoder);
1929
+ }
1930
+ async function streamElement(element, controller, encoder) {
1931
+ const { tag, props, children } = element;
1932
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1933
+ await streamElement(tag(props), controller, encoder);
1934
+ return;
1935
+ }
1936
+ if (tag === Visible) {
1937
+ await streamElement(tag(props), controller, encoder);
1938
+ return;
1939
+ }
1940
+ if (isShowElement(element)) {
1941
+ const when = readReactive4(props.when);
1942
+ await streamNode(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder);
1943
+ return;
1944
+ }
1945
+ if (isForElement(element)) {
1946
+ await streamForElement(element, controller, encoder);
1947
+ return;
1948
+ }
1949
+ if (isSwitchElement(element)) {
1950
+ await streamNode(resolveSwitchContent3(element), controller, encoder);
1951
+ return;
1952
+ }
1953
+ if (isMatchElement(element)) {
1954
+ const when = readReactive4(props.when);
1955
+ await streamNode(when ? resolveMatchChildren3(element, when) : null, controller, encoder);
1956
+ return;
1957
+ }
1958
+ if (isIndexElement(element)) {
1959
+ await streamIndexElement(element, controller, encoder);
1960
+ return;
1961
+ }
1962
+ if (isKeyElement(element)) {
1963
+ const key = readReactive4(props.when);
1964
+ await streamNode(resolveKeyChildren3(element, key), controller, encoder);
1965
+ return;
1966
+ }
1967
+ if (isDynamicElement(element)) {
1968
+ const dynamicTag = readReactive4(props.component);
1969
+ const dynamic = createDynamicElement3(element, dynamicTag);
1970
+ if (dynamic) {
1971
+ await streamElement(dynamic, controller, encoder);
1972
+ }
1973
+ return;
1974
+ }
1975
+ if (isPortalElement(element)) {
1976
+ return;
1977
+ }
1978
+ if (typeof tag === "function") {
1979
+ const result = await tag(props);
1980
+ await streamNode(result, controller, encoder);
1981
+ return;
1982
+ }
1983
+ if (typeof tag === "string") {
1984
+ await streamIntrinsicElement(tag, props, children, controller, encoder);
1985
+ return;
1986
+ }
1987
+ await streamNode(children, controller, encoder);
1988
+ }
1989
+ async function streamIntrinsicElement(tag, props, children, controller, encoder) {
1990
+ const attrs = renderAttributes2(props);
1991
+ const dangerous = props.dangerouslySetInnerHTML;
1992
+ if (VOID_ELEMENTS4.has(tag)) {
1993
+ const html = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
1994
+ controller.enqueue(encoder.encode(html));
1995
+ return;
1996
+ }
1997
+ const openTag = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
1998
+ controller.enqueue(encoder.encode(openTag));
1999
+ if (dangerous && typeof dangerous.__html === "string") {
2000
+ controller.enqueue(encoder.encode(dangerous.__html));
2001
+ } else {
2002
+ await streamNode(children, controller, encoder);
2003
+ }
2004
+ controller.enqueue(encoder.encode(`</${tag}>`));
2005
+ }
2006
+ function renderAttributes2(props) {
2007
+ let attrs = "";
2008
+ for (const [key, value] of Object.entries(props)) {
2009
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
2010
+ continue;
2011
+ }
2012
+ const resolvedValue = readReactive4(value);
2013
+ if (resolvedValue == null || resolvedValue === false)
2014
+ continue;
2015
+ attrs += renderServerAttribute(key, resolvedValue);
2016
+ }
2017
+ return attrs;
2018
+ }
2019
+ async function streamHydratableNodeToController(node, controller, encoder, ctx, isComponentRoot = false) {
2020
+ if (node == null || typeof node === "boolean") {
2021
+ return;
2022
+ }
2023
+ if (typeof node === "string") {
2024
+ enqueue(controller, encoder, escapeHtml(node));
2025
+ return;
2026
+ }
2027
+ if (typeof node === "number") {
2028
+ enqueue(controller, encoder, String(node));
2029
+ return;
2030
+ }
2031
+ if (node instanceof HtmlEscapedString) {
2032
+ enqueue(controller, encoder, node.value);
2033
+ return;
2034
+ }
2035
+ if (isSignal(node) || isComputed(node)) {
2036
+ const idx = ctx.textIndex++;
2037
+ enqueue(controller, encoder, `${textMarkerOpen(idx)}${escapeHtml(String(node.value))}${textMarkerCloseStr()}`);
2038
+ return;
2039
+ }
2040
+ if (Array.isArray(node)) {
2041
+ for (const child of node) {
2042
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
2043
+ }
2044
+ return;
2045
+ }
2046
+ if (node instanceof Promise) {
2047
+ await streamHydratableElement(await node, controller, encoder, ctx, isComponentRoot);
2048
+ return;
2049
+ }
2050
+ await streamHydratableElement(node, controller, encoder, ctx, isComponentRoot);
2051
+ }
2052
+ async function streamHydratableElement(element, controller, encoder, ctx, isComponentRoot) {
2053
+ const { tag, props, children } = element;
2054
+ if (tag === "") {
2055
+ for (const child of children) {
2056
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
2057
+ }
2058
+ return;
2059
+ }
2060
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2061
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
2062
+ return;
2063
+ }
2064
+ if (tag === Visible) {
2065
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
2066
+ return;
2067
+ }
2068
+ if (isShowElement(element)) {
2069
+ const when = readReactive4(props.when);
2070
+ await streamHydratableNodeToController(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder, ctx, isComponentRoot);
2071
+ return;
2072
+ }
2073
+ if (isForElement(element)) {
2074
+ await streamHydratableForElement(element, controller, encoder, ctx);
2075
+ return;
2076
+ }
2077
+ if (isSwitchElement(element)) {
2078
+ await streamHydratableNodeToController(resolveSwitchContent3(element), controller, encoder, ctx, isComponentRoot);
2079
+ return;
2080
+ }
2081
+ if (isMatchElement(element)) {
2082
+ const when = readReactive4(props.when);
2083
+ await streamHydratableNodeToController(when ? resolveMatchChildren3(element, when) : null, controller, encoder, ctx, isComponentRoot);
2084
+ return;
2085
+ }
2086
+ if (isIndexElement(element)) {
2087
+ await streamHydratableIndexElement(element, controller, encoder, ctx);
2088
+ return;
2089
+ }
2090
+ if (isKeyElement(element)) {
2091
+ const key = readReactive4(props.when);
2092
+ await streamHydratableNodeToController(resolveKeyChildren3(element, key), controller, encoder, ctx, isComponentRoot);
2093
+ return;
2094
+ }
2095
+ if (isDynamicElement(element)) {
2096
+ const dynamicTag = readReactive4(props.component);
2097
+ const dynamic = createDynamicElement3(element, dynamicTag);
2098
+ if (dynamic) {
2099
+ await streamHydratableElement(dynamic, controller, encoder, ctx, isComponentRoot);
2100
+ }
2101
+ return;
2102
+ }
2103
+ if (isPortalElement(element)) {
2104
+ return;
2105
+ }
2106
+ if (typeof tag === "function") {
2107
+ await streamHydratableComponent(tag, props, controller, encoder, ctx, true);
2108
+ return;
2109
+ }
2110
+ if (typeof tag === "string") {
2111
+ await streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot);
2112
+ return;
2113
+ }
2114
+ await streamHydratableNodeToController(children, controller, encoder, ctx);
2115
+ }
2116
+ async function streamHydratableComponent(component, props, controller, encoder, ctx, isComponentRoot) {
2117
+ const parentInstance = getCurrentInstance();
2118
+ const instance = createComponentInstance(component, props, parentInstance);
2119
+ if (parentInstance) {
2120
+ parentInstance.children.push(instance);
2121
+ }
2122
+ const prev = setCurrentInstance(instance);
2123
+ try {
2124
+ const result = await component(props);
2125
+ await streamHydratableNodeToController(result, controller, encoder, ctx, isComponentRoot);
2126
+ } finally {
2127
+ setCurrentInstance(prev);
2128
+ }
2129
+ }
2130
+ async function streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot) {
2131
+ const attrs = renderHydratableAttributes(props, ctx, isComponentRoot);
2132
+ const dangerous = props.dangerouslySetInnerHTML;
2133
+ enqueue(controller, encoder, attrs ? `<${tag}${attrs}>` : `<${tag}>`);
2134
+ if (VOID_ELEMENTS4.has(tag)) {
2135
+ return;
2136
+ }
2137
+ if (dangerous && typeof dangerous.__html === "string") {
2138
+ enqueue(controller, encoder, dangerous.__html);
2139
+ } else {
2140
+ for (const child of children) {
2141
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
2142
+ }
2143
+ }
2144
+ enqueue(controller, encoder, `</${tag}>`);
2145
+ }
2146
+ async function streamHydratableForElement(element, controller, encoder, ctx) {
2147
+ const props = element.props;
2148
+ const each = readReactive4(props.each);
2149
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2150
+ if (props.fallback) {
2151
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2152
+ }
2153
+ return;
2154
+ }
2155
+ if (each.length === 0) {
2156
+ if (props.fallback) {
2157
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2158
+ }
2159
+ return;
2160
+ }
2161
+ for (let index = 0;index < each.length; index++) {
2162
+ await streamHydratableNodeToController(props.children(each[index], () => index), controller, encoder, ctx);
2163
+ }
2164
+ }
2165
+ async function streamHydratableIndexElement(element, controller, encoder, ctx) {
2166
+ const props = element.props;
2167
+ const each = readReactive4(props.each);
2168
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2169
+ if (props.fallback) {
2170
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2171
+ }
2172
+ return;
2173
+ }
2174
+ if (each.length === 0) {
2175
+ if (props.fallback) {
2176
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2177
+ }
2178
+ return;
2179
+ }
2180
+ for (let index = 0;index < each.length; index++) {
2181
+ await streamHydratableNodeToController(props.children(() => each[index], index), controller, encoder, ctx);
2182
+ }
2183
+ }
2184
+ function renderHydratableAttributes(props, ctx, isComponentRoot) {
2185
+ let attrs = "";
2186
+ if (isComponentRoot) {
2187
+ attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
2188
+ }
2189
+ const eventParts = [];
2190
+ for (const [key, value] of Object.entries(props)) {
2191
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
2192
+ continue;
2193
+ }
2194
+ if (isEventProp(key)) {
2195
+ eventParts.push(`${toEventName(key)}:${ctx.eventIndex++}`);
2196
+ continue;
2197
+ }
2198
+ const resolvedValue = readReactive4(value);
2199
+ if (resolvedValue == null || resolvedValue === false)
2200
+ continue;
2201
+ attrs += renderServerAttribute(key, resolvedValue);
2202
+ }
2203
+ if (eventParts.length > 0) {
2204
+ attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
2205
+ }
2206
+ return attrs;
2207
+ }
2208
+ function enqueue(controller, encoder, html) {
2209
+ controller.enqueue(encoder.encode(html));
2210
+ }
2211
+ async function streamForElement(element, controller, encoder) {
2212
+ const props = element.props;
2213
+ const each = readReactive4(props.each);
2214
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2215
+ if (props.fallback) {
2216
+ await streamNode(props.fallback, controller, encoder);
2217
+ }
2218
+ return;
2219
+ }
2220
+ if (each.length === 0) {
2221
+ if (props.fallback) {
2222
+ await streamNode(props.fallback, controller, encoder);
2223
+ }
2224
+ return;
2225
+ }
2226
+ for (let index = 0;index < each.length; index++) {
2227
+ await streamNode(props.children(each[index], () => index), controller, encoder);
2228
+ }
2229
+ }
2230
+ async function streamIndexElement(element, controller, encoder) {
2231
+ const props = element.props;
2232
+ const each = readReactive4(props.each);
2233
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2234
+ if (props.fallback) {
2235
+ await streamNode(props.fallback, controller, encoder);
2236
+ }
2237
+ return;
2238
+ }
2239
+ if (each.length === 0) {
2240
+ if (props.fallback) {
2241
+ await streamNode(props.fallback, controller, encoder);
2242
+ }
2243
+ return;
2244
+ }
2245
+ for (let index = 0;index < each.length; index++) {
2246
+ await streamNode(props.children(() => each[index], index), controller, encoder);
2247
+ }
2248
+ }
2249
+ function resolveShowChildren3(element, value) {
2250
+ const children = element.props.children ?? element.children;
2251
+ if (typeof children === "function") {
2252
+ return children(value);
2253
+ }
2254
+ return children;
2255
+ }
2256
+ function resolveSwitchContent3(element) {
2257
+ const props = element.props;
2258
+ const children = normalizeContent3(props.children ?? element.children);
2259
+ for (const child of children) {
2260
+ const match = getMatchElement3(child);
2261
+ if (!match) {
2262
+ continue;
2263
+ }
2264
+ const when = readReactive4(match.props.when);
2265
+ if (when) {
2266
+ return resolveMatchChildren3(match, when);
2267
+ }
2268
+ }
2269
+ return props.fallback;
2270
+ }
2271
+ function resolveMatchChildren3(element, value) {
2272
+ const children = element.props.children ?? element.children;
2273
+ if (typeof children === "function") {
2274
+ return children(value);
2275
+ }
2276
+ return children;
2277
+ }
2278
+ function resolveKeyChildren3(element, value) {
2279
+ const children = element.props.children ?? element.children;
2280
+ if (typeof children === "function") {
2281
+ return children(value);
2282
+ }
2283
+ return children;
2284
+ }
2285
+ function createDynamicElement3(element, tag) {
2286
+ if (typeof tag !== "string" && typeof tag !== "function") {
2287
+ return null;
2288
+ }
2289
+ const { component, ...props } = element.props;
2290
+ const children = normalizeContent3(props.children ?? element.children);
2291
+ return {
2292
+ tag,
2293
+ props,
2294
+ children
2295
+ };
2296
+ }
2297
+ function readReactive4(value) {
2298
+ return isSignal(value) || isComputed(value) ? value.value : value;
2299
+ }
2300
+ function normalizeContent3(content) {
2301
+ if (content == null || typeof content === "boolean") {
2302
+ return [];
2303
+ }
2304
+ return Array.isArray(content) ? content : [content];
2305
+ }
2306
+ function isElementLike3(value) {
2307
+ return value != null && typeof value === "object" && "tag" in value;
2308
+ }
2309
+ function getMatchElement3(value) {
2310
+ if (!isElementLike3(value)) {
2311
+ return null;
2312
+ }
2313
+ if (isMatchElement(value)) {
2314
+ return value;
2315
+ }
2316
+ return value.tag === Match ? Match(value.props) : null;
2317
+ }
2318
+ // src/server/hydration-markers.ts
2319
+ function createHydrationContext() {
2320
+ return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
2321
+ }
2322
+ async function renderToHydratableString(component, props) {
2323
+ const ctx = createHydrationContext();
2324
+ const mergedProps = props ?? {};
2325
+ const instance = createComponentInstance(component, mergedProps, null);
2326
+ const prev = setCurrentInstance(instance);
2327
+ try {
2328
+ const result = await component(mergedProps);
2329
+ if (result && typeof result === "object" && "tag" in result) {
2330
+ return renderElementH(result, ctx, true);
2331
+ }
2332
+ return renderNodeH(result, ctx);
2333
+ } finally {
2334
+ setCurrentInstance(prev);
2335
+ }
2336
+ }
2337
+ async function renderNodeToHydratableString(node) {
2338
+ const ctx = createHydrationContext();
2339
+ return renderNodeH(node, ctx);
2340
+ }
2341
+ var VOID_ELEMENTS5 = new Set([
2342
+ "area",
2343
+ "base",
2344
+ "br",
2345
+ "col",
2346
+ "embed",
2347
+ "hr",
2348
+ "img",
2349
+ "input",
2350
+ "link",
2351
+ "meta",
2352
+ "param",
2353
+ "source",
2354
+ "track",
2355
+ "wbr"
2356
+ ]);
2357
+ function renderNodeH(node, ctx) {
2358
+ if (node == null || typeof node === "boolean")
2359
+ return "";
2360
+ if (typeof node === "string")
2361
+ return escapeHtml(node);
2362
+ if (typeof node === "number")
2363
+ return String(node);
2364
+ if (node instanceof HtmlEscapedString)
2365
+ return node.value;
2366
+ if (isSignal(node) || isComputed(node)) {
2367
+ const value = node.value;
2368
+ const idx = ctx.textIndex++;
2369
+ return `${textMarkerOpen(idx)}${escapeHtml(String(value))}${textMarkerCloseStr()}`;
2370
+ }
2371
+ if (Array.isArray(node)) {
2372
+ return node.map((child) => renderNodeH(child, ctx)).join("");
2373
+ }
2374
+ if (node instanceof Promise) {
2375
+ return "";
2376
+ }
2377
+ if (typeof node === "object" && "tag" in node) {
2378
+ return renderElementH(node, ctx, false);
2379
+ }
2380
+ return escapeHtml(String(node));
2381
+ }
2382
+ function renderElementH(element, ctx, isComponentRoot) {
2383
+ const { tag, props, children } = element;
2384
+ if (tag === "") {
2385
+ return children.map((child) => renderNodeH(child, ctx)).join("");
2386
+ }
2387
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2388
+ return renderElementH(tag(props), ctx, isComponentRoot);
2389
+ }
2390
+ if (tag === Visible) {
2391
+ return renderElementH(tag(props), ctx, isComponentRoot);
2392
+ }
2393
+ if (isShowElement(element)) {
2394
+ const when = readReactive5(props.when);
2395
+ const content = when ? resolveShowChildren4(element, when) : props.fallback;
2396
+ return renderNodeMaybeRoot(content, ctx, isComponentRoot);
2397
+ }
2398
+ if (isForElement(element)) {
2399
+ return renderForElementH(element, ctx);
2400
+ }
2401
+ if (isSwitchElement(element)) {
2402
+ return renderNodeMaybeRoot(resolveSwitchContent4(element), ctx, isComponentRoot);
2403
+ }
2404
+ if (isMatchElement(element)) {
2405
+ const when = readReactive5(props.when);
2406
+ return renderNodeMaybeRoot(when ? resolveMatchChildren4(element, when) : null, ctx, isComponentRoot);
2407
+ }
2408
+ if (isIndexElement(element)) {
2409
+ return renderIndexElementH(element, ctx);
2410
+ }
2411
+ if (isKeyElement(element)) {
2412
+ const key = readReactive5(props.when);
2413
+ return renderNodeMaybeRoot(resolveKeyChildren4(element, key), ctx, isComponentRoot);
2414
+ }
2415
+ if (isDynamicElement(element)) {
2416
+ const dynamicTag = readReactive5(props.component);
2417
+ const dynamic = createDynamicElement4(element, dynamicTag);
2418
+ return dynamic ? renderElementH(dynamic, ctx, isComponentRoot) : "";
2419
+ }
2420
+ if (isPortalElement(element)) {
2421
+ return "";
2422
+ }
2423
+ if (typeof tag === "function") {
2424
+ return renderComponentH(tag, props, ctx);
2425
+ }
2426
+ if (typeof tag === "string") {
2427
+ return renderIntrinsicH(tag, props, children, ctx, isComponentRoot);
2428
+ }
2429
+ return children.map((child) => renderNodeH(child, ctx)).join("");
2430
+ }
2431
+ function renderComponentH(component, props, ctx) {
2432
+ const parentInstance = getCurrentInstance();
2433
+ const instance = createComponentInstance(component, props, parentInstance);
2434
+ if (parentInstance) {
2435
+ parentInstance.children.push(instance);
2436
+ }
2437
+ const prev = setCurrentInstance(instance);
2438
+ try {
2439
+ const result = component(props);
2440
+ if (result && typeof result === "object" && "tag" in result) {
2441
+ return renderElementH(result, ctx, true);
2442
+ }
2443
+ return renderNodeH(result, ctx);
2444
+ } finally {
2445
+ setCurrentInstance(prev);
2446
+ }
2447
+ }
2448
+ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
2449
+ let attrs = "";
2450
+ if (isComponentRoot) {
2451
+ attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
2452
+ }
2453
+ const eventParts = [];
2454
+ for (const [key, value] of Object.entries(props)) {
2455
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
2456
+ continue;
2457
+ }
2458
+ if (isEventProp(key)) {
2459
+ const eventName = toEventName(key);
2460
+ eventParts.push(`${eventName}:${ctx.eventIndex++}`);
2461
+ continue;
2462
+ }
2463
+ if (value == null || value === false)
2464
+ continue;
2465
+ let resolvedValue = value;
2466
+ if (isSignal(value) || isComputed(value)) {
2467
+ resolvedValue = value.value;
2468
+ }
2469
+ attrs += renderServerAttribute(key, resolvedValue);
2470
+ }
2471
+ if (eventParts.length > 0) {
2472
+ attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
2473
+ }
2474
+ if (VOID_ELEMENTS5.has(tag)) {
2475
+ return `<${tag}${attrs}>`;
2476
+ }
2477
+ const dangerous = props.dangerouslySetInnerHTML;
2478
+ if (dangerous && typeof dangerous.__html === "string") {
2479
+ return `<${tag}${attrs}>${dangerous.__html}</${tag}>`;
2480
+ }
2481
+ const childrenHtml = children.map((child) => renderNodeH(child, ctx)).join("");
2482
+ return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
2483
+ }
2484
+ function renderNodeMaybeRoot(node, ctx, isComponentRoot) {
2485
+ if (isComponentRoot && node && typeof node === "object" && !Array.isArray(node) && "tag" in node) {
2486
+ return renderElementH(node, ctx, true);
1153
2487
  }
1154
- if (isSignal(node) || isComputed(node)) {
1155
- const text2 = domOps.createTextNode(String(node.value));
1156
- insertNode(parent, text2, anchor);
1157
- const dispose = effect(() => {
1158
- domOps.setTextContent(text2, String(node.value));
1159
- });
1160
- return { type: "reactive-text", node: text2, dispose };
2488
+ return renderNodeH(node, ctx);
2489
+ }
2490
+ function renderForElementH(element, ctx) {
2491
+ const props = element.props;
2492
+ const each = readReactive5(props.each);
2493
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2494
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1161
2495
  }
1162
- if (Array.isArray(node)) {
1163
- return renderArrayToDOM(node, parent, anchor);
2496
+ if (each.length === 0) {
2497
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1164
2498
  }
1165
- if (node instanceof Promise) {
1166
- const placeholder = domOps.createTextNode("");
1167
- insertNode(parent, placeholder, anchor);
1168
- node.then((resolved) => {
1169
- const mounted = renderNodeToDOM(resolved, parent, placeholder);
1170
- domOps.remove(placeholder);
1171
- });
1172
- return { type: "text", node: placeholder };
2499
+ return each.map((item, index) => renderNodeH(props.children(item, () => index), ctx)).join("");
2500
+ }
2501
+ function renderIndexElementH(element, ctx) {
2502
+ const props = element.props;
2503
+ const each = readReactive5(props.each);
2504
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2505
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1173
2506
  }
1174
- if (typeof node === "object" && "tag" in node) {
1175
- return renderElementToDOM(node, parent, anchor);
2507
+ if (each.length === 0) {
2508
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1176
2509
  }
1177
- const text = domOps.createTextNode(String(node));
1178
- insertNode(parent, text, anchor);
1179
- return { type: "text", node: text };
2510
+ return each.map((item, index) => renderNodeH(props.children(() => item, index), ctx)).join("");
1180
2511
  }
1181
- function renderArrayToDOM(nodes, parent, anchor) {
1182
- const anchorComment = domOps.createComment("Sinwan-f");
1183
- insertNode(parent, anchorComment, anchor);
1184
- const children = [];
1185
- for (const child of nodes) {
1186
- children.push(renderNodeToDOM(child, parent, anchor));
2512
+ function resolveShowChildren4(element, value) {
2513
+ const children = element.props.children ?? element.children;
2514
+ if (typeof children === "function") {
2515
+ return children(value);
1187
2516
  }
1188
- return { type: "fragment", children, anchor: anchorComment };
2517
+ return children;
1189
2518
  }
1190
- function renderChildrenToDOM(children, parent) {
1191
- const mounted = [];
2519
+ function resolveSwitchContent4(element) {
2520
+ const props = element.props;
2521
+ const children = normalizeContent4(props.children ?? element.children);
1192
2522
  for (const child of children) {
1193
- mounted.push(renderNodeToDOM(child, parent));
2523
+ const match = getMatchElement4(child);
2524
+ if (!match) {
2525
+ continue;
2526
+ }
2527
+ const when = readReactive5(match.props.when);
2528
+ if (when) {
2529
+ return resolveMatchChildren4(match, when);
2530
+ }
1194
2531
  }
1195
- return mounted;
2532
+ return props.fallback;
1196
2533
  }
1197
- function insertNode(parent, child, anchor) {
1198
- if (anchor) {
1199
- domOps.insertBefore(parent, child, anchor);
1200
- } else {
1201
- domOps.appendChild(parent, child);
2534
+ function resolveMatchChildren4(element, value) {
2535
+ const children = element.props.children ?? element.children;
2536
+ if (typeof children === "function") {
2537
+ return children(value);
1202
2538
  }
2539
+ return children;
1203
2540
  }
1204
-
1205
- // src/renderer/mount.ts
1206
- function mount(component, container, props) {
1207
- container.innerHTML = "";
1208
- const mergedProps = props ?? {};
1209
- const instance = createComponentInstance(component, mergedProps, null);
1210
- let result;
1211
- let root;
1212
- setCurrentInstance(instance);
1213
- try {
1214
- result = component(mergedProps);
1215
- if (result instanceof Promise) {
1216
- const placeholder = document.createTextNode("");
1217
- container.appendChild(placeholder);
1218
- root = { type: "text", node: placeholder };
1219
- result.then((resolved) => {
1220
- container.innerHTML = "";
1221
- setCurrentInstance(instance);
1222
- root = renderElementToDOM(resolved, container);
1223
- setCurrentInstance(null);
1224
- instance.element = root;
1225
- fireMountedHooks(instance);
1226
- });
1227
- } else if (result && typeof result === "object" && "tag" in result) {
1228
- root = renderElementToDOM(result, container);
1229
- } else {
1230
- root = renderNodeToDOM(result, container);
1231
- }
1232
- } catch (err) {
1233
- setCurrentInstance(null);
1234
- handleComponentError(instance, err);
1235
- return {
1236
- root: { type: "text", node: document.createTextNode("") },
1237
- unmount() {}
1238
- };
2541
+ function resolveKeyChildren4(element, value) {
2542
+ const children = element.props.children ?? element.children;
2543
+ if (typeof children === "function") {
2544
+ return children(value);
1239
2545
  }
1240
- setCurrentInstance(null);
1241
- instance.element = root;
1242
- fireMountedHooks(instance);
1243
- return {
1244
- root,
1245
- unmount() {
1246
- fireUnmountedHooks(instance);
1247
- unmountNode(root);
1248
- container.innerHTML = "";
1249
- }
1250
- };
2546
+ return children;
1251
2547
  }
1252
- function render(node, container) {
1253
- container.innerHTML = "";
1254
- const root = renderNodeToDOM(node, container);
2548
+ function createDynamicElement4(element, tag) {
2549
+ if (typeof tag !== "string" && typeof tag !== "function") {
2550
+ return null;
2551
+ }
2552
+ const { component, ...props } = element.props;
2553
+ const children = normalizeContent4(props.children ?? element.children);
1255
2554
  return {
1256
- root,
1257
- unmount() {
1258
- unmountNode(root);
1259
- container.innerHTML = "";
1260
- }
2555
+ tag,
2556
+ props,
2557
+ children
1261
2558
  };
1262
2559
  }
1263
- function unmountNode(node) {
1264
- switch (node.type) {
1265
- case "text":
1266
- break;
1267
- case "reactive-text":
1268
- node.dispose();
1269
- break;
1270
- case "element":
1271
- for (const dispose of node.attrDisposers) {
1272
- dispose();
1273
- }
1274
- for (const cleanup of node.eventCleanups) {
1275
- cleanup();
1276
- }
1277
- for (const child of node.children) {
1278
- unmountNode(child);
1279
- }
1280
- break;
1281
- case "fragment":
1282
- for (const child of node.children) {
1283
- unmountNode(child);
1284
- }
1285
- break;
1286
- case "reactive-block":
1287
- node.dispose();
1288
- for (const child of node.children) {
1289
- unmountNode(child);
1290
- }
1291
- break;
1292
- case "component":
1293
- if (node.instance) {
1294
- fireUnmountedHooks(node.instance);
1295
- } else {
1296
- for (const dispose of node.disposers) {
1297
- dispose();
1298
- }
1299
- }
1300
- for (const child of node.children) {
1301
- unmountNode(child);
1302
- }
1303
- break;
2560
+ function readReactive5(value) {
2561
+ return isSignal(value) || isComputed(value) ? value.value : value;
2562
+ }
2563
+ function normalizeContent4(content) {
2564
+ if (content == null || typeof content === "boolean") {
2565
+ return [];
2566
+ }
2567
+ return Array.isArray(content) ? content : [content];
2568
+ }
2569
+ function isElementLike4(value) {
2570
+ return value != null && typeof value === "object" && "tag" in value;
2571
+ }
2572
+ function getMatchElement4(value) {
2573
+ if (!isElementLike4(value)) {
2574
+ return null;
2575
+ }
2576
+ if (isMatchElement(value)) {
2577
+ return value;
2578
+ }
2579
+ return value.tag === Match ? Match(value.props) : null;
2580
+ }
2581
+ // src/component/lifecycle.ts
2582
+ function onMounted(fn) {
2583
+ const instance = getCurrentInstance();
2584
+ if (!instance) {
2585
+ throw new Error("onMounted() called outside of component setup.");
2586
+ }
2587
+ instance._mountedHooks.push(() => withInstance(instance, fn));
2588
+ }
2589
+ function onUnmounted(fn) {
2590
+ const instance = getCurrentInstance();
2591
+ if (!instance) {
2592
+ throw new Error("onUnmounted() called outside of component setup.");
2593
+ }
2594
+ instance._unmountedHooks.push(() => withInstance(instance, fn));
2595
+ }
2596
+ function onUpdated(fn) {
2597
+ const instance = getCurrentInstance();
2598
+ if (!instance) {
2599
+ throw new Error("onUpdated() called outside of component setup.");
2600
+ }
2601
+ instance._updatedHooks.push(() => withInstance(instance, fn));
2602
+ }
2603
+ function onError(fn) {
2604
+ const instance = getCurrentInstance();
2605
+ if (!instance) {
2606
+ throw new Error("onError() called outside of component setup.");
2607
+ }
2608
+ instance._errorHooks.push((err) => withInstance(instance, () => fn(err)));
2609
+ }
2610
+ // src/component/create.ts
2611
+ function createComponent(fn) {
2612
+ const component = (props) => fn(props);
2613
+ component._SinwanComponent = true;
2614
+ component._displayName = fn.name || "AnonymousComponent";
2615
+ return component;
2616
+ }
2617
+ function createPage(fn) {
2618
+ const page = (data) => fn(data);
2619
+ page._SinwanPage = true;
2620
+ page._displayName = fn.name || "AnonymousPage";
2621
+ return page;
2622
+ }
2623
+ function createLayout(fn) {
2624
+ return createComponent(fn);
2625
+ }
2626
+ // src/component/provide-inject.ts
2627
+ function provide(key, value) {
2628
+ const instance = getCurrentInstance();
2629
+ if (!instance) {
2630
+ throw new Error("provide() called outside of component setup.");
1304
2631
  }
2632
+ instance.provides[key] = value;
2633
+ }
2634
+ function inject(key, defaultValue) {
2635
+ const instance = getCurrentInstance();
2636
+ if (!instance) {
2637
+ throw new Error("inject() called outside of component setup.");
2638
+ }
2639
+ if (key in instance.provides) {
2640
+ return instance.provides[key];
2641
+ }
2642
+ if (arguments.length >= 2) {
2643
+ return defaultValue;
2644
+ }
2645
+ console.warn(`[Sinwan] inject() key "${String(key)}" not found and no default provided.`);
2646
+ return;
1305
2647
  }
1306
2648
  // src/hydration/walk.ts
1307
2649
  function advance(cursor) {
@@ -1342,6 +2684,7 @@ function hydrateNode(node, cursor) {
1342
2684
  }
1343
2685
  function hydrateReactiveText(reactive, cursor) {
1344
2686
  const openComment = cursor.current;
2687
+ const owner = getCurrentInstance();
1345
2688
  if (openComment && openComment.nodeType === 8 && parseTextOpenMarker(openComment) >= 0) {
1346
2689
  advance(cursor);
1347
2690
  const textNode2 = advance(cursor);
@@ -1349,21 +2692,36 @@ function hydrateReactiveText(reactive, cursor) {
1349
2692
  if (closeComment && closeComment.nodeType === 8 && isTextCloseMarker(closeComment)) {
1350
2693
  advance(cursor);
1351
2694
  }
2695
+ let initialized2 = false;
1352
2696
  const dispose2 = effect(() => {
1353
2697
  textNode2.data = String(reactive.value);
2698
+ if (initialized2) {
2699
+ queueUpdatedHooks(owner);
2700
+ }
2701
+ initialized2 = true;
1354
2702
  });
1355
2703
  return { type: "reactive-text", node: textNode2, dispose: dispose2 };
1356
2704
  }
1357
2705
  const textNode = advance(cursor);
1358
2706
  if (textNode) {
2707
+ let initialized2 = false;
1359
2708
  const dispose2 = effect(() => {
1360
2709
  textNode.data = String(reactive.value);
2710
+ if (initialized2) {
2711
+ queueUpdatedHooks(owner);
2712
+ }
2713
+ initialized2 = true;
1361
2714
  });
1362
2715
  return { type: "reactive-text", node: textNode, dispose: dispose2 };
1363
2716
  }
1364
2717
  const newText = document.createTextNode(String(reactive.value));
2718
+ let initialized = false;
1365
2719
  const dispose = effect(() => {
1366
2720
  newText.data = String(reactive.value);
2721
+ if (initialized) {
2722
+ queueUpdatedHooks(owner);
2723
+ }
2724
+ initialized = true;
1367
2725
  });
1368
2726
  return { type: "reactive-text", node: newText, dispose };
1369
2727
  }
@@ -1372,6 +2730,18 @@ function hydrateElement(element, cursor) {
1372
2730
  if (tag === "") {
1373
2731
  return hydrateArray(children, cursor);
1374
2732
  }
2733
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2734
+ return hydrateElement(tag(props), cursor);
2735
+ }
2736
+ if (tag === Visible) {
2737
+ return hydrateElement(tag(props), cursor);
2738
+ }
2739
+ if (isPortalElement(element)) {
2740
+ return renderControlFlowToDOM(element, cursor.parent, cursor.current, null);
2741
+ }
2742
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element)) {
2743
+ return hydrateControlFlow(element, cursor);
2744
+ }
1375
2745
  if (typeof tag === "function") {
1376
2746
  return hydrateComponent(tag, props, cursor);
1377
2747
  }
@@ -1390,6 +2760,7 @@ function hydrateIntrinsic(tag, props, children, cursor) {
1390
2760
  el.removeAttribute("data-sinwan-ev");
1391
2761
  const attrDisposers = hydrateAttributes(el, props);
1392
2762
  const eventCleanups = bindEvents(el, props);
2763
+ const refCleanup = applyRef2(el, props.ref);
1393
2764
  const childCursor = {
1394
2765
  parent: el,
1395
2766
  current: el.firstChild
@@ -1403,31 +2774,155 @@ function hydrateIntrinsic(tag, props, children, cursor) {
1403
2774
  node: el,
1404
2775
  children: mountedChildren,
1405
2776
  eventCleanups,
1406
- attrDisposers
2777
+ attrDisposers,
2778
+ refCleanup
1407
2779
  };
1408
2780
  }
1409
2781
  function hydrateAttributes(el, props) {
1410
2782
  const disposers = [];
2783
+ const owner = getCurrentInstance();
1411
2784
  for (const [key, value] of Object.entries(props)) {
1412
- if (key === "children" || key === "key" || key === "ref" || isEventProp(key))
2785
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key))
1413
2786
  continue;
1414
2787
  if (isSignal(value) || isComputed(value)) {
2788
+ const state = { previousStyleProps: new Set };
2789
+ let initialized = false;
1415
2790
  const dispose = effect(() => {
1416
- const v = value.value;
1417
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1418
- if (v == null || v === false) {
1419
- el.removeAttribute(attrName);
1420
- } else if (v === true) {
1421
- el.setAttribute(attrName, "");
1422
- } else {
1423
- el.setAttribute(attrName, String(v));
2791
+ setSingleAttribute(el, key, value.value, state);
2792
+ if (initialized) {
2793
+ queueUpdatedHooks(owner);
1424
2794
  }
2795
+ initialized = true;
1425
2796
  });
1426
2797
  disposers.push(dispose);
1427
2798
  }
1428
2799
  }
1429
2800
  return disposers;
1430
2801
  }
2802
+ function hydrateControlFlow(element, cursor) {
2803
+ if (isShowElement(element)) {
2804
+ const when = readReactive6(element.props.when);
2805
+ const content = when ? resolveShowChildren5(element, when) : element.props.fallback;
2806
+ return hydrateContent(content, cursor);
2807
+ }
2808
+ if (isForElement(element)) {
2809
+ const props = element.props;
2810
+ const items = readReactive6(props.each);
2811
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(item, () => index)) : props.fallback ? [props.fallback] : [];
2812
+ return hydrateArray(children, cursor);
2813
+ }
2814
+ if (isSwitchElement(element)) {
2815
+ return hydrateContent(resolveSwitchContent5(element), cursor);
2816
+ }
2817
+ if (isIndexElement(element)) {
2818
+ const props = element.props;
2819
+ const items = readReactive6(props.each);
2820
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(() => item, index)) : props.fallback ? [props.fallback] : [];
2821
+ return hydrateArray(children, cursor);
2822
+ }
2823
+ if (isKeyElement(element)) {
2824
+ const key = readReactive6(element.props.when);
2825
+ return hydrateContent(resolveKeyChildren5(element, key), cursor);
2826
+ }
2827
+ if (isDynamicElement(element)) {
2828
+ const tag = readReactive6(element.props.component);
2829
+ const dynamic = createDynamicElement5(element, tag);
2830
+ return dynamic ? hydrateElement(dynamic, cursor) : hydrateArray([], cursor);
2831
+ }
2832
+ return hydrateArray(element.children, cursor);
2833
+ }
2834
+ function hydrateContent(content, cursor) {
2835
+ if (content == null || typeof content === "boolean") {
2836
+ return hydrateArray([], cursor);
2837
+ }
2838
+ return Array.isArray(content) ? hydrateArray(content, cursor) : hydrateNode(content, cursor);
2839
+ }
2840
+ function resolveShowChildren5(element, value) {
2841
+ const children = element.props.children ?? element.children;
2842
+ if (typeof children === "function") {
2843
+ return children(value);
2844
+ }
2845
+ return children;
2846
+ }
2847
+ function resolveSwitchContent5(element) {
2848
+ const props = element.props;
2849
+ const children = normalizeContent5(props.children ?? element.children);
2850
+ for (const child of children) {
2851
+ const match = getMatchElement5(child);
2852
+ if (!match) {
2853
+ continue;
2854
+ }
2855
+ const when = readReactive6(match.props.when);
2856
+ if (when) {
2857
+ return resolveMatchChildren5(match, when);
2858
+ }
2859
+ }
2860
+ return props.fallback;
2861
+ }
2862
+ function resolveMatchChildren5(element, value) {
2863
+ const children = element.props.children ?? element.children;
2864
+ if (typeof children === "function") {
2865
+ return children(value);
2866
+ }
2867
+ return children;
2868
+ }
2869
+ function resolveKeyChildren5(element, value) {
2870
+ const children = element.props.children ?? element.children;
2871
+ if (typeof children === "function") {
2872
+ return children(value);
2873
+ }
2874
+ return children;
2875
+ }
2876
+ function createDynamicElement5(element, tag) {
2877
+ if (typeof tag !== "string" && typeof tag !== "function") {
2878
+ return null;
2879
+ }
2880
+ const { component, ...props } = element.props;
2881
+ const children = normalizeContent5(props.children ?? element.children);
2882
+ return {
2883
+ tag,
2884
+ props,
2885
+ children
2886
+ };
2887
+ }
2888
+ function readReactive6(value) {
2889
+ return isSignal(value) || isComputed(value) ? value.value : value;
2890
+ }
2891
+ function normalizeContent5(content) {
2892
+ if (content == null || typeof content === "boolean") {
2893
+ return [];
2894
+ }
2895
+ return Array.isArray(content) ? content : [content];
2896
+ }
2897
+ function isElementLike5(value) {
2898
+ return value != null && typeof value === "object" && "tag" in value;
2899
+ }
2900
+ function getMatchElement5(value) {
2901
+ if (!isElementLike5(value)) {
2902
+ return null;
2903
+ }
2904
+ if (isMatchElement(value)) {
2905
+ return value;
2906
+ }
2907
+ return value.tag === Match ? Match(value.props) : null;
2908
+ }
2909
+ function applyRef2(el, ref) {
2910
+ const value = ref;
2911
+ if (!value) {
2912
+ return null;
2913
+ }
2914
+ if (typeof value === "function") {
2915
+ value(el);
2916
+ return () => value(null);
2917
+ }
2918
+ if (typeof value === "object" && "current" in value) {
2919
+ value.current = el;
2920
+ return () => {
2921
+ value.current = null;
2922
+ };
2923
+ }
2924
+ return null;
2925
+ }
1431
2926
  function hydrateComponent(component, props, cursor) {
1432
2927
  const parentInstance = getCurrentInstance();
1433
2928
  const instance = createComponentInstance(component, props, parentInstance);
@@ -1516,8 +3011,12 @@ function hydrate(component, container, props) {
1516
3011
  export {
1517
3012
  unmountNode,
1518
3013
  streamPage,
3014
+ streamHydratablePage,
3015
+ streamHydratableNode,
1519
3016
  signal,
3017
+ setDOMOps,
1520
3018
  safeHtml,
3019
+ resetDOMOps,
1521
3020
  renderToString,
1522
3021
  renderToHydratableString,
1523
3022
  renderPage,
@@ -1547,14 +3046,24 @@ export {
1547
3046
  getCurrentInstance,
1548
3047
  escapeHtml,
1549
3048
  effect,
3049
+ domOps,
1550
3050
  createPage,
1551
3051
  createLayout,
1552
3052
  createComponent,
1553
3053
  computed,
1554
3054
  batch,
3055
+ Visible,
3056
+ Switch,
3057
+ Show,
3058
+ Portal,
3059
+ Match,
3060
+ Key,
3061
+ Index,
1555
3062
  HtmlEscapedString,
1556
- Fragment
3063
+ Fragment,
3064
+ For,
3065
+ Dynamic
1557
3066
  };
1558
3067
 
1559
- //# debugId=37C387A0B7C368DE64756E2164756E21
3068
+ //# debugId=5F7C902C8127620064756E2164756E21
1560
3069
  //# sourceMappingURL=index.development.js.map