sinwan 0.1.0 → 1.0.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 (87) hide show
  1. package/README.md +66 -39
  2. package/dist/cjs/index.development.js +1624 -961
  3. package/dist/cjs/index.development.js.map +21 -18
  4. package/dist/cjs/index.production.min.js +2 -2
  5. package/dist/cjs/index.production.min.js.map +21 -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 +1175 -0
  15. package/dist/cjs/renderer/index.development.js.map +24 -0
  16. package/dist/cjs/renderer/index.production.min.js +3 -0
  17. package/dist/cjs/renderer/index.production.min.js.map +24 -0
  18. package/dist/cjs/server/index.development.js +665 -329
  19. package/dist/cjs/server/index.development.js.map +11 -10
  20. package/dist/cjs/server/index.production.min.js +2 -2
  21. package/dist/cjs/server/index.production.min.js.map +11 -10
  22. package/dist/component/control-flow.d.ts +18 -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 +1301 -660
  33. package/dist/esm/index.development.js.map +21 -18
  34. package/dist/esm/index.production.min.js +2 -2
  35. package/dist/esm/index.production.min.js.map +21 -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 +1124 -0
  45. package/dist/esm/renderer/index.development.js.map +24 -0
  46. package/dist/esm/renderer/index.production.min.js +4 -0
  47. package/dist/esm/renderer/index.production.min.js.map +24 -0
  48. package/dist/esm/server/index.development.js +665 -329
  49. package/dist/esm/server/index.development.js.map +11 -10
  50. package/dist/esm/server/index.production.min.js +2 -2
  51. package/dist/esm/server/index.production.min.js.map +11 -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.map +1 -1
  60. package/dist/renderer/dom-ops.d.ts +4 -1
  61. package/dist/renderer/dom-ops.d.ts.map +1 -1
  62. package/dist/renderer/index.d.ts +1 -1
  63. package/dist/renderer/index.d.ts.map +1 -1
  64. package/dist/renderer/mount.d.ts +2 -5
  65. package/dist/renderer/mount.d.ts.map +1 -1
  66. package/dist/renderer/render-children.d.ts +2 -2
  67. package/dist/renderer/render-children.d.ts.map +1 -1
  68. package/dist/renderer/render-control-flow.d.ts +13 -0
  69. package/dist/renderer/render-control-flow.d.ts.map +1 -0
  70. package/dist/renderer/render-element.d.ts +1 -1
  71. package/dist/renderer/render-element.d.ts.map +1 -1
  72. package/dist/renderer/types.d.ts +2 -0
  73. package/dist/renderer/types.d.ts.map +1 -1
  74. package/dist/renderer/unmount.d.ts +20 -0
  75. package/dist/renderer/unmount.d.ts.map +1 -0
  76. package/dist/renderer.d.ts +1 -0
  77. package/dist/renderer.js +7 -0
  78. package/dist/renderer.mjs +4 -0
  79. package/dist/server/hydration-markers.d.ts.map +1 -1
  80. package/dist/server/index.d.ts +1 -1
  81. package/dist/server/index.d.ts.map +1 -1
  82. package/dist/server/renderer.d.ts.map +1 -1
  83. package/dist/server/stream.d.ts +9 -1
  84. package/dist/server/stream.d.ts.map +1 -1
  85. package/dist/types.d.ts +8 -2
  86. package/dist/types.d.ts.map +1 -1
  87. package/package.json +15 -1
