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
@@ -87,22 +87,12 @@ function buildElement(type, props, children) {
87
87
  if (type === Fragment) {
88
88
  return { tag: "", props: {}, children };
89
89
  }
90
- if (typeof type === "function") {
91
- if (type._SinwanComponent || type._SinwanPage) {
92
- const result2 = type(props);
93
- if (result2 && typeof result2 === "object" && "tag" in result2) {
94
- return result2;
95
- }
96
- return { tag: "", props: {}, children: normalizeChildren(result2) };
97
- }
98
- const result = type(props);
99
- if (result && typeof result === "object" && "tag" in result) {
100
- return result;
90
+ if (typeof type === "function" || typeof type === "string") {
91
+ const finalProps = props ?? {};
92
+ if (children.length > 0 && finalProps.children === undefined) {
93
+ finalProps.children = children.length === 1 ? children[0] : children;
101
94
  }
102
- return { tag: "", props: {}, children: normalizeChildren(result) };
103
- }
104
- if (typeof type === "string") {
105
- return { tag: type, props: props || {}, children };
95
+ return { tag: type, props: finalProps, children };
106
96
  }
107
97
  return { tag: "", props: {}, children };
108
98
  }
@@ -126,6 +116,8 @@ function jsxDEV(type, props, key, isStaticChildren, source, self) {
126
116
  var exports_server = {};
127
117
  __export(exports_server, {
128
118
  streamPage: () => streamPage,
119
+ streamHydratablePage: () => streamHydratablePage,
120
+ streamHydratableNode: () => streamHydratableNode,
129
121
  renderToString: () => renderToString,
130
122
  renderToHydratableString: () => renderToHydratableString,
131
123
  renderPage: () => renderPage,
@@ -171,221 +163,37 @@ function isSafeHtml(value) {
171
163
  return value instanceof HtmlEscapedString;
172
164
  }
173
165
 
174
- // src/server/renderer.ts
175
- var componentCache = new WeakMap;
176
- var pageRegistry = new Map;
177
- function registerPage(name, page) {
178
- pageRegistry.set(name, page);
179
- }
180
- function getPage(name) {
181
- return pageRegistry.get(name);
182
- }
183
- function hasPage(name) {
184
- return pageRegistry.has(name);
185
- }
186
- async function renderPage(name, data) {
187
- const page = getPage(name);
188
- if (!page) {
189
- throw new Error(`Page "${name}" not found in registry`);
190
- }
191
- const element = await page(data);
192
- return renderToString(element);
193
- }
194
- async function renderToString(node) {
195
- if (node == null || typeof node === "boolean") {
166
+ // src/server/attribute-utils.ts
167
+ var PROP_ALIASES = {
168
+ className: "class",
169
+ htmlFor: "for",
170
+ tabIndex: "tabindex",
171
+ crossOrigin: "crossorigin"
172
+ };
173
+ function renderServerAttribute(key, value) {
174
+ const attrName = PROP_ALIASES[key] ?? key;
175
+ if (value == null || value === false) {
196
176
  return "";
197
177
  }
198
- if (typeof node === "string") {
199
- return escapeHtml(node);
200
- }
201
- if (typeof node === "number") {
202
- return String(node);
203
- }
204
- if (node instanceof HtmlEscapedString) {
205
- return node.value;
206
- }
207
- if (Array.isArray(node)) {
208
- const results = await Promise.all(node.map((child) => renderToString(child)));
209
- return results.join("");
210
- }
211
- if (node instanceof Promise) {
212
- return renderElement(await node);
213
- }
214
- return renderElement(node);
215
- }
216
- async function renderElement(element) {
217
- const { tag, props, children } = element;
218
- if (typeof tag === "function") {
219
- const result = await tag(props);
220
- return renderToString(result);
221
- }
222
- if (typeof tag === "string") {
223
- return renderIntrinsicElement(tag, props, children);
224
- }
225
- return renderToString(children);
226
- }
227
- var VOID_ELEMENTS2 = new Set([
228
- "area",
229
- "base",
230
- "br",
231
- "col",
232
- "embed",
233
- "hr",
234
- "img",
235
- "input",
236
- "link",
237
- "meta",
238
- "param",
239
- "source",
240
- "track",
241
- "wbr"
242
- ]);
243
- async function renderIntrinsicElement(tag, props, children) {
244
- const attrs = renderAttributes(props);
245
- if (VOID_ELEMENTS2.has(tag)) {
246
- return attrs ? `<${tag}${attrs}>` : `<${tag}>`;
247
- }
248
- const childrenHtml = await renderChildren(children, props);
249
- return attrs ? `<${tag}${attrs}>${childrenHtml}</${tag}>` : `<${tag}>${childrenHtml}</${tag}>`;
250
- }
251
- function renderAttributes(props) {
252
- let attrs = "";
253
- for (const [key, value] of Object.entries(props)) {
254
- if (key === "children")
255
- continue;
256
- if (value == null || value === false)
257
- continue;
258
- if (value === true) {
259
- attrs += ` ${key}`;
260
- continue;
261
- }
262
- if (key === "dangerouslySetInnerHTML") {
263
- continue;
264
- }
265
- const attrName = key === "className" ? "class" : key;
266
- const finalName = attrName === "htmlFor" ? "for" : attrName;
267
- const attrValue = escapeHtml(String(value));
268
- attrs += ` ${finalName}="${attrValue}"`;
269
- }
270
- return attrs;
271
- }
272
- async function renderChildren(children, props) {
273
- const dangerous = props.dangerouslySetInnerHTML;
274
- if (dangerous && typeof dangerous.__html === "string") {
275
- return dangerous.__html;
276
- }
277
- return renderToString(children);
278
- }
279
- function isSlots(children) {
280
- return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
281
- }
282
- // src/server/stream.ts
283
- var VOID_ELEMENTS3 = new Set([
284
- "area",
285
- "base",
286
- "br",
287
- "col",
288
- "embed",
289
- "hr",
290
- "img",
291
- "input",
292
- "link",
293
- "meta",
294
- "param",
295
- "source",
296
- "track",
297
- "wbr"
298
- ]);
299
- function streamPage(page, data) {
300
- const encoder = new TextEncoder;
301
- return new ReadableStream({
302
- async start(controller) {
303
- try {
304
- const element = await page(data);
305
- await streamNode(element, controller, encoder);
306
- controller.close();
307
- } catch (error) {
308
- controller.error(error);
309
- }
310
- }
311
- });
312
- }
313
- async function streamNode(node, controller, encoder) {
314
- if (node == null || typeof node === "boolean") {
315
- return;
316
- }
317
- if (typeof node === "string") {
318
- controller.enqueue(encoder.encode(escapeHtml(node)));
319
- return;
320
- }
321
- if (typeof node === "number") {
322
- controller.enqueue(encoder.encode(String(node)));
323
- return;
324
- }
325
- if (node instanceof HtmlEscapedString) {
326
- controller.enqueue(encoder.encode(node.value));
327
- return;
328
- }
329
- if (Array.isArray(node)) {
330
- for (const child of node) {
331
- await streamNode(child, controller, encoder);
332
- }
333
- return;
334
- }
335
- if (node instanceof Promise) {
336
- const resolved = await node;
337
- await streamElement(resolved, controller, encoder);
338
- return;
178
+ if (value === true) {
179
+ return ` ${attrName}`;
339
180
  }
340
- await streamElement(node, controller, encoder);
181
+ const attrValue = attrName === "class" && typeof value === "object" ? stringifyClass(value) : attrName === "style" && typeof value === "object" ? stringifyStyle(value) : String(value);
182
+ return ` ${attrName}="${escapeHtml(attrValue)}"`;
341
183
  }
342
- async function streamElement(element, controller, encoder) {
343
- const { tag, props, children } = element;
344
- if (typeof tag === "function") {
345
- const result = await tag(props);
346
- await streamNode(result, controller, encoder);
347
- return;
348
- }
349
- if (typeof tag === "string") {
350
- await streamIntrinsicElement(tag, props, children, controller, encoder);
351
- return;
184
+ function stringifyClass(value) {
185
+ if (Array.isArray(value)) {
186
+ return value.filter(Boolean).join(" ");
352
187
  }
353
- await streamNode(children, controller, encoder);
188
+ return Object.entries(value).filter(([, enabled]) => Boolean(enabled)).map(([name]) => name).join(" ");
354
189
  }
355
- async function streamIntrinsicElement(tag, props, children, controller, encoder) {
356
- const attrs = renderAttributes2(props);
357
- const dangerous = props.dangerouslySetInnerHTML;
358
- if (VOID_ELEMENTS3.has(tag)) {
359
- const html = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
360
- controller.enqueue(encoder.encode(html));
361
- return;
362
- }
363
- const openTag = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
364
- controller.enqueue(encoder.encode(openTag));
365
- if (dangerous && typeof dangerous.__html === "string") {
366
- controller.enqueue(encoder.encode(dangerous.__html));
367
- } else {
368
- await streamNode(children, controller, encoder);
369
- }
370
- controller.enqueue(encoder.encode(`</${tag}>`));
190
+ function stringifyStyle(value) {
191
+ return Object.entries(value).filter(([, val]) => val != null && val !== false).map(([prop, val]) => `${toKebabCase(prop)}:${String(val)}`).join(";");
371
192
  }
372
- function renderAttributes2(props) {
373
- let attrs = "";
374
- for (const [key, value] of Object.entries(props)) {
375
- if (key === "children" || key === "dangerouslySetInnerHTML")
376
- continue;
377
- if (value == null || value === false)
378
- continue;
379
- if (value === true) {
380
- attrs += ` ${key}`;
381
- continue;
382
- }
383
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
384
- const attrValue = escapeHtml(String(value));
385
- attrs += ` ${attrName}="${attrValue}"`;
386
- }
387
- return attrs;
193
+ function toKebabCase(value) {
194
+ return value.includes("-") ? value : value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
388
195
  }
196
+
389
197
  // src/reactivity/scheduler.ts
390
198
  var pendingEffects = new Set;
391
199
  var flushScheduled = false;
@@ -628,79 +436,68 @@ function isComputed(value) {
628
436
  return value != null && typeof value === "object" && COMPUTED_BRAND in value;
629
437
  }
630
438
 
631
- // src/hydration/markers.ts
632
- var COMP_ID_ATTR = "data-sinwan-id";
633
- var COMP_ID_PREFIX = "c";
634
- var TEXT_MARKER_OPEN = "sinwan-t:";
635
- var TEXT_MARKER_CLOSE = "/sinwan-t";
636
- var EVENT_ATTR = "data-sinwan-ev";
637
- function compId(index) {
638
- return `${COMP_ID_PREFIX}${index}`;
639
- }
640
- function textMarkerOpen(index) {
641
- return `<!--${TEXT_MARKER_OPEN}${index}-->`;
439
+ // src/renderer/dom-ops.ts
440
+ function createDefaultDOMOps() {
441
+ return {
442
+ createElement(tag) {
443
+ return document.createElement(tag);
444
+ },
445
+ createElementNS(namespace, tag) {
446
+ return document.createElementNS(namespace, tag);
447
+ },
448
+ createTextNode(text) {
449
+ return document.createTextNode(text);
450
+ },
451
+ createComment(text) {
452
+ return document.createComment(text);
453
+ },
454
+ setAttribute(el, key, value) {
455
+ el.setAttribute(key, value);
456
+ },
457
+ removeAttribute(el, key) {
458
+ el.removeAttribute(key);
459
+ },
460
+ setProperty(el, key, value) {
461
+ el[key] = value;
462
+ },
463
+ insertBefore(parent, child, anchor) {
464
+ parent.insertBefore(child, anchor);
465
+ },
466
+ appendChild(parent, child) {
467
+ parent.appendChild(child);
468
+ },
469
+ remove(node) {
470
+ node.parentNode?.removeChild(node);
471
+ },
472
+ setTextContent(node, text) {
473
+ node.data = text;
474
+ },
475
+ addEventListener(el, event, handler) {
476
+ el.addEventListener(event, handler);
477
+ },
478
+ removeEventListener(el, event, handler) {
479
+ el.removeEventListener(event, handler);
480
+ },
481
+ parentNode(node) {
482
+ return node.parentNode;
483
+ },
484
+ nextSibling(node) {
485
+ return node.nextSibling;
486
+ }
487
+ };
642
488
  }
643
- function textMarkerCloseStr() {
644
- return `<!--${TEXT_MARKER_CLOSE}-->`;
489
+ var defaultDOMOps = createDefaultDOMOps();
490
+ var domOps = { ...defaultDOMOps };
491
+ function setDOMOps(overrides) {
492
+ Object.assign(domOps, overrides);
645
493
  }
646
- function parseTextOpenMarker(node) {
647
- const data = node.data;
648
- if (data.startsWith(TEXT_MARKER_OPEN)) {
649
- const idx = parseInt(data.slice(TEXT_MARKER_OPEN.length), 10);
650
- return Number.isNaN(idx) ? -1 : idx;
494
+ function resetDOMOps() {
495
+ for (const key of Object.keys(domOps)) {
496
+ delete domOps[key];
651
497
  }
652
- return -1;
653
- }
654
- function isTextCloseMarker(node) {
655
- return node.data === TEXT_MARKER_CLOSE;
498
+ Object.assign(domOps, defaultDOMOps);
656
499
  }
657
500
 
658
- // src/renderer/dom-ops.ts
659
- var domOps = {
660
- createElement(tag) {
661
- return document.createElement(tag);
662
- },
663
- createTextNode(text) {
664
- return document.createTextNode(text);
665
- },
666
- createComment(text) {
667
- return document.createComment(text);
668
- },
669
- setAttribute(el, key, value) {
670
- el.setAttribute(key, value);
671
- },
672
- removeAttribute(el, key) {
673
- el.removeAttribute(key);
674
- },
675
- setProperty(el, key, value) {
676
- el[key] = value;
677
- },
678
- insertBefore(parent, child, anchor) {
679
- parent.insertBefore(child, anchor);
680
- },
681
- appendChild(parent, child) {
682
- parent.appendChild(child);
683
- },
684
- remove(node) {
685
- node.parentNode?.removeChild(node);
686
- },
687
- setTextContent(node, text) {
688
- node.data = text;
689
- },
690
- addEventListener(el, event, handler) {
691
- el.addEventListener(event, handler);
692
- },
693
- removeEventListener(el, event, handler) {
694
- el.removeEventListener(event, handler);
695
- },
696
- parentNode(node) {
697
- return node.parentNode;
698
- },
699
- nextSibling(node) {
700
- return node.nextSibling;
701
- }
702
- };
703
-
704
501
  // src/renderer/events.ts
705
502
  function isEventProp(key) {
706
503
  return key.length > 2 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z";
@@ -727,77 +524,991 @@ function bindEvents(el, props) {
727
524
  }
728
525
  return cleanups;
729
526
  }
730
-
731
- // src/component/instance.ts
732
- var uidCounter = 0;
733
- function createComponentInstance(component, props, parent) {
527
+ // src/reactivity/batch.ts
528
+ var batchDepth = 0;
529
+ function batch(fn) {
530
+ batchDepth++;
531
+ try {
532
+ fn();
533
+ } finally {
534
+ batchDepth--;
535
+ if (batchDepth === 0) {
536
+ flushSync();
537
+ }
538
+ }
539
+ }
540
+ // src/component/control-flow.ts
541
+ var SHOW_TYPE = Symbol.for("Sinwan.Show");
542
+ var FOR_TYPE = Symbol.for("Sinwan.For");
543
+ var SWITCH_TYPE = Symbol.for("Sinwan.Switch");
544
+ var MATCH_TYPE = Symbol.for("Sinwan.Match");
545
+ var INDEX_TYPE = Symbol.for("Sinwan.Index");
546
+ var KEY_TYPE = Symbol.for("Sinwan.Key");
547
+ var DYNAMIC_TYPE = Symbol.for("Sinwan.Dynamic");
548
+ var PORTAL_TYPE = Symbol.for("Sinwan.Portal");
549
+ function Show(props) {
734
550
  return {
735
- uid: uidCounter++,
736
- component,
551
+ tag: SHOW_TYPE,
737
552
  props,
738
- element: null,
739
- parent,
740
- children: [],
741
- effects: [],
742
- _mountedHooks: [],
743
- _unmountedHooks: [],
744
- _updatedHooks: [],
745
- _errorHooks: [],
746
- provides: parent ? Object.create(parent.provides) : Object.create(null),
747
- isMounted: false,
748
- isUnmounted: false
553
+ children: []
749
554
  };
750
555
  }
751
- var currentInstance = null;
752
- function getCurrentInstance() {
753
- return currentInstance;
556
+ function For(props) {
557
+ return {
558
+ tag: FOR_TYPE,
559
+ props,
560
+ children: []
561
+ };
754
562
  }
755
- function setCurrentInstance(instance) {
563
+ function Switch(props) {
564
+ return {
565
+ tag: SWITCH_TYPE,
566
+ props,
567
+ children: []
568
+ };
569
+ }
570
+ function Match(props) {
571
+ return {
572
+ tag: MATCH_TYPE,
573
+ props,
574
+ children: []
575
+ };
576
+ }
577
+ function Index(props) {
578
+ return {
579
+ tag: INDEX_TYPE,
580
+ props,
581
+ children: []
582
+ };
583
+ }
584
+ function Key(props) {
585
+ return {
586
+ tag: KEY_TYPE,
587
+ props,
588
+ children: []
589
+ };
590
+ }
591
+ function Dynamic(props) {
592
+ return {
593
+ tag: DYNAMIC_TYPE,
594
+ props,
595
+ children: []
596
+ };
597
+ }
598
+ function Visible(props) {
599
+ const {
600
+ when,
601
+ as = "span",
602
+ style,
603
+ children,
604
+ ...rest
605
+ } = props;
606
+ const visibleStyle = computed(() => {
607
+ const base = readReactive(style);
608
+ const visible = Boolean(readReactive(when));
609
+ if (typeof base === "string") {
610
+ return visible ? base : appendHiddenDisplay(base);
611
+ }
612
+ const styleObject = base && typeof base === "object" ? { ...base } : {};
613
+ styleObject.display = visible ? styleObject.display : "none";
614
+ return styleObject;
615
+ });
616
+ return {
617
+ tag: as,
618
+ props: {
619
+ ...rest,
620
+ style: visibleStyle,
621
+ children
622
+ },
623
+ children: normalizeChildren2(children)
624
+ };
625
+ }
626
+ function Portal(props) {
627
+ return {
628
+ tag: PORTAL_TYPE,
629
+ props,
630
+ children: []
631
+ };
632
+ }
633
+ function isShowElement(element) {
634
+ return element.tag === SHOW_TYPE;
635
+ }
636
+ function isForElement(element) {
637
+ return element.tag === FOR_TYPE;
638
+ }
639
+ function isSwitchElement(element) {
640
+ return element.tag === SWITCH_TYPE;
641
+ }
642
+ function isMatchElement(element) {
643
+ return element.tag === MATCH_TYPE;
644
+ }
645
+ function isIndexElement(element) {
646
+ return element.tag === INDEX_TYPE;
647
+ }
648
+ function isKeyElement(element) {
649
+ return element.tag === KEY_TYPE;
650
+ }
651
+ function isDynamicElement(element) {
652
+ return element.tag === DYNAMIC_TYPE;
653
+ }
654
+ function isPortalElement(element) {
655
+ return element.tag === PORTAL_TYPE;
656
+ }
657
+ function normalizeChildren2(children) {
658
+ if (children == null || typeof children === "boolean") {
659
+ return [];
660
+ }
661
+ return Array.isArray(children) ? children : [children];
662
+ }
663
+ function readReactive(value) {
664
+ return isSignal(value) || isComputed(value) ? value.value : value;
665
+ }
666
+ function appendHiddenDisplay(style) {
667
+ const trimmed = style.trim();
668
+ const separator = trimmed.length > 0 && !trimmed.endsWith(";") ? ";" : "";
669
+ return `${trimmed}${separator}display:none`;
670
+ }
671
+
672
+ // src/server/renderer.ts
673
+ var componentCache = new WeakMap;
674
+ var pageRegistry = new Map;
675
+ function registerPage(name, page) {
676
+ pageRegistry.set(name, page);
677
+ }
678
+ function getPage(name) {
679
+ return pageRegistry.get(name);
680
+ }
681
+ function hasPage(name) {
682
+ return pageRegistry.has(name);
683
+ }
684
+ async function renderPage(name, data) {
685
+ const page = getPage(name);
686
+ if (!page) {
687
+ throw new Error(`Page "${name}" not found in registry`);
688
+ }
689
+ const element = await page(data);
690
+ return renderToString(element);
691
+ }
692
+ async function renderToString(node) {
693
+ if (node == null || typeof node === "boolean") {
694
+ return "";
695
+ }
696
+ if (typeof node === "string") {
697
+ return escapeHtml(node);
698
+ }
699
+ if (typeof node === "number") {
700
+ return String(node);
701
+ }
702
+ if (node instanceof HtmlEscapedString) {
703
+ return node.value;
704
+ }
705
+ if (isSignal(node) || isComputed(node)) {
706
+ return escapeHtml(String(node.value));
707
+ }
708
+ if (Array.isArray(node)) {
709
+ const results = await Promise.all(node.map((child) => renderToString(child)));
710
+ return results.join("");
711
+ }
712
+ if (node instanceof Promise) {
713
+ return renderElement(await node);
714
+ }
715
+ return renderElement(node);
716
+ }
717
+ async function renderElement(element) {
718
+ const { tag, props, children } = element;
719
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
720
+ return renderElement(tag(props));
721
+ }
722
+ if (tag === Visible) {
723
+ return renderElement(tag(props));
724
+ }
725
+ if (isShowElement(element)) {
726
+ const when = readReactive2(props.when);
727
+ return renderToString(when ? resolveShowChildren(element, when) : props.fallback);
728
+ }
729
+ if (isForElement(element)) {
730
+ return renderForElement(element);
731
+ }
732
+ if (isSwitchElement(element)) {
733
+ return renderToString(resolveSwitchContent(element));
734
+ }
735
+ if (isMatchElement(element)) {
736
+ const when = readReactive2(props.when);
737
+ return renderToString(when ? resolveMatchChildren(element, when) : null);
738
+ }
739
+ if (isIndexElement(element)) {
740
+ return renderIndexElement(element);
741
+ }
742
+ if (isKeyElement(element)) {
743
+ const key = readReactive2(props.when);
744
+ return renderToString(resolveKeyChildren(element, key));
745
+ }
746
+ if (isDynamicElement(element)) {
747
+ const tag2 = readReactive2(props.component);
748
+ const dynamic = createDynamicElement(element, tag2);
749
+ return dynamic ? renderElement(dynamic) : "";
750
+ }
751
+ if (isPortalElement(element)) {
752
+ return "";
753
+ }
754
+ if (typeof tag === "function") {
755
+ const result = await tag(props);
756
+ return renderToString(result);
757
+ }
758
+ if (typeof tag === "string") {
759
+ return renderIntrinsicElement(tag, props, children);
760
+ }
761
+ return renderToString(children);
762
+ }
763
+ var VOID_ELEMENTS2 = new Set([
764
+ "area",
765
+ "base",
766
+ "br",
767
+ "col",
768
+ "embed",
769
+ "hr",
770
+ "img",
771
+ "input",
772
+ "link",
773
+ "meta",
774
+ "param",
775
+ "source",
776
+ "track",
777
+ "wbr"
778
+ ]);
779
+ async function renderIntrinsicElement(tag, props, children) {
780
+ const attrs = renderAttributes(props);
781
+ if (VOID_ELEMENTS2.has(tag)) {
782
+ return attrs ? `<${tag}${attrs}>` : `<${tag}>`;
783
+ }
784
+ const childrenHtml = await renderChildren(children, props);
785
+ return attrs ? `<${tag}${attrs}>${childrenHtml}</${tag}>` : `<${tag}>${childrenHtml}</${tag}>`;
786
+ }
787
+ function renderAttributes(props) {
788
+ let attrs = "";
789
+ for (const [key, value] of Object.entries(props)) {
790
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
791
+ continue;
792
+ }
793
+ const resolvedValue = readReactive2(value);
794
+ if (resolvedValue == null || resolvedValue === false)
795
+ continue;
796
+ attrs += renderServerAttribute(key, resolvedValue);
797
+ }
798
+ return attrs;
799
+ }
800
+ async function renderChildren(children, props) {
801
+ const dangerous = props.dangerouslySetInnerHTML;
802
+ if (dangerous && typeof dangerous.__html === "string") {
803
+ return dangerous.__html;
804
+ }
805
+ return renderToString(children);
806
+ }
807
+ function isSlots(children) {
808
+ return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
809
+ }
810
+ async function renderForElement(element) {
811
+ const props = element.props;
812
+ const each = readReactive2(props.each);
813
+ if (!Array.isArray(each) || typeof props.children !== "function") {
814
+ return props.fallback ? renderToString(props.fallback) : "";
815
+ }
816
+ if (each.length === 0) {
817
+ return props.fallback ? renderToString(props.fallback) : "";
818
+ }
819
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
820
+ return rendered.join("");
821
+ }
822
+ async function renderIndexElement(element) {
823
+ const props = element.props;
824
+ const each = readReactive2(props.each);
825
+ if (!Array.isArray(each) || typeof props.children !== "function") {
826
+ return props.fallback ? renderToString(props.fallback) : "";
827
+ }
828
+ if (each.length === 0) {
829
+ return props.fallback ? renderToString(props.fallback) : "";
830
+ }
831
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(() => item, index))));
832
+ return rendered.join("");
833
+ }
834
+ function resolveSwitchContent(element) {
835
+ const props = element.props;
836
+ const children = normalizeContent(props.children ?? element.children);
837
+ for (const child of children) {
838
+ const match = getMatchElement(child);
839
+ if (!match) {
840
+ continue;
841
+ }
842
+ const when = readReactive2(match.props.when);
843
+ if (when) {
844
+ return resolveMatchChildren(match, when);
845
+ }
846
+ }
847
+ return props.fallback;
848
+ }
849
+ function resolveMatchChildren(element, value) {
850
+ const children = element.props.children ?? element.children;
851
+ if (typeof children === "function") {
852
+ return children(value);
853
+ }
854
+ return children;
855
+ }
856
+ function resolveKeyChildren(element, value) {
857
+ const children = element.props.children ?? element.children;
858
+ if (typeof children === "function") {
859
+ return children(value);
860
+ }
861
+ return children;
862
+ }
863
+ function createDynamicElement(element, tag) {
864
+ if (typeof tag !== "string" && typeof tag !== "function") {
865
+ return null;
866
+ }
867
+ const { component, ...props } = element.props;
868
+ const children = normalizeContent(props.children ?? element.children);
869
+ return {
870
+ tag,
871
+ props,
872
+ children
873
+ };
874
+ }
875
+ function resolveShowChildren(element, value) {
876
+ const children = element.props.children ?? element.children;
877
+ if (typeof children === "function") {
878
+ return children(value);
879
+ }
880
+ return children;
881
+ }
882
+ function readReactive2(value) {
883
+ return isSignal(value) || isComputed(value) ? value.value : value;
884
+ }
885
+ function normalizeContent(content) {
886
+ if (content == null || typeof content === "boolean") {
887
+ return [];
888
+ }
889
+ return Array.isArray(content) ? content : [content];
890
+ }
891
+ function isElementLike(value) {
892
+ return value != null && typeof value === "object" && "tag" in value;
893
+ }
894
+ function getMatchElement(value) {
895
+ if (!isElementLike(value)) {
896
+ return null;
897
+ }
898
+ if (isMatchElement(value)) {
899
+ return value;
900
+ }
901
+ return value.tag === Match ? Match(value.props) : null;
902
+ }
903
+ // src/component/instance.ts
904
+ var uidCounter = 0;
905
+ function createComponentInstance(component, props, parent) {
906
+ return {
907
+ uid: uidCounter++,
908
+ component,
909
+ props,
910
+ element: null,
911
+ parent,
912
+ children: [],
913
+ effects: [],
914
+ _mountedHooks: [],
915
+ _unmountedHooks: [],
916
+ _updatedHooks: [],
917
+ _errorHooks: [],
918
+ provides: parent ? Object.create(parent.provides) : Object.create(null),
919
+ isMounted: false,
920
+ isUnmounted: false
921
+ };
922
+ }
923
+ var currentInstance = null;
924
+ function getCurrentInstance() {
925
+ return currentInstance;
926
+ }
927
+ function setCurrentInstance(instance) {
756
928
  const prev = currentInstance;
757
929
  currentInstance = instance;
758
930
  return prev;
759
931
  }
760
- function fireMountedHooks(instance) {
761
- for (const child of instance.children) {
762
- fireMountedHooks(child);
932
+ function withInstance(instance, fn) {
933
+ const prev = setCurrentInstance(instance);
934
+ try {
935
+ return fn();
936
+ } finally {
937
+ setCurrentInstance(prev);
938
+ }
939
+ }
940
+ function fireMountedHooks(instance) {
941
+ if (instance.isUnmounted) {
942
+ return;
943
+ }
944
+ for (const child of instance.children) {
945
+ fireMountedHooks(child);
946
+ }
947
+ if (!instance.isMounted) {
948
+ instance.isMounted = true;
949
+ for (const hook of instance._mountedHooks) {
950
+ hook();
951
+ }
952
+ }
953
+ }
954
+ function fireUnmountedHooks(instance) {
955
+ for (const child of instance.children) {
956
+ fireUnmountedHooks(child);
957
+ }
958
+ if (instance.isMounted && !instance.isUnmounted) {
959
+ instance.isUnmounted = true;
960
+ instance.isMounted = false;
961
+ for (const hook of instance._unmountedHooks) {
962
+ hook();
963
+ }
964
+ for (const dispose of instance.effects) {
965
+ dispose();
966
+ }
967
+ instance.effects.length = 0;
968
+ }
969
+ }
970
+ function fireUpdatedHooks(instance) {
971
+ for (const hook of instance._updatedHooks) {
972
+ hook();
973
+ }
974
+ }
975
+ var queuedUpdatedHooks = new Set;
976
+ function queueUpdatedHooks(instance) {
977
+ if (!instance || !instance.isMounted || instance.isUnmounted || instance._updatedHooks.length === 0 || queuedUpdatedHooks.has(instance)) {
978
+ return;
979
+ }
980
+ queuedUpdatedHooks.add(instance);
981
+ nextTick(() => {
982
+ queuedUpdatedHooks.delete(instance);
983
+ if (instance.isMounted && !instance.isUnmounted) {
984
+ fireUpdatedHooks(instance);
985
+ }
986
+ });
987
+ }
988
+ function handleComponentError(instance, err) {
989
+ let current = instance;
990
+ while (current) {
991
+ if (current._errorHooks.length > 0) {
992
+ for (const hook of current._errorHooks) {
993
+ hook(err);
994
+ }
995
+ return;
996
+ }
997
+ current = current.parent;
998
+ }
999
+ console.error("[Sinwan] Unhandled component error:", err);
1000
+ }
1001
+
1002
+ // src/hydration/markers.ts
1003
+ var COMP_ID_ATTR = "data-sinwan-id";
1004
+ var COMP_ID_PREFIX = "c";
1005
+ var TEXT_MARKER_OPEN = "sinwan-t:";
1006
+ var TEXT_MARKER_CLOSE = "/sinwan-t";
1007
+ var EVENT_ATTR = "data-sinwan-ev";
1008
+ function compId(index) {
1009
+ return `${COMP_ID_PREFIX}${index}`;
1010
+ }
1011
+ function textMarkerOpen(index) {
1012
+ return `<!--${TEXT_MARKER_OPEN}${index}-->`;
1013
+ }
1014
+ function textMarkerCloseStr() {
1015
+ return `<!--${TEXT_MARKER_CLOSE}-->`;
1016
+ }
1017
+ function parseTextOpenMarker(node) {
1018
+ const data = node.data;
1019
+ if (data.startsWith(TEXT_MARKER_OPEN)) {
1020
+ const idx = parseInt(data.slice(TEXT_MARKER_OPEN.length), 10);
1021
+ return Number.isNaN(idx) ? -1 : idx;
1022
+ }
1023
+ return -1;
1024
+ }
1025
+ function isTextCloseMarker(node) {
1026
+ return node.data === TEXT_MARKER_CLOSE;
1027
+ }
1028
+
1029
+ // src/server/stream.ts
1030
+ function createHydratableStreamContext() {
1031
+ return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
1032
+ }
1033
+ var VOID_ELEMENTS3 = new Set([
1034
+ "area",
1035
+ "base",
1036
+ "br",
1037
+ "col",
1038
+ "embed",
1039
+ "hr",
1040
+ "img",
1041
+ "input",
1042
+ "link",
1043
+ "meta",
1044
+ "param",
1045
+ "source",
1046
+ "track",
1047
+ "wbr"
1048
+ ]);
1049
+ function streamPage(page, data) {
1050
+ const encoder = new TextEncoder;
1051
+ return new ReadableStream({
1052
+ async start(controller) {
1053
+ try {
1054
+ const element = await page(data);
1055
+ await streamNode(element, controller, encoder);
1056
+ controller.close();
1057
+ } catch (error) {
1058
+ controller.error(error);
1059
+ }
1060
+ }
1061
+ });
1062
+ }
1063
+ function streamHydratablePage(component, props) {
1064
+ const encoder = new TextEncoder;
1065
+ const ctx = createHydratableStreamContext();
1066
+ return new ReadableStream({
1067
+ async start(controller) {
1068
+ try {
1069
+ await streamHydratableComponent(component, props ?? {}, controller, encoder, ctx, true);
1070
+ controller.close();
1071
+ } catch (error) {
1072
+ controller.error(error);
1073
+ }
1074
+ }
1075
+ });
1076
+ }
1077
+ function streamHydratableNode(node) {
1078
+ const encoder = new TextEncoder;
1079
+ const ctx = createHydratableStreamContext();
1080
+ return new ReadableStream({
1081
+ async start(controller) {
1082
+ try {
1083
+ await streamHydratableNodeToController(node, controller, encoder, ctx);
1084
+ controller.close();
1085
+ } catch (error) {
1086
+ controller.error(error);
1087
+ }
1088
+ }
1089
+ });
1090
+ }
1091
+ async function streamNode(node, controller, encoder) {
1092
+ if (node == null || typeof node === "boolean") {
1093
+ return;
1094
+ }
1095
+ if (typeof node === "string") {
1096
+ controller.enqueue(encoder.encode(escapeHtml(node)));
1097
+ return;
1098
+ }
1099
+ if (typeof node === "number") {
1100
+ controller.enqueue(encoder.encode(String(node)));
1101
+ return;
1102
+ }
1103
+ if (node instanceof HtmlEscapedString) {
1104
+ controller.enqueue(encoder.encode(node.value));
1105
+ return;
1106
+ }
1107
+ if (isSignal(node) || isComputed(node)) {
1108
+ controller.enqueue(encoder.encode(escapeHtml(String(node.value))));
1109
+ return;
1110
+ }
1111
+ if (Array.isArray(node)) {
1112
+ for (const child of node) {
1113
+ await streamNode(child, controller, encoder);
1114
+ }
1115
+ return;
1116
+ }
1117
+ if (node instanceof Promise) {
1118
+ const resolved = await node;
1119
+ await streamElement(resolved, controller, encoder);
1120
+ return;
1121
+ }
1122
+ await streamElement(node, controller, encoder);
1123
+ }
1124
+ async function streamElement(element, controller, encoder) {
1125
+ const { tag, props, children } = element;
1126
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1127
+ await streamElement(tag(props), controller, encoder);
1128
+ return;
1129
+ }
1130
+ if (tag === Visible) {
1131
+ await streamElement(tag(props), controller, encoder);
1132
+ return;
1133
+ }
1134
+ if (isShowElement(element)) {
1135
+ const when = readReactive3(props.when);
1136
+ await streamNode(when ? resolveShowChildren2(element, when) : props.fallback, controller, encoder);
1137
+ return;
1138
+ }
1139
+ if (isForElement(element)) {
1140
+ await streamForElement(element, controller, encoder);
1141
+ return;
1142
+ }
1143
+ if (isSwitchElement(element)) {
1144
+ await streamNode(resolveSwitchContent2(element), controller, encoder);
1145
+ return;
1146
+ }
1147
+ if (isMatchElement(element)) {
1148
+ const when = readReactive3(props.when);
1149
+ await streamNode(when ? resolveMatchChildren2(element, when) : null, controller, encoder);
1150
+ return;
1151
+ }
1152
+ if (isIndexElement(element)) {
1153
+ await streamIndexElement(element, controller, encoder);
1154
+ return;
1155
+ }
1156
+ if (isKeyElement(element)) {
1157
+ const key = readReactive3(props.when);
1158
+ await streamNode(resolveKeyChildren2(element, key), controller, encoder);
1159
+ return;
1160
+ }
1161
+ if (isDynamicElement(element)) {
1162
+ const dynamicTag = readReactive3(props.component);
1163
+ const dynamic = createDynamicElement2(element, dynamicTag);
1164
+ if (dynamic) {
1165
+ await streamElement(dynamic, controller, encoder);
1166
+ }
1167
+ return;
1168
+ }
1169
+ if (isPortalElement(element)) {
1170
+ return;
1171
+ }
1172
+ if (typeof tag === "function") {
1173
+ const result = await tag(props);
1174
+ await streamNode(result, controller, encoder);
1175
+ return;
1176
+ }
1177
+ if (typeof tag === "string") {
1178
+ await streamIntrinsicElement(tag, props, children, controller, encoder);
1179
+ return;
1180
+ }
1181
+ await streamNode(children, controller, encoder);
1182
+ }
1183
+ async function streamIntrinsicElement(tag, props, children, controller, encoder) {
1184
+ const attrs = renderAttributes2(props);
1185
+ const dangerous = props.dangerouslySetInnerHTML;
1186
+ if (VOID_ELEMENTS3.has(tag)) {
1187
+ const html = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
1188
+ controller.enqueue(encoder.encode(html));
1189
+ return;
763
1190
  }
764
- if (!instance.isMounted) {
765
- instance.isMounted = true;
766
- for (const hook of instance._mountedHooks) {
767
- hook();
1191
+ const openTag = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
1192
+ controller.enqueue(encoder.encode(openTag));
1193
+ if (dangerous && typeof dangerous.__html === "string") {
1194
+ controller.enqueue(encoder.encode(dangerous.__html));
1195
+ } else {
1196
+ await streamNode(children, controller, encoder);
1197
+ }
1198
+ controller.enqueue(encoder.encode(`</${tag}>`));
1199
+ }
1200
+ function renderAttributes2(props) {
1201
+ let attrs = "";
1202
+ for (const [key, value] of Object.entries(props)) {
1203
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
1204
+ continue;
768
1205
  }
1206
+ const resolvedValue = readReactive3(value);
1207
+ if (resolvedValue == null || resolvedValue === false)
1208
+ continue;
1209
+ attrs += renderServerAttribute(key, resolvedValue);
769
1210
  }
1211
+ return attrs;
770
1212
  }
771
- function fireUnmountedHooks(instance) {
772
- for (const child of instance.children) {
773
- fireUnmountedHooks(child);
1213
+ async function streamHydratableNodeToController(node, controller, encoder, ctx, isComponentRoot = false) {
1214
+ if (node == null || typeof node === "boolean") {
1215
+ return;
774
1216
  }
775
- if (instance.isMounted && !instance.isUnmounted) {
776
- instance.isUnmounted = true;
777
- instance.isMounted = false;
778
- for (const hook of instance._unmountedHooks) {
779
- hook();
1217
+ if (typeof node === "string") {
1218
+ enqueue(controller, encoder, escapeHtml(node));
1219
+ return;
1220
+ }
1221
+ if (typeof node === "number") {
1222
+ enqueue(controller, encoder, String(node));
1223
+ return;
1224
+ }
1225
+ if (node instanceof HtmlEscapedString) {
1226
+ enqueue(controller, encoder, node.value);
1227
+ return;
1228
+ }
1229
+ if (isSignal(node) || isComputed(node)) {
1230
+ const idx = ctx.textIndex++;
1231
+ enqueue(controller, encoder, `${textMarkerOpen(idx)}${escapeHtml(String(node.value))}${textMarkerCloseStr()}`);
1232
+ return;
1233
+ }
1234
+ if (Array.isArray(node)) {
1235
+ for (const child of node) {
1236
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
780
1237
  }
781
- for (const dispose of instance.effects) {
782
- dispose();
1238
+ return;
1239
+ }
1240
+ if (node instanceof Promise) {
1241
+ await streamHydratableElement(await node, controller, encoder, ctx, isComponentRoot);
1242
+ return;
1243
+ }
1244
+ await streamHydratableElement(node, controller, encoder, ctx, isComponentRoot);
1245
+ }
1246
+ async function streamHydratableElement(element, controller, encoder, ctx, isComponentRoot) {
1247
+ const { tag, props, children } = element;
1248
+ if (tag === "") {
1249
+ for (const child of children) {
1250
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
783
1251
  }
784
- instance.effects.length = 0;
1252
+ return;
1253
+ }
1254
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1255
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
1256
+ return;
1257
+ }
1258
+ if (tag === Visible) {
1259
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
1260
+ return;
1261
+ }
1262
+ if (isShowElement(element)) {
1263
+ const when = readReactive3(props.when);
1264
+ await streamHydratableNodeToController(when ? resolveShowChildren2(element, when) : props.fallback, controller, encoder, ctx, isComponentRoot);
1265
+ return;
1266
+ }
1267
+ if (isForElement(element)) {
1268
+ await streamHydratableForElement(element, controller, encoder, ctx);
1269
+ return;
1270
+ }
1271
+ if (isSwitchElement(element)) {
1272
+ await streamHydratableNodeToController(resolveSwitchContent2(element), controller, encoder, ctx, isComponentRoot);
1273
+ return;
1274
+ }
1275
+ if (isMatchElement(element)) {
1276
+ const when = readReactive3(props.when);
1277
+ await streamHydratableNodeToController(when ? resolveMatchChildren2(element, when) : null, controller, encoder, ctx, isComponentRoot);
1278
+ return;
1279
+ }
1280
+ if (isIndexElement(element)) {
1281
+ await streamHydratableIndexElement(element, controller, encoder, ctx);
1282
+ return;
1283
+ }
1284
+ if (isKeyElement(element)) {
1285
+ const key = readReactive3(props.when);
1286
+ await streamHydratableNodeToController(resolveKeyChildren2(element, key), controller, encoder, ctx, isComponentRoot);
1287
+ return;
785
1288
  }
1289
+ if (isDynamicElement(element)) {
1290
+ const dynamicTag = readReactive3(props.component);
1291
+ const dynamic = createDynamicElement2(element, dynamicTag);
1292
+ if (dynamic) {
1293
+ await streamHydratableElement(dynamic, controller, encoder, ctx, isComponentRoot);
1294
+ }
1295
+ return;
1296
+ }
1297
+ if (isPortalElement(element)) {
1298
+ return;
1299
+ }
1300
+ if (typeof tag === "function") {
1301
+ await streamHydratableComponent(tag, props, controller, encoder, ctx, true);
1302
+ return;
1303
+ }
1304
+ if (typeof tag === "string") {
1305
+ await streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot);
1306
+ return;
1307
+ }
1308
+ await streamHydratableNodeToController(children, controller, encoder, ctx);
786
1309
  }
787
- function handleComponentError(instance, err) {
788
- let current = instance;
789
- while (current) {
790
- if (current._errorHooks.length > 0) {
791
- for (const hook of current._errorHooks) {
792
- hook(err);
793
- }
794
- return;
1310
+ async function streamHydratableComponent(component, props, controller, encoder, ctx, isComponentRoot) {
1311
+ const parentInstance = getCurrentInstance();
1312
+ const instance = createComponentInstance(component, props, parentInstance);
1313
+ if (parentInstance) {
1314
+ parentInstance.children.push(instance);
1315
+ }
1316
+ const prev = setCurrentInstance(instance);
1317
+ try {
1318
+ const result = await component(props);
1319
+ await streamHydratableNodeToController(result, controller, encoder, ctx, isComponentRoot);
1320
+ } finally {
1321
+ setCurrentInstance(prev);
1322
+ }
1323
+ }
1324
+ async function streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot) {
1325
+ const attrs = renderHydratableAttributes(props, ctx, isComponentRoot);
1326
+ const dangerous = props.dangerouslySetInnerHTML;
1327
+ enqueue(controller, encoder, attrs ? `<${tag}${attrs}>` : `<${tag}>`);
1328
+ if (VOID_ELEMENTS3.has(tag)) {
1329
+ return;
1330
+ }
1331
+ if (dangerous && typeof dangerous.__html === "string") {
1332
+ enqueue(controller, encoder, dangerous.__html);
1333
+ } else {
1334
+ for (const child of children) {
1335
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
795
1336
  }
796
- current = current.parent;
797
1337
  }
798
- console.error("[Sinwan] Unhandled component error:", err);
1338
+ enqueue(controller, encoder, `</${tag}>`);
1339
+ }
1340
+ async function streamHydratableForElement(element, controller, encoder, ctx) {
1341
+ const props = element.props;
1342
+ const each = readReactive3(props.each);
1343
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1344
+ if (props.fallback) {
1345
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
1346
+ }
1347
+ return;
1348
+ }
1349
+ if (each.length === 0) {
1350
+ if (props.fallback) {
1351
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
1352
+ }
1353
+ return;
1354
+ }
1355
+ for (let index = 0;index < each.length; index++) {
1356
+ await streamHydratableNodeToController(props.children(each[index], () => index), controller, encoder, ctx);
1357
+ }
1358
+ }
1359
+ async function streamHydratableIndexElement(element, controller, encoder, ctx) {
1360
+ const props = element.props;
1361
+ const each = readReactive3(props.each);
1362
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1363
+ if (props.fallback) {
1364
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
1365
+ }
1366
+ return;
1367
+ }
1368
+ if (each.length === 0) {
1369
+ if (props.fallback) {
1370
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
1371
+ }
1372
+ return;
1373
+ }
1374
+ for (let index = 0;index < each.length; index++) {
1375
+ await streamHydratableNodeToController(props.children(() => each[index], index), controller, encoder, ctx);
1376
+ }
1377
+ }
1378
+ function renderHydratableAttributes(props, ctx, isComponentRoot) {
1379
+ let attrs = "";
1380
+ if (isComponentRoot) {
1381
+ attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
1382
+ }
1383
+ const eventParts = [];
1384
+ for (const [key, value] of Object.entries(props)) {
1385
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
1386
+ continue;
1387
+ }
1388
+ if (isEventProp(key)) {
1389
+ eventParts.push(`${toEventName(key)}:${ctx.eventIndex++}`);
1390
+ continue;
1391
+ }
1392
+ const resolvedValue = readReactive3(value);
1393
+ if (resolvedValue == null || resolvedValue === false)
1394
+ continue;
1395
+ attrs += renderServerAttribute(key, resolvedValue);
1396
+ }
1397
+ if (eventParts.length > 0) {
1398
+ attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
1399
+ }
1400
+ return attrs;
1401
+ }
1402
+ function enqueue(controller, encoder, html) {
1403
+ controller.enqueue(encoder.encode(html));
1404
+ }
1405
+ async function streamForElement(element, controller, encoder) {
1406
+ const props = element.props;
1407
+ const each = readReactive3(props.each);
1408
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1409
+ if (props.fallback) {
1410
+ await streamNode(props.fallback, controller, encoder);
1411
+ }
1412
+ return;
1413
+ }
1414
+ if (each.length === 0) {
1415
+ if (props.fallback) {
1416
+ await streamNode(props.fallback, controller, encoder);
1417
+ }
1418
+ return;
1419
+ }
1420
+ for (let index = 0;index < each.length; index++) {
1421
+ await streamNode(props.children(each[index], () => index), controller, encoder);
1422
+ }
1423
+ }
1424
+ async function streamIndexElement(element, controller, encoder) {
1425
+ const props = element.props;
1426
+ const each = readReactive3(props.each);
1427
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1428
+ if (props.fallback) {
1429
+ await streamNode(props.fallback, controller, encoder);
1430
+ }
1431
+ return;
1432
+ }
1433
+ if (each.length === 0) {
1434
+ if (props.fallback) {
1435
+ await streamNode(props.fallback, controller, encoder);
1436
+ }
1437
+ return;
1438
+ }
1439
+ for (let index = 0;index < each.length; index++) {
1440
+ await streamNode(props.children(() => each[index], index), controller, encoder);
1441
+ }
1442
+ }
1443
+ function resolveShowChildren2(element, value) {
1444
+ const children = element.props.children ?? element.children;
1445
+ if (typeof children === "function") {
1446
+ return children(value);
1447
+ }
1448
+ return children;
1449
+ }
1450
+ function resolveSwitchContent2(element) {
1451
+ const props = element.props;
1452
+ const children = normalizeContent2(props.children ?? element.children);
1453
+ for (const child of children) {
1454
+ const match = getMatchElement2(child);
1455
+ if (!match) {
1456
+ continue;
1457
+ }
1458
+ const when = readReactive3(match.props.when);
1459
+ if (when) {
1460
+ return resolveMatchChildren2(match, when);
1461
+ }
1462
+ }
1463
+ return props.fallback;
1464
+ }
1465
+ function resolveMatchChildren2(element, value) {
1466
+ const children = element.props.children ?? element.children;
1467
+ if (typeof children === "function") {
1468
+ return children(value);
1469
+ }
1470
+ return children;
1471
+ }
1472
+ function resolveKeyChildren2(element, value) {
1473
+ const children = element.props.children ?? element.children;
1474
+ if (typeof children === "function") {
1475
+ return children(value);
1476
+ }
1477
+ return children;
1478
+ }
1479
+ function createDynamicElement2(element, tag) {
1480
+ if (typeof tag !== "string" && typeof tag !== "function") {
1481
+ return null;
1482
+ }
1483
+ const { component, ...props } = element.props;
1484
+ const children = normalizeContent2(props.children ?? element.children);
1485
+ return {
1486
+ tag,
1487
+ props,
1488
+ children
1489
+ };
1490
+ }
1491
+ function readReactive3(value) {
1492
+ return isSignal(value) || isComputed(value) ? value.value : value;
1493
+ }
1494
+ function normalizeContent2(content) {
1495
+ if (content == null || typeof content === "boolean") {
1496
+ return [];
1497
+ }
1498
+ return Array.isArray(content) ? content : [content];
1499
+ }
1500
+ function isElementLike2(value) {
1501
+ return value != null && typeof value === "object" && "tag" in value;
1502
+ }
1503
+ function getMatchElement2(value) {
1504
+ if (!isElementLike2(value)) {
1505
+ return null;
1506
+ }
1507
+ if (isMatchElement(value)) {
1508
+ return value;
1509
+ }
1510
+ return value.tag === Match ? Match(value.props) : null;
799
1511
  }
800
-
801
1512
  // src/server/hydration-markers.ts
802
1513
  function createHydrationContext() {
803
1514
  return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
@@ -806,13 +1517,16 @@ async function renderToHydratableString(component, props) {
806
1517
  const ctx = createHydrationContext();
807
1518
  const mergedProps = props ?? {};
808
1519
  const instance = createComponentInstance(component, mergedProps, null);
809
- setCurrentInstance(instance);
810
- const result = await component(mergedProps);
811
- setCurrentInstance(null);
812
- if (result && typeof result === "object" && "tag" in result) {
813
- return renderElementH(result, ctx, true);
1520
+ const prev = setCurrentInstance(instance);
1521
+ try {
1522
+ const result = await component(mergedProps);
1523
+ if (result && typeof result === "object" && "tag" in result) {
1524
+ return renderElementH(result, ctx, true);
1525
+ }
1526
+ return renderNodeH(result, ctx);
1527
+ } finally {
1528
+ setCurrentInstance(prev);
814
1529
  }
815
- return renderNodeH(result, ctx);
816
1530
  }
817
1531
  async function renderNodeToHydratableString(node) {
818
1532
  const ctx = createHydrationContext();
@@ -864,6 +1578,42 @@ function renderElementH(element, ctx, isComponentRoot) {
864
1578
  if (tag === "") {
865
1579
  return children.map((child) => renderNodeH(child, ctx)).join("");
866
1580
  }
1581
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1582
+ return renderElementH(tag(props), ctx, isComponentRoot);
1583
+ }
1584
+ if (tag === Visible) {
1585
+ return renderElementH(tag(props), ctx, isComponentRoot);
1586
+ }
1587
+ if (isShowElement(element)) {
1588
+ const when = readReactive4(props.when);
1589
+ const content = when ? resolveShowChildren3(element, when) : props.fallback;
1590
+ return renderNodeMaybeRoot(content, ctx, isComponentRoot);
1591
+ }
1592
+ if (isForElement(element)) {
1593
+ return renderForElementH(element, ctx);
1594
+ }
1595
+ if (isSwitchElement(element)) {
1596
+ return renderNodeMaybeRoot(resolveSwitchContent3(element), ctx, isComponentRoot);
1597
+ }
1598
+ if (isMatchElement(element)) {
1599
+ const when = readReactive4(props.when);
1600
+ return renderNodeMaybeRoot(when ? resolveMatchChildren3(element, when) : null, ctx, isComponentRoot);
1601
+ }
1602
+ if (isIndexElement(element)) {
1603
+ return renderIndexElementH(element, ctx);
1604
+ }
1605
+ if (isKeyElement(element)) {
1606
+ const key = readReactive4(props.when);
1607
+ return renderNodeMaybeRoot(resolveKeyChildren3(element, key), ctx, isComponentRoot);
1608
+ }
1609
+ if (isDynamicElement(element)) {
1610
+ const dynamicTag = readReactive4(props.component);
1611
+ const dynamic = createDynamicElement3(element, dynamicTag);
1612
+ return dynamic ? renderElementH(dynamic, ctx, isComponentRoot) : "";
1613
+ }
1614
+ if (isPortalElement(element)) {
1615
+ return "";
1616
+ }
867
1617
  if (typeof tag === "function") {
868
1618
  return renderComponentH(tag, props, ctx);
869
1619
  }
@@ -873,15 +1623,21 @@ function renderElementH(element, ctx, isComponentRoot) {
873
1623
  return children.map((child) => renderNodeH(child, ctx)).join("");
874
1624
  }
875
1625
  function renderComponentH(component, props, ctx) {
876
- const parentInstance = globalThis.__SinwanCurrentInstance;
877
- const instance = createComponentInstance(component, props, null);
1626
+ const parentInstance = getCurrentInstance();
1627
+ const instance = createComponentInstance(component, props, parentInstance);
1628
+ if (parentInstance) {
1629
+ parentInstance.children.push(instance);
1630
+ }
878
1631
  const prev = setCurrentInstance(instance);
879
- const result = component(props);
880
- setCurrentInstance(prev);
881
- if (result && typeof result === "object" && "tag" in result) {
882
- return renderElementH(result, ctx, true);
1632
+ try {
1633
+ const result = component(props);
1634
+ if (result && typeof result === "object" && "tag" in result) {
1635
+ return renderElementH(result, ctx, true);
1636
+ }
1637
+ return renderNodeH(result, ctx);
1638
+ } finally {
1639
+ setCurrentInstance(prev);
883
1640
  }
884
- return renderNodeH(result, ctx);
885
1641
  }
886
1642
  function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
887
1643
  let attrs = "";
@@ -890,8 +1646,9 @@ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
890
1646
  }
891
1647
  const eventParts = [];
892
1648
  for (const [key, value] of Object.entries(props)) {
893
- if (key === "children" || key === "dangerouslySetInnerHTML")
1649
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
894
1650
  continue;
1651
+ }
895
1652
  if (isEventProp(key)) {
896
1653
  const eventName = toEventName(key);
897
1654
  eventParts.push(`${eventName}:${ctx.eventIndex++}`);
@@ -903,13 +1660,7 @@ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
903
1660
  if (isSignal(value) || isComputed(value)) {
904
1661
  resolvedValue = value.value;
905
1662
  }
906
- if (resolvedValue === true) {
907
- const attrName2 = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
908
- attrs += ` ${attrName2}`;
909
- continue;
910
- }
911
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
912
- attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
1663
+ attrs += renderServerAttribute(key, resolvedValue);
913
1664
  }
914
1665
  if (eventParts.length > 0) {
915
1666
  attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
@@ -924,6 +1675,103 @@ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
924
1675
  const childrenHtml = children.map((child) => renderNodeH(child, ctx)).join("");
925
1676
  return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
926
1677
  }
1678
+ function renderNodeMaybeRoot(node, ctx, isComponentRoot) {
1679
+ if (isComponentRoot && node && typeof node === "object" && !Array.isArray(node) && "tag" in node) {
1680
+ return renderElementH(node, ctx, true);
1681
+ }
1682
+ return renderNodeH(node, ctx);
1683
+ }
1684
+ function renderForElementH(element, ctx) {
1685
+ const props = element.props;
1686
+ const each = readReactive4(props.each);
1687
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1688
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1689
+ }
1690
+ if (each.length === 0) {
1691
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1692
+ }
1693
+ return each.map((item, index) => renderNodeH(props.children(item, () => index), ctx)).join("");
1694
+ }
1695
+ function renderIndexElementH(element, ctx) {
1696
+ const props = element.props;
1697
+ const each = readReactive4(props.each);
1698
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1699
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1700
+ }
1701
+ if (each.length === 0) {
1702
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1703
+ }
1704
+ return each.map((item, index) => renderNodeH(props.children(() => item, index), ctx)).join("");
1705
+ }
1706
+ function resolveShowChildren3(element, value) {
1707
+ const children = element.props.children ?? element.children;
1708
+ if (typeof children === "function") {
1709
+ return children(value);
1710
+ }
1711
+ return children;
1712
+ }
1713
+ function resolveSwitchContent3(element) {
1714
+ const props = element.props;
1715
+ const children = normalizeContent3(props.children ?? element.children);
1716
+ for (const child of children) {
1717
+ const match = getMatchElement3(child);
1718
+ if (!match) {
1719
+ continue;
1720
+ }
1721
+ const when = readReactive4(match.props.when);
1722
+ if (when) {
1723
+ return resolveMatchChildren3(match, when);
1724
+ }
1725
+ }
1726
+ return props.fallback;
1727
+ }
1728
+ function resolveMatchChildren3(element, value) {
1729
+ const children = element.props.children ?? element.children;
1730
+ if (typeof children === "function") {
1731
+ return children(value);
1732
+ }
1733
+ return children;
1734
+ }
1735
+ function resolveKeyChildren3(element, value) {
1736
+ const children = element.props.children ?? element.children;
1737
+ if (typeof children === "function") {
1738
+ return children(value);
1739
+ }
1740
+ return children;
1741
+ }
1742
+ function createDynamicElement3(element, tag) {
1743
+ if (typeof tag !== "string" && typeof tag !== "function") {
1744
+ return null;
1745
+ }
1746
+ const { component, ...props } = element.props;
1747
+ const children = normalizeContent3(props.children ?? element.children);
1748
+ return {
1749
+ tag,
1750
+ props,
1751
+ children
1752
+ };
1753
+ }
1754
+ function readReactive4(value) {
1755
+ return isSignal(value) || isComputed(value) ? value.value : value;
1756
+ }
1757
+ function normalizeContent3(content) {
1758
+ if (content == null || typeof content === "boolean") {
1759
+ return [];
1760
+ }
1761
+ return Array.isArray(content) ? content : [content];
1762
+ }
1763
+ function isElementLike3(value) {
1764
+ return value != null && typeof value === "object" && "tag" in value;
1765
+ }
1766
+ function getMatchElement3(value) {
1767
+ if (!isElementLike3(value)) {
1768
+ return null;
1769
+ }
1770
+ if (isMatchElement(value)) {
1771
+ return value;
1772
+ }
1773
+ return value.tag === Match ? Match(value.props) : null;
1774
+ }
927
1775
 
928
- //# debugId=76A0C66C8E5A5C3C64756E2164756E21
1776
+ //# debugId=B6B29A838DF26EA964756E2164756E21
929
1777
  //# sourceMappingURL=index.development.js.map