@@ -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,6 @@ 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") {
196
- return "";
197
- }
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;
339
- }
340
- await streamElement(node, controller, encoder);
341
- }
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;
352
- }
353
- await streamNode(children, controller, encoder);
354
- }
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}>`));
371
- }
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;
388
- }
389
166
  // src/reactivity/scheduler.ts
390
167
  var pendingEffects = new Set;
391
168
  var flushScheduled = false;
@@ -628,79 +405,68 @@ function isComputed(value) {
628
405
  return value != null && typeof value === "object" && COMPUTED_BRAND in value;
629
406
  }
630
407
 
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}-->`;
408
+ // src/renderer/dom-ops.ts
409
+ function createDefaultDOMOps() {
410
+ return {
411
+ createElement(tag) {
412
+ return document.createElement(tag);
413
+ },
414
+ createElementNS(namespace, tag) {
415
+ return document.createElementNS(namespace, tag);
416
+ },
417
+ createTextNode(text) {
418
+ return document.createTextNode(text);
419
+ },
420
+ createComment(text) {
421
+ return document.createComment(text);
422
+ },
423
+ setAttribute(el, key, value) {
424
+ el.setAttribute(key, value);
425
+ },
426
+ removeAttribute(el, key) {
427
+ el.removeAttribute(key);
428
+ },
429
+ setProperty(el, key, value) {
430
+ el[key] = value;
431
+ },
432
+ insertBefore(parent, child, anchor) {
433
+ parent.insertBefore(child, anchor);
434
+ },
435
+ appendChild(parent, child) {
436
+ parent.appendChild(child);
437
+ },
438
+ remove(node) {
439
+ node.parentNode?.removeChild(node);
440
+ },
441
+ setTextContent(node, text) {
442
+ node.data = text;
443
+ },
444
+ addEventListener(el, event, handler) {
445
+ el.addEventListener(event, handler);
446
+ },
447
+ removeEventListener(el, event, handler) {
448
+ el.removeEventListener(event, handler);
449
+ },
450
+ parentNode(node) {
451
+ return node.parentNode;
452
+ },
453
+ nextSibling(node) {
454
+ return node.nextSibling;
455
+ }
456
+ };
642
457
  }
643
- function textMarkerCloseStr() {
644
- return `<!--${TEXT_MARKER_CLOSE}-->`;
458
+ var defaultDOMOps = createDefaultDOMOps();
459
+ var domOps = { ...defaultDOMOps };
460
+ function setDOMOps(overrides) {
461
+ Object.assign(domOps, overrides);
645
462
  }
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;
463
+ function resetDOMOps() {
464
+ for (const key of Object.keys(domOps)) {
465
+ delete domOps[key];
651
466
  }
652
- return -1;
653
- }
654
- function isTextCloseMarker(node) {
655
- return node.data === TEXT_MARKER_CLOSE;
467
+ Object.assign(domOps, defaultDOMOps);
656
468
  }
657
469
 
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
470
  // src/renderer/events.ts
705
471
  function isEventProp(key) {
706
472
  return key.length > 2 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z";
@@ -728,24 +494,184 @@ function bindEvents(el, props) {
728
494
  return cleanups;
729
495
  }
730
496
 
731
- // src/component/instance.ts
732
- var uidCounter = 0;
733
- function createComponentInstance(component, props, parent) {
497
+ // src/component/control-flow.ts
498
+ var SHOW_TYPE = Symbol.for("Sinwan.Show");
499
+ var FOR_TYPE = Symbol.for("Sinwan.For");
500
+ function Show(props) {
734
501
  return {
735
- uid: uidCounter++,
736
- component,
502
+ tag: SHOW_TYPE,
737
503
  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
504
+ children: []
505
+ };
506
+ }
507
+ function For(props) {
508
+ return {
509
+ tag: FOR_TYPE,
510
+ props,
511
+ children: []
512
+ };
513
+ }
514
+ function isShowElement(element) {
515
+ return element.tag === SHOW_TYPE;
516
+ }
517
+ function isForElement(element) {
518
+ return element.tag === FOR_TYPE;
519
+ }
520
+
521
+ // src/server/renderer.ts
522
+ var componentCache = new WeakMap;
523
+ var pageRegistry = new Map;
524
+ function registerPage(name, page) {
525
+ pageRegistry.set(name, page);
526
+ }
527
+ function getPage(name) {
528
+ return pageRegistry.get(name);
529
+ }
530
+ function hasPage(name) {
531
+ return pageRegistry.has(name);
532
+ }
533
+ async function renderPage(name, data) {
534
+ const page = getPage(name);
535
+ if (!page) {
536
+ throw new Error(`Page "${name}" not found in registry`);
537
+ }
538
+ const element = await page(data);
539
+ return renderToString(element);
540
+ }
541
+ async function renderToString(node) {
542
+ if (node == null || typeof node === "boolean") {
543
+ return "";
544
+ }
545
+ if (typeof node === "string") {
546
+ return escapeHtml(node);
547
+ }
548
+ if (typeof node === "number") {
549
+ return String(node);
550
+ }
551
+ if (node instanceof HtmlEscapedString) {
552
+ return node.value;
553
+ }
554
+ if (isSignal(node) || isComputed(node)) {
555
+ return escapeHtml(String(node.value));
556
+ }
557
+ if (Array.isArray(node)) {
558
+ const results = await Promise.all(node.map((child) => renderToString(child)));
559
+ return results.join("");
560
+ }
561
+ if (node instanceof Promise) {
562
+ return renderElement(await node);
563
+ }
564
+ return renderElement(node);
565
+ }
566
+ async function renderElement(element) {
567
+ const { tag, props, children } = element;
568
+ if (isShowElement(element)) {
569
+ const when = readReactive(props.when);
570
+ return renderToString(when ? resolveShowChildren(element, when) : props.fallback);
571
+ }
572
+ if (isForElement(element)) {
573
+ return renderForElement(element);
574
+ }
575
+ if (typeof tag === "function") {
576
+ const result = await tag(props);
577
+ return renderToString(result);
578
+ }
579
+ if (typeof tag === "string") {
580
+ return renderIntrinsicElement(tag, props, children);
581
+ }
582
+ return renderToString(children);
583
+ }
584
+ var VOID_ELEMENTS2 = new Set([
585
+ "area",
586
+ "base",
587
+ "br",
588
+ "col",
589
+ "embed",
590
+ "hr",
591
+ "img",
592
+ "input",
593
+ "link",
594
+ "meta",
595
+ "param",
596
+ "source",
597
+ "track",
598
+ "wbr"
599
+ ]);
600
+ async function renderIntrinsicElement(tag, props, children) {
601
+ const attrs = renderAttributes(props);
602
+ if (VOID_ELEMENTS2.has(tag)) {
603
+ return attrs ? `<${tag}${attrs}>` : `<${tag}>`;
604
+ }
605
+ const childrenHtml = await renderChildren(children, props);
606
+ return attrs ? `<${tag}${attrs}>${childrenHtml}</${tag}>` : `<${tag}>${childrenHtml}</${tag}>`;
607
+ }
608
+ function renderAttributes(props) {
609
+ let attrs = "";
610
+ for (const [key, value] of Object.entries(props)) {
611
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
612
+ continue;
613
+ }
614
+ const resolvedValue = readReactive(value);
615
+ if (resolvedValue == null || resolvedValue === false)
616
+ continue;
617
+ const attrName = key === "className" ? "class" : key;
618
+ const finalName = attrName === "htmlFor" ? "for" : attrName;
619
+ if (resolvedValue === true) {
620
+ attrs += ` ${finalName}`;
621
+ continue;
622
+ }
623
+ const attrValue = escapeHtml(String(resolvedValue));
624
+ attrs += ` ${finalName}="${attrValue}"`;
625
+ }
626
+ return attrs;
627
+ }
628
+ async function renderChildren(children, props) {
629
+ const dangerous = props.dangerouslySetInnerHTML;
630
+ if (dangerous && typeof dangerous.__html === "string") {
631
+ return dangerous.__html;
632
+ }
633
+ return renderToString(children);
634
+ }
635
+ function isSlots(children) {
636
+ return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
637
+ }
638
+ async function renderForElement(element) {
639
+ const props = element.props;
640
+ const each = readReactive(props.each);
641
+ if (!Array.isArray(each) || typeof props.children !== "function") {
642
+ return "";
643
+ }
644
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
645
+ return rendered.join("");
646
+ }
647
+ function resolveShowChildren(element, value) {
648
+ const children = element.props.children ?? element.children;
649
+ if (typeof children === "function") {
650
+ return children(value);
651
+ }
652
+ return children;
653
+ }
654
+ function readReactive(value) {
655
+ return isSignal(value) || isComputed(value) ? value.value : value;
656
+ }
657
+ // src/component/instance.ts
658
+ var uidCounter = 0;
659
+ function createComponentInstance(component, props, parent) {
660
+ return {
661
+ uid: uidCounter++,
662
+ component,
663
+ props,
664
+ element: null,
665
+ parent,
666
+ children: [],
667
+ effects: [],
668
+ _mountedHooks: [],
669
+ _unmountedHooks: [],
670
+ _updatedHooks: [],
671
+ _errorHooks: [],
672
+ provides: parent ? Object.create(parent.provides) : Object.create(null),
673
+ isMounted: false,
674
+ isUnmounted: false
749
675
  };
750
676
  }
751
677
  var currentInstance = null;
@@ -757,7 +683,18 @@ function setCurrentInstance(instance) {
757
683
  currentInstance = instance;
758
684
  return prev;
759
685
  }
686
+ function withInstance(instance, fn) {
687
+ const prev = setCurrentInstance(instance);
688
+ try {
689
+ return fn();
690
+ } finally {
691
+ setCurrentInstance(prev);
692
+ }
693
+ }
760
694
  function fireMountedHooks(instance) {
695
+ if (instance.isUnmounted) {
696
+ return;
697
+ }
761
698
  for (const child of instance.children) {
762
699
  fireMountedHooks(child);
763
700
  }
@@ -784,6 +721,24 @@ function fireUnmountedHooks(instance) {
784
721
  instance.effects.length = 0;
785
722
  }
786
723
  }
724
+ function fireUpdatedHooks(instance) {
725
+ for (const hook of instance._updatedHooks) {
726
+ hook();
727
+ }
728
+ }
729
+ var queuedUpdatedHooks = new Set;
730
+ function queueUpdatedHooks(instance) {
731
+ if (!instance || !instance.isMounted || instance.isUnmounted || instance._updatedHooks.length === 0 || queuedUpdatedHooks.has(instance)) {
732
+ return;
733
+ }
734
+ queuedUpdatedHooks.add(instance);
735
+ nextTick(() => {
736
+ queuedUpdatedHooks.delete(instance);
737
+ if (instance.isMounted && !instance.isUnmounted) {
738
+ fireUpdatedHooks(instance);
739
+ }
740
+ });
741
+ }
787
742
  function handleComponentError(instance, err) {
788
743
  let current = instance;
789
744
  while (current) {
@@ -798,6 +753,342 @@ function handleComponentError(instance, err) {
798
753
  console.error("[Sinwan] Unhandled component error:", err);
799
754
  }
800
755
 
756
+ // src/hydration/markers.ts
757
+ var COMP_ID_ATTR = "data-sinwan-id";
758
+ var COMP_ID_PREFIX = "c";
759
+ var TEXT_MARKER_OPEN = "sinwan-t:";
760
+ var TEXT_MARKER_CLOSE = "/sinwan-t";
761
+ var EVENT_ATTR = "data-sinwan-ev";
762
+ function compId(index) {
763
+ return `${COMP_ID_PREFIX}${index}`;
764
+ }
765
+ function textMarkerOpen(index) {
766
+ return `<!--${TEXT_MARKER_OPEN}${index}-->`;
767
+ }
768
+ function textMarkerCloseStr() {
769
+ return `<!--${TEXT_MARKER_CLOSE}-->`;
770
+ }
771
+ function parseTextOpenMarker(node) {
772
+ const data = node.data;
773
+ if (data.startsWith(TEXT_MARKER_OPEN)) {
774
+ const idx = parseInt(data.slice(TEXT_MARKER_OPEN.length), 10);
775
+ return Number.isNaN(idx) ? -1 : idx;
776
+ }
777
+ return -1;
778
+ }
779
+ function isTextCloseMarker(node) {
780
+ return node.data === TEXT_MARKER_CLOSE;
781
+ }
782
+
783
+ // src/server/stream.ts
784
+ function createHydratableStreamContext() {
785
+ return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
786
+ }
787
+ var VOID_ELEMENTS3 = new Set([
788
+ "area",
789
+ "base",
790
+ "br",
791
+ "col",
792
+ "embed",
793
+ "hr",
794
+ "img",
795
+ "input",
796
+ "link",
797
+ "meta",
798
+ "param",
799
+ "source",
800
+ "track",
801
+ "wbr"
802
+ ]);
803
+ function streamPage(page, data) {
804
+ const encoder = new TextEncoder;
805
+ return new ReadableStream({
806
+ async start(controller) {
807
+ try {
808
+ const element = await page(data);
809
+ await streamNode(element, controller, encoder);
810
+ controller.close();
811
+ } catch (error) {
812
+ controller.error(error);
813
+ }
814
+ }
815
+ });
816
+ }
817
+ function streamHydratablePage(component, props) {
818
+ const encoder = new TextEncoder;
819
+ const ctx = createHydratableStreamContext();
820
+ return new ReadableStream({
821
+ async start(controller) {
822
+ try {
823
+ await streamHydratableComponent(component, props ?? {}, controller, encoder, ctx, true);
824
+ controller.close();
825
+ } catch (error) {
826
+ controller.error(error);
827
+ }
828
+ }
829
+ });
830
+ }
831
+ function streamHydratableNode(node) {
832
+ const encoder = new TextEncoder;
833
+ const ctx = createHydratableStreamContext();
834
+ return new ReadableStream({
835
+ async start(controller) {
836
+ try {
837
+ await streamHydratableNodeToController(node, controller, encoder, ctx);
838
+ controller.close();
839
+ } catch (error) {
840
+ controller.error(error);
841
+ }
842
+ }
843
+ });
844
+ }
845
+ async function streamNode(node, controller, encoder) {
846
+ if (node == null || typeof node === "boolean") {
847
+ return;
848
+ }
849
+ if (typeof node === "string") {
850
+ controller.enqueue(encoder.encode(escapeHtml(node)));
851
+ return;
852
+ }
853
+ if (typeof node === "number") {
854
+ controller.enqueue(encoder.encode(String(node)));
855
+ return;
856
+ }
857
+ if (node instanceof HtmlEscapedString) {
858
+ controller.enqueue(encoder.encode(node.value));
859
+ return;
860
+ }
861
+ if (isSignal(node) || isComputed(node)) {
862
+ controller.enqueue(encoder.encode(escapeHtml(String(node.value))));
863
+ return;
864
+ }
865
+ if (Array.isArray(node)) {
866
+ for (const child of node) {
867
+ await streamNode(child, controller, encoder);
868
+ }
869
+ return;
870
+ }
871
+ if (node instanceof Promise) {
872
+ const resolved = await node;
873
+ await streamElement(resolved, controller, encoder);
874
+ return;
875
+ }
876
+ await streamElement(node, controller, encoder);
877
+ }
878
+ async function streamElement(element, controller, encoder) {
879
+ const { tag, props, children } = element;
880
+ if (isShowElement(element)) {
881
+ const when = readReactive2(props.when);
882
+ await streamNode(when ? resolveShowChildren2(element, when) : props.fallback, controller, encoder);
883
+ return;
884
+ }
885
+ if (isForElement(element)) {
886
+ await streamForElement(element, controller, encoder);
887
+ return;
888
+ }
889
+ if (typeof tag === "function") {
890
+ const result = await tag(props);
891
+ await streamNode(result, controller, encoder);
892
+ return;
893
+ }
894
+ if (typeof tag === "string") {
895
+ await streamIntrinsicElement(tag, props, children, controller, encoder);
896
+ return;
897
+ }
898
+ await streamNode(children, controller, encoder);
899
+ }
900
+ async function streamIntrinsicElement(tag, props, children, controller, encoder) {
901
+ const attrs = renderAttributes2(props);
902
+ const dangerous = props.dangerouslySetInnerHTML;
903
+ if (VOID_ELEMENTS3.has(tag)) {
904
+ const html = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
905
+ controller.enqueue(encoder.encode(html));
906
+ return;
907
+ }
908
+ const openTag = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
909
+ controller.enqueue(encoder.encode(openTag));
910
+ if (dangerous && typeof dangerous.__html === "string") {
911
+ controller.enqueue(encoder.encode(dangerous.__html));
912
+ } else {
913
+ await streamNode(children, controller, encoder);
914
+ }
915
+ controller.enqueue(encoder.encode(`</${tag}>`));
916
+ }
917
+ function renderAttributes2(props) {
918
+ let attrs = "";
919
+ for (const [key, value] of Object.entries(props)) {
920
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
921
+ continue;
922
+ }
923
+ const resolvedValue = readReactive2(value);
924
+ if (resolvedValue == null || resolvedValue === false)
925
+ continue;
926
+ const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
927
+ if (resolvedValue === true) {
928
+ attrs += ` ${attrName}`;
929
+ continue;
930
+ }
931
+ const attrValue = escapeHtml(String(resolvedValue));
932
+ attrs += ` ${attrName}="${attrValue}"`;
933
+ }
934
+ return attrs;
935
+ }
936
+ async function streamHydratableNodeToController(node, controller, encoder, ctx, isComponentRoot = false) {
937
+ if (node == null || typeof node === "boolean") {
938
+ return;
939
+ }
940
+ if (typeof node === "string") {
941
+ enqueue(controller, encoder, escapeHtml(node));
942
+ return;
943
+ }
944
+ if (typeof node === "number") {
945
+ enqueue(controller, encoder, String(node));
946
+ return;
947
+ }
948
+ if (node instanceof HtmlEscapedString) {
949
+ enqueue(controller, encoder, node.value);
950
+ return;
951
+ }
952
+ if (isSignal(node) || isComputed(node)) {
953
+ const idx = ctx.textIndex++;
954
+ enqueue(controller, encoder, `${textMarkerOpen(idx)}${escapeHtml(String(node.value))}${textMarkerCloseStr()}`);
955
+ return;
956
+ }
957
+ if (Array.isArray(node)) {
958
+ for (const child of node) {
959
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
960
+ }
961
+ return;
962
+ }
963
+ if (node instanceof Promise) {
964
+ await streamHydratableElement(await node, controller, encoder, ctx, isComponentRoot);
965
+ return;
966
+ }
967
+ await streamHydratableElement(node, controller, encoder, ctx, isComponentRoot);
968
+ }
969
+ async function streamHydratableElement(element, controller, encoder, ctx, isComponentRoot) {
970
+ const { tag, props, children } = element;
971
+ if (tag === "") {
972
+ for (const child of children) {
973
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
974
+ }
975
+ return;
976
+ }
977
+ if (tag === Show || tag === For) {
978
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
979
+ return;
980
+ }
981
+ if (isShowElement(element)) {
982
+ const when = readReactive2(props.when);
983
+ await streamHydratableNodeToController(when ? resolveShowChildren2(element, when) : props.fallback, controller, encoder, ctx, isComponentRoot);
984
+ return;
985
+ }
986
+ if (isForElement(element)) {
987
+ await streamHydratableForElement(element, controller, encoder, ctx);
988
+ return;
989
+ }
990
+ if (typeof tag === "function") {
991
+ await streamHydratableComponent(tag, props, controller, encoder, ctx, true);
992
+ return;
993
+ }
994
+ if (typeof tag === "string") {
995
+ await streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot);
996
+ return;
997
+ }
998
+ await streamHydratableNodeToController(children, controller, encoder, ctx);
999
+ }
1000
+ async function streamHydratableComponent(component, props, controller, encoder, ctx, isComponentRoot) {
1001
+ const parentInstance = getCurrentInstance();
1002
+ const instance = createComponentInstance(component, props, parentInstance);
1003
+ if (parentInstance) {
1004
+ parentInstance.children.push(instance);
1005
+ }
1006
+ const prev = setCurrentInstance(instance);
1007
+ try {
1008
+ const result = await component(props);
1009
+ await streamHydratableNodeToController(result, controller, encoder, ctx, isComponentRoot);
1010
+ } finally {
1011
+ setCurrentInstance(prev);
1012
+ }
1013
+ }
1014
+ async function streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot) {
1015
+ const attrs = renderHydratableAttributes(props, ctx, isComponentRoot);
1016
+ const dangerous = props.dangerouslySetInnerHTML;
1017
+ enqueue(controller, encoder, attrs ? `<${tag}${attrs}>` : `<${tag}>`);
1018
+ if (VOID_ELEMENTS3.has(tag)) {
1019
+ return;
1020
+ }
1021
+ if (dangerous && typeof dangerous.__html === "string") {
1022
+ enqueue(controller, encoder, dangerous.__html);
1023
+ } else {
1024
+ for (const child of children) {
1025
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
1026
+ }
1027
+ }
1028
+ enqueue(controller, encoder, `</${tag}>`);
1029
+ }
1030
+ async function streamHydratableForElement(element, controller, encoder, ctx) {
1031
+ const props = element.props;
1032
+ const each = readReactive2(props.each);
1033
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1034
+ return;
1035
+ }
1036
+ for (let index = 0;index < each.length; index++) {
1037
+ await streamHydratableNodeToController(props.children(each[index], () => index), controller, encoder, ctx);
1038
+ }
1039
+ }
1040
+ function renderHydratableAttributes(props, ctx, isComponentRoot) {
1041
+ let attrs = "";
1042
+ if (isComponentRoot) {
1043
+ attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
1044
+ }
1045
+ const eventParts = [];
1046
+ for (const [key, value] of Object.entries(props)) {
1047
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
1048
+ continue;
1049
+ }
1050
+ if (isEventProp(key)) {
1051
+ eventParts.push(`${toEventName(key)}:${ctx.eventIndex++}`);
1052
+ continue;
1053
+ }
1054
+ const resolvedValue = readReactive2(value);
1055
+ if (resolvedValue == null || resolvedValue === false)
1056
+ continue;
1057
+ const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1058
+ if (resolvedValue === true) {
1059
+ attrs += ` ${attrName}`;
1060
+ continue;
1061
+ }
1062
+ attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
1063
+ }
1064
+ if (eventParts.length > 0) {
1065
+ attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
1066
+ }
1067
+ return attrs;
1068
+ }
1069
+ function enqueue(controller, encoder, html) {
1070
+ controller.enqueue(encoder.encode(html));
1071
+ }
1072
+ async function streamForElement(element, controller, encoder) {
1073
+ const props = element.props;
1074
+ const each = readReactive2(props.each);
1075
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1076
+ return;
1077
+ }
1078
+ for (let index = 0;index < each.length; index++) {
1079
+ await streamNode(props.children(each[index], () => index), controller, encoder);
1080
+ }
1081
+ }
1082
+ function resolveShowChildren2(element, value) {
1083
+ const children = element.props.children ?? element.children;
1084
+ if (typeof children === "function") {
1085
+ return children(value);
1086
+ }
1087
+ return children;
1088
+ }
1089
+ function readReactive2(value) {
1090
+ return isSignal(value) || isComputed(value) ? value.value : value;
1091
+ }
801
1092
  // src/server/hydration-markers.ts
802
1093
  function createHydrationContext() {
803
1094
  return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
@@ -806,13 +1097,16 @@ async function renderToHydratableString(component, props) {
806
1097
  const ctx = createHydrationContext();
807
1098
  const mergedProps = props ?? {};
808
1099
  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);
1100
+ const prev = setCurrentInstance(instance);
1101
+ try {
1102
+ const result = await component(mergedProps);
1103
+ if (result && typeof result === "object" && "tag" in result) {
1104
+ return renderElementH(result, ctx, true);
1105
+ }
1106
+ return renderNodeH(result, ctx);
1107
+ } finally {
1108
+ setCurrentInstance(prev);
814
1109
  }
815
- return renderNodeH(result, ctx);
816
1110
  }
817
1111
  async function renderNodeToHydratableString(node) {
818
1112
  const ctx = createHydrationContext();
@@ -864,6 +1158,17 @@ function renderElementH(element, ctx, isComponentRoot) {
864
1158
  if (tag === "") {
865
1159
  return children.map((child) => renderNodeH(child, ctx)).join("");
866
1160
  }
1161
+ if (tag === Show || tag === For) {
1162
+ return renderElementH(tag(props), ctx, isComponentRoot);
1163
+ }
1164
+ if (isShowElement(element)) {
1165
+ const when = readReactive3(props.when);
1166
+ const content = when ? resolveShowChildren3(element, when) : props.fallback;
1167
+ return renderNodeMaybeRoot(content, ctx, isComponentRoot);
1168
+ }
1169
+ if (isForElement(element)) {
1170
+ return renderForElementH(element, ctx);
1171
+ }
867
1172
  if (typeof tag === "function") {
868
1173
  return renderComponentH(tag, props, ctx);
869
1174
  }
@@ -873,15 +1178,21 @@ function renderElementH(element, ctx, isComponentRoot) {
873
1178
  return children.map((child) => renderNodeH(child, ctx)).join("");
874
1179
  }
875
1180
  function renderComponentH(component, props, ctx) {
876
- const parentInstance = globalThis.__SinwanCurrentInstance;
877
- const instance = createComponentInstance(component, props, null);
1181
+ const parentInstance = getCurrentInstance();
1182
+ const instance = createComponentInstance(component, props, parentInstance);
1183
+ if (parentInstance) {
1184
+ parentInstance.children.push(instance);
1185
+ }
878
1186
  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);
1187
+ try {
1188
+ const result = component(props);
1189
+ if (result && typeof result === "object" && "tag" in result) {
1190
+ return renderElementH(result, ctx, true);
1191
+ }
1192
+ return renderNodeH(result, ctx);
1193
+ } finally {
1194
+ setCurrentInstance(prev);
883
1195
  }
884
- return renderNodeH(result, ctx);
885
1196
  }
886
1197
  function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
887
1198
  let attrs = "";
@@ -890,8 +1201,9 @@ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
890
1201
  }
891
1202
  const eventParts = [];
892
1203
  for (const [key, value] of Object.entries(props)) {
893
- if (key === "children" || key === "dangerouslySetInnerHTML")
1204
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
894
1205
  continue;
1206
+ }
895
1207
  if (isEventProp(key)) {
896
1208
  const eventName = toEventName(key);
897
1209
  eventParts.push(`${eventName}:${ctx.eventIndex++}`);
@@ -924,6 +1236,30 @@ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
924
1236
  const childrenHtml = children.map((child) => renderNodeH(child, ctx)).join("");
925
1237
  return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
926
1238
  }
1239
+ function renderNodeMaybeRoot(node, ctx, isComponentRoot) {
1240
+ if (isComponentRoot && node && typeof node === "object" && !Array.isArray(node) && "tag" in node) {
1241
+ return renderElementH(node, ctx, true);
1242
+ }
1243
+ return renderNodeH(node, ctx);
1244
+ }
1245
+ function renderForElementH(element, ctx) {
1246
+ const props = element.props;
1247
+ const each = readReactive3(props.each);
1248
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1249
+ return "";
1250
+ }
1251
+ return each.map((item, index) => renderNodeH(props.children(item, () => index), ctx)).join("");
1252
+ }
1253
+ function resolveShowChildren3(element, value) {
1254
+ const children = element.props.children ?? element.children;
1255
+ if (typeof children === "function") {
1256
+ return children(value);
1257
+ }
1258
+ return children;
1259
+ }
1260
+ function readReactive3(value) {
1261
+ return isSignal(value) || isComputed(value) ? value.value : value;
1262
+ }
927
1263
 
928
- //# debugId=76A0C66C8E5A5C3C64756E2164756E21
1264
+ //# debugId=107ADB344D9D30F764756E2164756E21
929
1265
  //# sourceMappingURL=index.development.js.map