sinwan 1.0.0 → 1.1.1

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 (54) hide show
  1. package/dist/cjs/index.development.js +1012 -112
  2. package/dist/cjs/index.development.js.map +16 -14
  3. package/dist/cjs/index.production.min.js +2 -2
  4. package/dist/cjs/index.production.min.js.map +16 -14
  5. package/dist/cjs/renderer/index.development.js +467 -29
  6. package/dist/cjs/renderer/index.development.js.map +11 -9
  7. package/dist/cjs/renderer/index.production.min.js +2 -2
  8. package/dist/cjs/renderer/index.production.min.js.map +11 -9
  9. package/dist/cjs/server/index.development.js +573 -48
  10. package/dist/cjs/server/index.development.js.map +10 -7
  11. package/dist/cjs/server/index.production.min.js +2 -2
  12. package/dist/cjs/server/index.production.min.js.map +10 -7
  13. package/dist/component/control-flow.d.ts +54 -1
  14. package/dist/component/control-flow.d.ts.map +1 -1
  15. package/dist/component/index.d.ts +2 -2
  16. package/dist/component/index.d.ts.map +1 -1
  17. package/dist/esm/index.development.js +1010 -110
  18. package/dist/esm/index.development.js.map +16 -14
  19. package/dist/esm/index.production.min.js +2 -2
  20. package/dist/esm/index.production.min.js.map +16 -14
  21. package/dist/esm/renderer/index.development.js +467 -29
  22. package/dist/esm/renderer/index.development.js.map +11 -9
  23. package/dist/esm/renderer/index.production.min.js +2 -2
  24. package/dist/esm/renderer/index.production.min.js.map +11 -9
  25. package/dist/esm/server/index.development.js +573 -48
  26. package/dist/esm/server/index.development.js.map +10 -7
  27. package/dist/esm/server/index.production.min.js +2 -2
  28. package/dist/esm/server/index.production.min.js.map +10 -7
  29. package/dist/hydration/walk.d.ts.map +1 -1
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/reactivity/index.d.ts +1 -0
  33. package/dist/reactivity/index.d.ts.map +1 -1
  34. package/dist/reactivity/normalization.d.ts +19 -0
  35. package/dist/reactivity/normalization.d.ts.map +1 -0
  36. package/dist/renderer/attributes.d.ts +11 -0
  37. package/dist/renderer/attributes.d.ts.map +1 -1
  38. package/dist/renderer/index.d.ts +1 -1
  39. package/dist/renderer/index.d.ts.map +1 -1
  40. package/dist/renderer/render-children.d.ts.map +1 -1
  41. package/dist/renderer/render-control-flow.d.ts +3 -3
  42. package/dist/renderer/render-control-flow.d.ts.map +1 -1
  43. package/dist/renderer/render-element.d.ts.map +1 -1
  44. package/dist/renderer/types.d.ts +8 -1
  45. package/dist/renderer/types.d.ts.map +1 -1
  46. package/dist/renderer/unmount.d.ts.map +1 -1
  47. package/dist/server/attribute-utils.d.ts +2 -0
  48. package/dist/server/attribute-utils.d.ts.map +1 -0
  49. package/dist/server/hydration-markers.d.ts.map +1 -1
  50. package/dist/server/renderer.d.ts.map +1 -1
  51. package/dist/server/stream.d.ts.map +1 -1
  52. package/dist/types.d.ts +2 -2
  53. package/dist/types.d.ts.map +1 -1
  54. package/package.json +5 -5
@@ -316,7 +316,6 @@ function signal(initial) {
316
316
  function isSignal(value) {
317
317
  return value != null && typeof value === "object" && SIGNAL_BRAND in value;
318
318
  }
319
-
320
319
  // src/reactivity/computed.ts
321
320
  var COMPUTED_BRAND = Symbol("Sinwan:computed");
322
321
 
@@ -368,7 +367,32 @@ function computed(getter) {
368
367
  function isComputed(value) {
369
368
  return value != null && typeof value === "object" && COMPUTED_BRAND in value;
370
369
  }
371
-
370
+ // src/reactivity/batch.ts
371
+ var batchDepth = 0;
372
+ function batch(fn) {
373
+ batchDepth++;
374
+ try {
375
+ fn();
376
+ } finally {
377
+ batchDepth--;
378
+ if (batchDepth === 0) {
379
+ flushSync();
380
+ }
381
+ }
382
+ }
383
+ // src/reactivity/normalization.ts
384
+ function isReactive(value) {
385
+ return isSignal(value) || isComputed(value) || typeof value === "function";
386
+ }
387
+ function resolve(value) {
388
+ if (isSignal(value) || isComputed(value)) {
389
+ return value.value;
390
+ }
391
+ if (typeof value === "function") {
392
+ return value();
393
+ }
394
+ return value;
395
+ }
372
396
  // src/renderer/events.ts
373
397
  function isEventProp(key) {
374
398
  return key.length > 2 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z";
@@ -510,10 +534,11 @@ function applyAttributes(el, props) {
510
534
  for (const [key, value] of Object.entries(props)) {
511
535
  if (SKIP_PROPS.has(key) || isEventProp(key))
512
536
  continue;
513
- if (isSignal(value) || isComputed(value)) {
537
+ if (isReactive(value)) {
538
+ const state = { previousStyleProps: new Set };
514
539
  let initialized = false;
515
540
  const dispose = effect(() => {
516
- setSingleAttribute(el, key, value.value);
541
+ setSingleAttribute(el, key, resolve(value), state);
517
542
  if (initialized) {
518
543
  queueUpdatedHooks(owner);
519
544
  }
@@ -526,10 +551,10 @@ function applyAttributes(el, props) {
526
551
  }
527
552
  return disposers;
528
553
  }
529
- function setSingleAttribute(el, key, value) {
530
- const attrName = PROP_ALIASES[key] ?? key;
554
+ function setSingleAttribute(el, key, value, state) {
555
+ const attrName = resolveAttributeName(key);
531
556
  if (attrName === "style" && typeof value === "object" && value !== null) {
532
- applyStyle(el, value);
557
+ applyStyle(el, value, state);
533
558
  return;
534
559
  }
535
560
  if (attrName === "class" && typeof value === "object" && value !== null) {
@@ -538,6 +563,9 @@ function setSingleAttribute(el, key, value) {
538
563
  }
539
564
  if (value == null || value === false) {
540
565
  domOps.removeAttribute(el, attrName);
566
+ if (attrName === "style" && state) {
567
+ state.previousStyleProps.clear();
568
+ }
541
569
  if (DOM_PROPERTIES.has(attrName)) {
542
570
  domOps.setProperty(el, attrName, attrName === "value" ? "" : false);
543
571
  }
@@ -545,25 +573,59 @@ function setSingleAttribute(el, key, value) {
545
573
  }
546
574
  if (value === true) {
547
575
  domOps.setAttribute(el, attrName, "");
576
+ if (attrName === "style" && state) {
577
+ state.previousStyleProps.clear();
578
+ }
548
579
  if (DOM_PROPERTIES.has(attrName)) {
549
580
  domOps.setProperty(el, attrName, true);
550
581
  }
551
582
  return;
552
583
  }
553
584
  if (DOM_PROPERTIES.has(attrName)) {
585
+ if (attrName === "style" && state) {
586
+ state.previousStyleProps.clear();
587
+ }
554
588
  domOps.setProperty(el, attrName, value);
555
589
  return;
556
590
  }
591
+ if (attrName === "style" && state) {
592
+ state.previousStyleProps.clear();
593
+ }
557
594
  domOps.setAttribute(el, attrName, String(value));
558
595
  }
559
- function applyStyle(el, styles) {
596
+ function resolveAttributeName(key) {
597
+ return PROP_ALIASES[key] ?? key;
598
+ }
599
+ function applyStyle(el, styles, state) {
600
+ const nextProps = new Set;
560
601
  for (const [prop, val] of Object.entries(styles)) {
602
+ nextProps.add(prop);
603
+ if (val == null) {
604
+ removeStyleProperty(el, prop);
605
+ continue;
606
+ }
561
607
  if (prop.includes("-")) {
562
- el.style.setProperty(prop, val);
608
+ el.style.setProperty(prop, String(val));
563
609
  } else {
564
610
  el.style[prop] = val;
565
611
  }
566
612
  }
613
+ if (!state) {
614
+ return;
615
+ }
616
+ for (const previousProp of state.previousStyleProps) {
617
+ if (!nextProps.has(previousProp)) {
618
+ removeStyleProperty(el, previousProp);
619
+ }
620
+ }
621
+ state.previousStyleProps = nextProps;
622
+ }
623
+ function removeStyleProperty(el, prop) {
624
+ if (prop.includes("-")) {
625
+ el.style.removeProperty(prop);
626
+ } else {
627
+ el.style[prop] = "";
628
+ }
567
629
  }
568
630
  function applyClass(el, value) {
569
631
  let classStr;
@@ -580,6 +642,12 @@ function applyClass(el, value) {
580
642
  // src/component/control-flow.ts
581
643
  var SHOW_TYPE = Symbol.for("Sinwan.Show");
582
644
  var FOR_TYPE = Symbol.for("Sinwan.For");
645
+ var SWITCH_TYPE = Symbol.for("Sinwan.Switch");
646
+ var MATCH_TYPE = Symbol.for("Sinwan.Match");
647
+ var INDEX_TYPE = Symbol.for("Sinwan.Index");
648
+ var KEY_TYPE = Symbol.for("Sinwan.Key");
649
+ var DYNAMIC_TYPE = Symbol.for("Sinwan.Dynamic");
650
+ var PORTAL_TYPE = Symbol.for("Sinwan.Portal");
583
651
  function Show(props) {
584
652
  return {
585
653
  tag: SHOW_TYPE,
@@ -594,12 +662,114 @@ function For(props) {
594
662
  children: []
595
663
  };
596
664
  }
665
+ function Switch(props) {
666
+ return {
667
+ tag: SWITCH_TYPE,
668
+ props,
669
+ children: []
670
+ };
671
+ }
672
+ function Match(props) {
673
+ return {
674
+ tag: MATCH_TYPE,
675
+ props,
676
+ children: []
677
+ };
678
+ }
679
+ function Index(props) {
680
+ return {
681
+ tag: INDEX_TYPE,
682
+ props,
683
+ children: []
684
+ };
685
+ }
686
+ function Key(props) {
687
+ return {
688
+ tag: KEY_TYPE,
689
+ props,
690
+ children: []
691
+ };
692
+ }
693
+ function Dynamic(props) {
694
+ return {
695
+ tag: DYNAMIC_TYPE,
696
+ props,
697
+ children: []
698
+ };
699
+ }
700
+ function Visible(props) {
701
+ const {
702
+ when,
703
+ as = "span",
704
+ style,
705
+ children,
706
+ ...rest
707
+ } = props;
708
+ const visibleStyle = computed(() => {
709
+ const base = readReactive(style);
710
+ const visible = Boolean(readReactive(when));
711
+ if (typeof base === "string") {
712
+ return visible ? base : appendHiddenDisplay(base);
713
+ }
714
+ const styleObject = base && typeof base === "object" ? { ...base } : {};
715
+ styleObject.display = visible ? styleObject.display : "none";
716
+ return styleObject;
717
+ });
718
+ return {
719
+ tag: as,
720
+ props: {
721
+ ...rest,
722
+ style: visibleStyle,
723
+ children
724
+ },
725
+ children: normalizeChildren2(children)
726
+ };
727
+ }
728
+ function Portal(props) {
729
+ return {
730
+ tag: PORTAL_TYPE,
731
+ props,
732
+ children: []
733
+ };
734
+ }
597
735
  function isShowElement(element) {
598
736
  return element.tag === SHOW_TYPE;
599
737
  }
600
738
  function isForElement(element) {
601
739
  return element.tag === FOR_TYPE;
602
740
  }
741
+ function isSwitchElement(element) {
742
+ return element.tag === SWITCH_TYPE;
743
+ }
744
+ function isMatchElement(element) {
745
+ return element.tag === MATCH_TYPE;
746
+ }
747
+ function isIndexElement(element) {
748
+ return element.tag === INDEX_TYPE;
749
+ }
750
+ function isKeyElement(element) {
751
+ return element.tag === KEY_TYPE;
752
+ }
753
+ function isDynamicElement(element) {
754
+ return element.tag === DYNAMIC_TYPE;
755
+ }
756
+ function isPortalElement(element) {
757
+ return element.tag === PORTAL_TYPE;
758
+ }
759
+ function normalizeChildren2(children) {
760
+ if (children == null || typeof children === "boolean") {
761
+ return [];
762
+ }
763
+ return Array.isArray(children) ? children : [children];
764
+ }
765
+ function readReactive(value) {
766
+ return resolve(value);
767
+ }
768
+ function appendHiddenDisplay(style) {
769
+ const trimmed = style.trim();
770
+ const separator = trimmed.length > 0 && !trimmed.endsWith(";") ? ";" : "";
771
+ return `${trimmed}${separator}display:none`;
772
+ }
603
773
 
604
774
  // src/renderer/unmount.ts
605
775
  function getMountedDomNodes(node) {
@@ -622,6 +792,8 @@ function getMountedDomNodes(node) {
622
792
  ];
623
793
  case "component":
624
794
  return node.children.flatMap((child) => getMountedDomNodes(child));
795
+ case "portal":
796
+ return [node.anchor];
625
797
  }
626
798
  }
627
799
  function unmountNode(node) {
@@ -666,6 +838,13 @@ function unmountNode(node) {
666
838
  unmountNode(child);
667
839
  }
668
840
  break;
841
+ case "portal":
842
+ node.dispose();
843
+ for (const child of node.children) {
844
+ removeMountedNode(child);
845
+ }
846
+ node.children = [];
847
+ break;
669
848
  }
670
849
  }
671
850
  function removeMountedNode(node) {
@@ -680,6 +859,9 @@ function removeMountedNode(node) {
680
859
 
681
860
  // src/renderer/render-control-flow.ts
682
861
  function renderControlFlowToDOM(element, parent, anchor, namespace) {
862
+ if (isPortalElement(element)) {
863
+ return renderPortal(element, parent, anchor, namespace);
864
+ }
683
865
  const startAnchor = domOps.createComment("Sinwan-b");
684
866
  const endAnchor = domOps.createComment("/Sinwan-b");
685
867
  insertNode(parent, startAnchor, anchor);
@@ -697,6 +879,14 @@ function renderControlFlowToDOM(element, parent, anchor, namespace) {
697
879
  disposeEffect = renderShowBlock(element, block, parent, namespace, owner);
698
880
  } else if (isForElement(element)) {
699
881
  disposeEffect = renderForBlock(element, block, parent, namespace, owner);
882
+ } else if (isSwitchElement(element)) {
883
+ disposeEffect = renderSwitchBlock(element, block, parent, namespace, owner);
884
+ } else if (isIndexElement(element)) {
885
+ disposeEffect = renderIndexBlock(element, block, parent, namespace, owner);
886
+ } else if (isKeyElement(element)) {
887
+ disposeEffect = renderKeyBlock(element, block, parent, namespace, owner);
888
+ } else if (isDynamicElement(element)) {
889
+ disposeEffect = renderDynamicBlock(element, block, parent, namespace, owner);
700
890
  }
701
891
  return block;
702
892
  }
@@ -704,7 +894,7 @@ function renderShowBlock(element, block, parent, namespace, owner) {
704
894
  let initialized = false;
705
895
  return effect(() => {
706
896
  clearChildren(block);
707
- const when = readReactive(element.props.when);
897
+ const when = readReactive2(element.props.when);
708
898
  const content = withOptionalInstance(owner, () => when ? resolveShowChildren(element, when) : element.props.fallback);
709
899
  block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
710
900
  if (initialized) {
@@ -718,7 +908,7 @@ function renderForBlock(element, block, parent, namespace, owner) {
718
908
  let records = [];
719
909
  return effect(() => {
720
910
  const props = element.props;
721
- const items = readReactive(props.each);
911
+ const items = readReactive2(props.each);
722
912
  const list = Array.isArray(items) ? items : [];
723
913
  const renderChild = props.children;
724
914
  if (typeof renderChild !== "function") {
@@ -730,6 +920,19 @@ function renderForBlock(element, block, parent, namespace, owner) {
730
920
  initialized = true;
731
921
  return;
732
922
  }
923
+ if (list.length === 0) {
924
+ clearChildren(block);
925
+ records = [];
926
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
927
+ if (initialized) {
928
+ fireMountedAndQueueUpdated(owner);
929
+ }
930
+ initialized = true;
931
+ return;
932
+ }
933
+ if (records.length === 0 && block.children.length > 0) {
934
+ clearChildren(block);
935
+ }
733
936
  const oldByKey = new Map;
734
937
  for (const record of records) {
735
938
  oldByKey.set(record.key, record);
@@ -769,6 +972,137 @@ function renderForBlock(element, block, parent, namespace, owner) {
769
972
  initialized = true;
770
973
  });
771
974
  }
975
+ function renderSwitchBlock(element, block, parent, namespace, owner) {
976
+ let initialized = false;
977
+ return effect(() => {
978
+ clearChildren(block);
979
+ const content = withOptionalInstance(owner, () => resolveSwitchContent(element));
980
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
981
+ if (initialized) {
982
+ fireMountedAndQueueUpdated(owner);
983
+ }
984
+ initialized = true;
985
+ });
986
+ }
987
+ function renderIndexBlock(element, block, parent, namespace, owner) {
988
+ let initialized = false;
989
+ let records = [];
990
+ return effect(() => {
991
+ const props = element.props;
992
+ const items = readReactive2(props.each);
993
+ const list = Array.isArray(items) ? items : [];
994
+ const renderChild = props.children;
995
+ if (typeof renderChild !== "function") {
996
+ clearChildren(block);
997
+ records = [];
998
+ if (initialized) {
999
+ queueUpdatedHooks(owner);
1000
+ }
1001
+ initialized = true;
1002
+ return;
1003
+ }
1004
+ if (list.length === 0) {
1005
+ clearChildren(block);
1006
+ records = [];
1007
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
1008
+ if (initialized) {
1009
+ fireMountedAndQueueUpdated(owner);
1010
+ }
1011
+ initialized = true;
1012
+ return;
1013
+ }
1014
+ if (records.length === 0 && block.children.length > 0) {
1015
+ clearChildren(block);
1016
+ }
1017
+ for (let index = 0;index < list.length; index++) {
1018
+ const existing = records[index];
1019
+ if (existing) {
1020
+ existing.item.value = list[index];
1021
+ continue;
1022
+ }
1023
+ const itemSignal = signal(list[index]);
1024
+ const record = {
1025
+ item: itemSignal,
1026
+ mounted: withOptionalInstance(owner, () => renderNodeToDOM(renderChild(() => itemSignal.value, index), parent, block.endAnchor, namespace))
1027
+ };
1028
+ records.push(record);
1029
+ }
1030
+ while (records.length > list.length) {
1031
+ const removed = records.pop();
1032
+ removeMountedNode(removed.mounted);
1033
+ }
1034
+ block.children = records.map((record) => record.mounted);
1035
+ if (initialized) {
1036
+ fireMountedAndQueueUpdated(owner);
1037
+ }
1038
+ initialized = true;
1039
+ });
1040
+ }
1041
+ function renderKeyBlock(element, block, parent, namespace, owner) {
1042
+ let initialized = false;
1043
+ let hasKey = false;
1044
+ let currentKey;
1045
+ return effect(() => {
1046
+ const key = readReactive2(element.props.when);
1047
+ if (hasKey && Object.is(currentKey, key)) {
1048
+ return;
1049
+ }
1050
+ currentKey = key;
1051
+ hasKey = true;
1052
+ clearChildren(block);
1053
+ const content = withOptionalInstance(owner, () => resolveKeyChildren(element, key));
1054
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1055
+ if (initialized) {
1056
+ fireMountedAndQueueUpdated(owner);
1057
+ }
1058
+ initialized = true;
1059
+ });
1060
+ }
1061
+ function renderDynamicBlock(element, block, parent, namespace, owner) {
1062
+ let initialized = false;
1063
+ let hasTag = false;
1064
+ let currentTag;
1065
+ return effect(() => {
1066
+ const tag = readReactive2(element.props.component);
1067
+ if (hasTag && Object.is(currentTag, tag)) {
1068
+ return;
1069
+ }
1070
+ currentTag = tag;
1071
+ hasTag = true;
1072
+ clearChildren(block);
1073
+ const content = tag ? createDynamicElement(element, tag) : null;
1074
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1075
+ if (initialized) {
1076
+ fireMountedAndQueueUpdated(owner);
1077
+ }
1078
+ initialized = true;
1079
+ });
1080
+ }
1081
+ function renderPortal(element, parent, anchor, namespace) {
1082
+ const placeholder = domOps.createComment("Sinwan-p");
1083
+ insertNode(parent, placeholder, anchor);
1084
+ const owner = getCurrentInstance();
1085
+ let disposeEffect = () => {};
1086
+ const portal = {
1087
+ type: "portal",
1088
+ anchor: placeholder,
1089
+ children: [],
1090
+ dispose: () => disposeEffect()
1091
+ };
1092
+ let initialized = false;
1093
+ disposeEffect = effect(() => {
1094
+ clearPortalChildren(portal);
1095
+ const target = resolvePortalTarget(element.props.mount);
1096
+ if (target) {
1097
+ portal.children = renderBlockContent(element.props.children ?? element.children, target, null, namespace, owner);
1098
+ }
1099
+ if (initialized) {
1100
+ fireMountedAndQueueUpdated(owner);
1101
+ }
1102
+ initialized = true;
1103
+ });
1104
+ return portal;
1105
+ }
772
1106
  function resolveShowChildren(element, value) {
773
1107
  const children = element.props.children ?? element.children;
774
1108
  if (typeof children === "function") {
@@ -776,6 +1110,47 @@ function resolveShowChildren(element, value) {
776
1110
  }
777
1111
  return children;
778
1112
  }
1113
+ function resolveSwitchContent(element) {
1114
+ const props = element.props;
1115
+ const children = normalizeContent(props.children ?? element.children);
1116
+ for (const child of children) {
1117
+ const match = getMatchElement(child);
1118
+ if (!match) {
1119
+ continue;
1120
+ }
1121
+ const when = readReactive2(match.props.when);
1122
+ if (when) {
1123
+ return resolveMatchChildren(match, when);
1124
+ }
1125
+ }
1126
+ return props.fallback;
1127
+ }
1128
+ function resolveMatchChildren(element, value) {
1129
+ const children = element.props.children ?? element.children;
1130
+ if (typeof children === "function") {
1131
+ return children(value);
1132
+ }
1133
+ return children;
1134
+ }
1135
+ function resolveKeyChildren(element, value) {
1136
+ const children = element.props.children ?? element.children;
1137
+ if (typeof children === "function") {
1138
+ return children(value);
1139
+ }
1140
+ return children;
1141
+ }
1142
+ function createDynamicElement(element, tag) {
1143
+ if (typeof tag !== "string" && typeof tag !== "function") {
1144
+ return null;
1145
+ }
1146
+ const { component, ...props } = element.props;
1147
+ const children = normalizeContent(props.children ?? element.children);
1148
+ return {
1149
+ tag,
1150
+ props,
1151
+ children
1152
+ };
1153
+ }
779
1154
  function renderBlockContent(content, parent, anchor, namespace, owner) {
780
1155
  if (content == null || typeof content === "boolean") {
781
1156
  return [];
@@ -789,6 +1164,12 @@ function clearChildren(block) {
789
1164
  }
790
1165
  block.children = [];
791
1166
  }
1167
+ function clearPortalChildren(portal) {
1168
+ for (const child of portal.children) {
1169
+ removeMountedNode(child);
1170
+ }
1171
+ portal.children = [];
1172
+ }
792
1173
  function moveBeforeEnd(parent, mounted, endAnchor) {
793
1174
  for (const node of getMountedDomNodes(mounted)) {
794
1175
  domOps.insertBefore(parent, node, endAnchor);
@@ -803,8 +1184,42 @@ function fireMountedAndQueueUpdated(owner) {
803
1184
  function withOptionalInstance(owner, fn) {
804
1185
  return owner ? withInstance(owner, fn) : fn();
805
1186
  }
806
- function readReactive(value) {
807
- return isSignal(value) || isComputed(value) ? value.value : value;
1187
+ function readReactive2(value) {
1188
+ return resolve(value);
1189
+ }
1190
+ function normalizeContent(content) {
1191
+ if (content == null || typeof content === "boolean") {
1192
+ return [];
1193
+ }
1194
+ return Array.isArray(content) ? content : [content];
1195
+ }
1196
+ function isElementLike(value) {
1197
+ return value != null && typeof value === "object" && "tag" in value;
1198
+ }
1199
+ function getMatchElement(value) {
1200
+ if (!isElementLike(value)) {
1201
+ return null;
1202
+ }
1203
+ if (isMatchElement(value)) {
1204
+ return value;
1205
+ }
1206
+ return value.tag === Match ? Match(value.props) : null;
1207
+ }
1208
+ function resolvePortalTarget(value) {
1209
+ const target = readReactive2(value);
1210
+ if (target == null) {
1211
+ return typeof document === "undefined" ? null : document.body;
1212
+ }
1213
+ if (typeof target === "string") {
1214
+ return document.querySelector(target);
1215
+ }
1216
+ if (typeof target === "function") {
1217
+ return target();
1218
+ }
1219
+ if (typeof target === "object" && "nodeType" in target) {
1220
+ return target;
1221
+ }
1222
+ return null;
808
1223
  }
809
1224
  function insertNode(parent, child, anchor) {
810
1225
  if (anchor) {
@@ -838,10 +1253,13 @@ function renderElementToDOM(element, parent, anchor = null, namespace = null) {
838
1253
  if (tag === "" || tag === Fragment) {
839
1254
  return renderFragmentToDOM(children, parent, anchor, namespace);
840
1255
  }
841
- if (tag === Show || tag === For) {
1256
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1257
+ return renderElementToDOM(tag(props), parent, anchor, namespace);
1258
+ }
1259
+ if (tag === Visible) {
842
1260
  return renderElementToDOM(tag(props), parent, anchor, namespace);
843
1261
  }
844
- if (isShowElement(element) || isForElement(element)) {
1262
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element) || isPortalElement(element)) {
845
1263
  return renderControlFlowToDOM(element, parent, anchor, namespace);
846
1264
  }
847
1265
  if (typeof tag === "function") {
@@ -988,19 +1406,8 @@ function renderNodeToDOM(node, parent, anchor = null, namespace = null) {
988
1406
  insertNode2(parent, text2, anchor);
989
1407
  return { type: "text", node: text2 };
990
1408
  }
991
- if (isSignal(node) || isComputed(node)) {
992
- const text2 = domOps.createTextNode(String(node.value));
993
- insertNode2(parent, text2, anchor);
994
- const owner = getCurrentInstance();
995
- let initialized = false;
996
- const dispose = effect(() => {
997
- domOps.setTextContent(text2, String(node.value));
998
- if (initialized) {
999
- queueUpdatedHooks(owner);
1000
- }
1001
- initialized = true;
1002
- });
1003
- return { type: "reactive-text", node: text2, dispose };
1409
+ if (isReactive(node)) {
1410
+ return renderReactiveNodeToDOM(node, parent, anchor, namespace);
1004
1411
  }
1005
1412
  if (Array.isArray(node)) {
1006
1413
  return renderArrayToDOM(node, parent, anchor, namespace);
@@ -1037,6 +1444,37 @@ function renderChildrenToDOM(children, parent, namespace = null) {
1037
1444
  }
1038
1445
  return mounted;
1039
1446
  }
1447
+ function renderReactiveNodeToDOM(reactive, parent, anchor, namespace) {
1448
+ const startAnchor = domOps.createComment("Sinwan-r");
1449
+ const endAnchor = domOps.createComment("/Sinwan-r");
1450
+ insertNode2(parent, startAnchor, anchor);
1451
+ insertNode2(parent, endAnchor, anchor);
1452
+ const owner = getCurrentInstance();
1453
+ let mountedContent = null;
1454
+ let initialized = false;
1455
+ const block = {
1456
+ type: "reactive-block",
1457
+ startAnchor,
1458
+ endAnchor,
1459
+ children: [],
1460
+ dispose: () => {}
1461
+ };
1462
+ block.dispose = effect(() => {
1463
+ if (mountedContent) {
1464
+ removeMountedNode(mountedContent);
1465
+ }
1466
+ const value = resolve(reactive);
1467
+ mountedContent = renderNodeToDOM(value, parent, endAnchor, namespace);
1468
+ block.children = [mountedContent];
1469
+ if (initialized) {
1470
+ if (owner)
1471
+ fireMountedHooks(owner);
1472
+ queueUpdatedHooks(owner);
1473
+ }
1474
+ initialized = true;
1475
+ });
1476
+ return block;
1477
+ }
1040
1478
  function insertNode2(parent, child, anchor) {
1041
1479
  if (anchor) {
1042
1480
  domOps.insertBefore(parent, child, anchor);
@@ -1137,13 +1575,44 @@ function isSafeHtml(value) {
1137
1575
  return value instanceof HtmlEscapedString;
1138
1576
  }
1139
1577
 
1140
- // src/server/renderer.ts
1141
- var componentCache = new WeakMap;
1142
- var pageRegistry = new Map;
1143
- function registerPage(name, page) {
1144
- pageRegistry.set(name, page);
1145
- }
1146
- function getPage(name) {
1578
+ // src/server/attribute-utils.ts
1579
+ var PROP_ALIASES2 = {
1580
+ className: "class",
1581
+ htmlFor: "for",
1582
+ tabIndex: "tabindex",
1583
+ crossOrigin: "crossorigin"
1584
+ };
1585
+ function renderServerAttribute(key, value) {
1586
+ const attrName = PROP_ALIASES2[key] ?? key;
1587
+ if (value == null || value === false) {
1588
+ return "";
1589
+ }
1590
+ if (value === true) {
1591
+ return ` ${attrName}`;
1592
+ }
1593
+ const attrValue = attrName === "class" && typeof value === "object" ? stringifyClass(value) : attrName === "style" && typeof value === "object" ? stringifyStyle(value) : String(value);
1594
+ return ` ${attrName}="${escapeHtml(attrValue)}"`;
1595
+ }
1596
+ function stringifyClass(value) {
1597
+ if (Array.isArray(value)) {
1598
+ return value.filter(Boolean).join(" ");
1599
+ }
1600
+ return Object.entries(value).filter(([, enabled]) => Boolean(enabled)).map(([name]) => name).join(" ");
1601
+ }
1602
+ function stringifyStyle(value) {
1603
+ return Object.entries(value).filter(([, val]) => val != null && val !== false).map(([prop, val]) => `${toKebabCase(prop)}:${String(val)}`).join(";");
1604
+ }
1605
+ function toKebabCase(value) {
1606
+ return value.includes("-") ? value : value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
1607
+ }
1608
+
1609
+ // src/server/renderer.ts
1610
+ var componentCache = new WeakMap;
1611
+ var pageRegistry = new Map;
1612
+ function registerPage(name, page) {
1613
+ pageRegistry.set(name, page);
1614
+ }
1615
+ function getPage(name) {
1147
1616
  return pageRegistry.get(name);
1148
1617
  }
1149
1618
  function hasPage(name) {
@@ -1184,13 +1653,41 @@ async function renderToString(node) {
1184
1653
  }
1185
1654
  async function renderElement(element) {
1186
1655
  const { tag, props, children } = element;
1656
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1657
+ return renderElement(tag(props));
1658
+ }
1659
+ if (tag === Visible) {
1660
+ return renderElement(tag(props));
1661
+ }
1187
1662
  if (isShowElement(element)) {
1188
- const when = readReactive2(props.when);
1663
+ const when = readReactive3(props.when);
1189
1664
  return renderToString(when ? resolveShowChildren2(element, when) : props.fallback);
1190
1665
  }
1191
1666
  if (isForElement(element)) {
1192
1667
  return renderForElement(element);
1193
1668
  }
1669
+ if (isSwitchElement(element)) {
1670
+ return renderToString(resolveSwitchContent2(element));
1671
+ }
1672
+ if (isMatchElement(element)) {
1673
+ const when = readReactive3(props.when);
1674
+ return renderToString(when ? resolveMatchChildren2(element, when) : null);
1675
+ }
1676
+ if (isIndexElement(element)) {
1677
+ return renderIndexElement(element);
1678
+ }
1679
+ if (isKeyElement(element)) {
1680
+ const key = readReactive3(props.when);
1681
+ return renderToString(resolveKeyChildren2(element, key));
1682
+ }
1683
+ if (isDynamicElement(element)) {
1684
+ const tag2 = readReactive3(props.component);
1685
+ const dynamic = createDynamicElement2(element, tag2);
1686
+ return dynamic ? renderElement(dynamic) : "";
1687
+ }
1688
+ if (isPortalElement(element)) {
1689
+ return "";
1690
+ }
1194
1691
  if (typeof tag === "function") {
1195
1692
  const result = await tag(props);
1196
1693
  return renderToString(result);
@@ -1230,17 +1727,10 @@ function renderAttributes(props) {
1230
1727
  if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
1231
1728
  continue;
1232
1729
  }
1233
- const resolvedValue = readReactive2(value);
1730
+ const resolvedValue = readReactive3(value);
1234
1731
  if (resolvedValue == null || resolvedValue === false)
1235
1732
  continue;
1236
- const attrName = key === "className" ? "class" : key;
1237
- const finalName = attrName === "htmlFor" ? "for" : attrName;
1238
- if (resolvedValue === true) {
1239
- attrs += ` ${finalName}`;
1240
- continue;
1241
- }
1242
- const attrValue = escapeHtml(String(resolvedValue));
1243
- attrs += ` ${finalName}="${attrValue}"`;
1733
+ attrs += renderServerAttribute(key, resolvedValue);
1244
1734
  }
1245
1735
  return attrs;
1246
1736
  }
@@ -1256,13 +1746,69 @@ function isSlots(children) {
1256
1746
  }
1257
1747
  async function renderForElement(element) {
1258
1748
  const props = element.props;
1259
- const each = readReactive2(props.each);
1749
+ const each = readReactive3(props.each);
1260
1750
  if (!Array.isArray(each) || typeof props.children !== "function") {
1261
- return "";
1751
+ return props.fallback ? renderToString(props.fallback) : "";
1752
+ }
1753
+ if (each.length === 0) {
1754
+ return props.fallback ? renderToString(props.fallback) : "";
1262
1755
  }
1263
1756
  const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
1264
1757
  return rendered.join("");
1265
1758
  }
1759
+ async function renderIndexElement(element) {
1760
+ const props = element.props;
1761
+ const each = readReactive3(props.each);
1762
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1763
+ return props.fallback ? renderToString(props.fallback) : "";
1764
+ }
1765
+ if (each.length === 0) {
1766
+ return props.fallback ? renderToString(props.fallback) : "";
1767
+ }
1768
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(() => item, index))));
1769
+ return rendered.join("");
1770
+ }
1771
+ function resolveSwitchContent2(element) {
1772
+ const props = element.props;
1773
+ const children = normalizeContent2(props.children ?? element.children);
1774
+ for (const child of children) {
1775
+ const match = getMatchElement2(child);
1776
+ if (!match) {
1777
+ continue;
1778
+ }
1779
+ const when = readReactive3(match.props.when);
1780
+ if (when) {
1781
+ return resolveMatchChildren2(match, when);
1782
+ }
1783
+ }
1784
+ return props.fallback;
1785
+ }
1786
+ function resolveMatchChildren2(element, value) {
1787
+ const children = element.props.children ?? element.children;
1788
+ if (typeof children === "function") {
1789
+ return children(value);
1790
+ }
1791
+ return children;
1792
+ }
1793
+ function resolveKeyChildren2(element, value) {
1794
+ const children = element.props.children ?? element.children;
1795
+ if (typeof children === "function") {
1796
+ return children(value);
1797
+ }
1798
+ return children;
1799
+ }
1800
+ function createDynamicElement2(element, tag) {
1801
+ if (typeof tag !== "string" && typeof tag !== "function") {
1802
+ return null;
1803
+ }
1804
+ const { component, ...props } = element.props;
1805
+ const children = normalizeContent2(props.children ?? element.children);
1806
+ return {
1807
+ tag,
1808
+ props,
1809
+ children
1810
+ };
1811
+ }
1266
1812
  function resolveShowChildren2(element, value) {
1267
1813
  const children = element.props.children ?? element.children;
1268
1814
  if (typeof children === "function") {
@@ -1270,9 +1816,27 @@ function resolveShowChildren2(element, value) {
1270
1816
  }
1271
1817
  return children;
1272
1818
  }
1273
- function readReactive2(value) {
1819
+ function readReactive3(value) {
1274
1820
  return isSignal(value) || isComputed(value) ? value.value : value;
1275
1821
  }
1822
+ function normalizeContent2(content) {
1823
+ if (content == null || typeof content === "boolean") {
1824
+ return [];
1825
+ }
1826
+ return Array.isArray(content) ? content : [content];
1827
+ }
1828
+ function isElementLike2(value) {
1829
+ return value != null && typeof value === "object" && "tag" in value;
1830
+ }
1831
+ function getMatchElement2(value) {
1832
+ if (!isElementLike2(value)) {
1833
+ return null;
1834
+ }
1835
+ if (isMatchElement(value)) {
1836
+ return value;
1837
+ }
1838
+ return value.tag === Match ? Match(value.props) : null;
1839
+ }
1276
1840
  // src/hydration/markers.ts
1277
1841
  var COMP_ID_ATTR = "data-sinwan-id";
1278
1842
  var COMP_ID_PREFIX = "c";
@@ -1397,8 +1961,16 @@ async function streamNode(node, controller, encoder) {
1397
1961
  }
1398
1962
  async function streamElement(element, controller, encoder) {
1399
1963
  const { tag, props, children } = element;
1964
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1965
+ await streamElement(tag(props), controller, encoder);
1966
+ return;
1967
+ }
1968
+ if (tag === Visible) {
1969
+ await streamElement(tag(props), controller, encoder);
1970
+ return;
1971
+ }
1400
1972
  if (isShowElement(element)) {
1401
- const when = readReactive3(props.when);
1973
+ const when = readReactive4(props.when);
1402
1974
  await streamNode(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder);
1403
1975
  return;
1404
1976
  }
@@ -1406,6 +1978,35 @@ async function streamElement(element, controller, encoder) {
1406
1978
  await streamForElement(element, controller, encoder);
1407
1979
  return;
1408
1980
  }
1981
+ if (isSwitchElement(element)) {
1982
+ await streamNode(resolveSwitchContent3(element), controller, encoder);
1983
+ return;
1984
+ }
1985
+ if (isMatchElement(element)) {
1986
+ const when = readReactive4(props.when);
1987
+ await streamNode(when ? resolveMatchChildren3(element, when) : null, controller, encoder);
1988
+ return;
1989
+ }
1990
+ if (isIndexElement(element)) {
1991
+ await streamIndexElement(element, controller, encoder);
1992
+ return;
1993
+ }
1994
+ if (isKeyElement(element)) {
1995
+ const key = readReactive4(props.when);
1996
+ await streamNode(resolveKeyChildren3(element, key), controller, encoder);
1997
+ return;
1998
+ }
1999
+ if (isDynamicElement(element)) {
2000
+ const dynamicTag = readReactive4(props.component);
2001
+ const dynamic = createDynamicElement3(element, dynamicTag);
2002
+ if (dynamic) {
2003
+ await streamElement(dynamic, controller, encoder);
2004
+ }
2005
+ return;
2006
+ }
2007
+ if (isPortalElement(element)) {
2008
+ return;
2009
+ }
1409
2010
  if (typeof tag === "function") {
1410
2011
  const result = await tag(props);
1411
2012
  await streamNode(result, controller, encoder);
@@ -1440,16 +2041,10 @@ function renderAttributes2(props) {
1440
2041
  if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
1441
2042
  continue;
1442
2043
  }
1443
- const resolvedValue = readReactive3(value);
2044
+ const resolvedValue = readReactive4(value);
1444
2045
  if (resolvedValue == null || resolvedValue === false)
1445
2046
  continue;
1446
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1447
- if (resolvedValue === true) {
1448
- attrs += ` ${attrName}`;
1449
- continue;
1450
- }
1451
- const attrValue = escapeHtml(String(resolvedValue));
1452
- attrs += ` ${attrName}="${attrValue}"`;
2047
+ attrs += renderServerAttribute(key, resolvedValue);
1453
2048
  }
1454
2049
  return attrs;
1455
2050
  }
@@ -1494,12 +2089,16 @@ async function streamHydratableElement(element, controller, encoder, ctx, isComp
1494
2089
  }
1495
2090
  return;
1496
2091
  }
1497
- if (tag === Show || tag === For) {
2092
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2093
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
2094
+ return;
2095
+ }
2096
+ if (tag === Visible) {
1498
2097
  await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
1499
2098
  return;
1500
2099
  }
1501
2100
  if (isShowElement(element)) {
1502
- const when = readReactive3(props.when);
2101
+ const when = readReactive4(props.when);
1503
2102
  await streamHydratableNodeToController(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder, ctx, isComponentRoot);
1504
2103
  return;
1505
2104
  }
@@ -1507,6 +2106,35 @@ async function streamHydratableElement(element, controller, encoder, ctx, isComp
1507
2106
  await streamHydratableForElement(element, controller, encoder, ctx);
1508
2107
  return;
1509
2108
  }
2109
+ if (isSwitchElement(element)) {
2110
+ await streamHydratableNodeToController(resolveSwitchContent3(element), controller, encoder, ctx, isComponentRoot);
2111
+ return;
2112
+ }
2113
+ if (isMatchElement(element)) {
2114
+ const when = readReactive4(props.when);
2115
+ await streamHydratableNodeToController(when ? resolveMatchChildren3(element, when) : null, controller, encoder, ctx, isComponentRoot);
2116
+ return;
2117
+ }
2118
+ if (isIndexElement(element)) {
2119
+ await streamHydratableIndexElement(element, controller, encoder, ctx);
2120
+ return;
2121
+ }
2122
+ if (isKeyElement(element)) {
2123
+ const key = readReactive4(props.when);
2124
+ await streamHydratableNodeToController(resolveKeyChildren3(element, key), controller, encoder, ctx, isComponentRoot);
2125
+ return;
2126
+ }
2127
+ if (isDynamicElement(element)) {
2128
+ const dynamicTag = readReactive4(props.component);
2129
+ const dynamic = createDynamicElement3(element, dynamicTag);
2130
+ if (dynamic) {
2131
+ await streamHydratableElement(dynamic, controller, encoder, ctx, isComponentRoot);
2132
+ }
2133
+ return;
2134
+ }
2135
+ if (isPortalElement(element)) {
2136
+ return;
2137
+ }
1510
2138
  if (typeof tag === "function") {
1511
2139
  await streamHydratableComponent(tag, props, controller, encoder, ctx, true);
1512
2140
  return;
@@ -1549,14 +2177,42 @@ async function streamHydratableIntrinsic(tag, props, children, controller, encod
1549
2177
  }
1550
2178
  async function streamHydratableForElement(element, controller, encoder, ctx) {
1551
2179
  const props = element.props;
1552
- const each = readReactive3(props.each);
2180
+ const each = readReactive4(props.each);
1553
2181
  if (!Array.isArray(each) || typeof props.children !== "function") {
2182
+ if (props.fallback) {
2183
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2184
+ }
2185
+ return;
2186
+ }
2187
+ if (each.length === 0) {
2188
+ if (props.fallback) {
2189
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2190
+ }
1554
2191
  return;
1555
2192
  }
1556
2193
  for (let index = 0;index < each.length; index++) {
1557
2194
  await streamHydratableNodeToController(props.children(each[index], () => index), controller, encoder, ctx);
1558
2195
  }
1559
2196
  }
2197
+ async function streamHydratableIndexElement(element, controller, encoder, ctx) {
2198
+ const props = element.props;
2199
+ const each = readReactive4(props.each);
2200
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2201
+ if (props.fallback) {
2202
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2203
+ }
2204
+ return;
2205
+ }
2206
+ if (each.length === 0) {
2207
+ if (props.fallback) {
2208
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2209
+ }
2210
+ return;
2211
+ }
2212
+ for (let index = 0;index < each.length; index++) {
2213
+ await streamHydratableNodeToController(props.children(() => each[index], index), controller, encoder, ctx);
2214
+ }
2215
+ }
1560
2216
  function renderHydratableAttributes(props, ctx, isComponentRoot) {
1561
2217
  let attrs = "";
1562
2218
  if (isComponentRoot) {
@@ -1571,15 +2227,10 @@ function renderHydratableAttributes(props, ctx, isComponentRoot) {
1571
2227
  eventParts.push(`${toEventName(key)}:${ctx.eventIndex++}`);
1572
2228
  continue;
1573
2229
  }
1574
- const resolvedValue = readReactive3(value);
2230
+ const resolvedValue = readReactive4(value);
1575
2231
  if (resolvedValue == null || resolvedValue === false)
1576
2232
  continue;
1577
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1578
- if (resolvedValue === true) {
1579
- attrs += ` ${attrName}`;
1580
- continue;
1581
- }
1582
- attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
2233
+ attrs += renderServerAttribute(key, resolvedValue);
1583
2234
  }
1584
2235
  if (eventParts.length > 0) {
1585
2236
  attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
@@ -1591,14 +2242,42 @@ function enqueue(controller, encoder, html) {
1591
2242
  }
1592
2243
  async function streamForElement(element, controller, encoder) {
1593
2244
  const props = element.props;
1594
- const each = readReactive3(props.each);
2245
+ const each = readReactive4(props.each);
1595
2246
  if (!Array.isArray(each) || typeof props.children !== "function") {
2247
+ if (props.fallback) {
2248
+ await streamNode(props.fallback, controller, encoder);
2249
+ }
2250
+ return;
2251
+ }
2252
+ if (each.length === 0) {
2253
+ if (props.fallback) {
2254
+ await streamNode(props.fallback, controller, encoder);
2255
+ }
1596
2256
  return;
1597
2257
  }
1598
2258
  for (let index = 0;index < each.length; index++) {
1599
2259
  await streamNode(props.children(each[index], () => index), controller, encoder);
1600
2260
  }
1601
2261
  }
2262
+ async function streamIndexElement(element, controller, encoder) {
2263
+ const props = element.props;
2264
+ const each = readReactive4(props.each);
2265
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2266
+ if (props.fallback) {
2267
+ await streamNode(props.fallback, controller, encoder);
2268
+ }
2269
+ return;
2270
+ }
2271
+ if (each.length === 0) {
2272
+ if (props.fallback) {
2273
+ await streamNode(props.fallback, controller, encoder);
2274
+ }
2275
+ return;
2276
+ }
2277
+ for (let index = 0;index < each.length; index++) {
2278
+ await streamNode(props.children(() => each[index], index), controller, encoder);
2279
+ }
2280
+ }
1602
2281
  function resolveShowChildren3(element, value) {
1603
2282
  const children = element.props.children ?? element.children;
1604
2283
  if (typeof children === "function") {
@@ -1606,9 +2285,68 @@ function resolveShowChildren3(element, value) {
1606
2285
  }
1607
2286
  return children;
1608
2287
  }
1609
- function readReactive3(value) {
2288
+ function resolveSwitchContent3(element) {
2289
+ const props = element.props;
2290
+ const children = normalizeContent3(props.children ?? element.children);
2291
+ for (const child of children) {
2292
+ const match = getMatchElement3(child);
2293
+ if (!match) {
2294
+ continue;
2295
+ }
2296
+ const when = readReactive4(match.props.when);
2297
+ if (when) {
2298
+ return resolveMatchChildren3(match, when);
2299
+ }
2300
+ }
2301
+ return props.fallback;
2302
+ }
2303
+ function resolveMatchChildren3(element, value) {
2304
+ const children = element.props.children ?? element.children;
2305
+ if (typeof children === "function") {
2306
+ return children(value);
2307
+ }
2308
+ return children;
2309
+ }
2310
+ function resolveKeyChildren3(element, value) {
2311
+ const children = element.props.children ?? element.children;
2312
+ if (typeof children === "function") {
2313
+ return children(value);
2314
+ }
2315
+ return children;
2316
+ }
2317
+ function createDynamicElement3(element, tag) {
2318
+ if (typeof tag !== "string" && typeof tag !== "function") {
2319
+ return null;
2320
+ }
2321
+ const { component, ...props } = element.props;
2322
+ const children = normalizeContent3(props.children ?? element.children);
2323
+ return {
2324
+ tag,
2325
+ props,
2326
+ children
2327
+ };
2328
+ }
2329
+ function readReactive4(value) {
1610
2330
  return isSignal(value) || isComputed(value) ? value.value : value;
1611
2331
  }
2332
+ function normalizeContent3(content) {
2333
+ if (content == null || typeof content === "boolean") {
2334
+ return [];
2335
+ }
2336
+ return Array.isArray(content) ? content : [content];
2337
+ }
2338
+ function isElementLike3(value) {
2339
+ return value != null && typeof value === "object" && "tag" in value;
2340
+ }
2341
+ function getMatchElement3(value) {
2342
+ if (!isElementLike3(value)) {
2343
+ return null;
2344
+ }
2345
+ if (isMatchElement(value)) {
2346
+ return value;
2347
+ }
2348
+ return value.tag === Match ? Match(value.props) : null;
2349
+ }
1612
2350
  // src/server/hydration-markers.ts
1613
2351
  function createHydrationContext() {
1614
2352
  return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
@@ -1678,17 +2416,42 @@ function renderElementH(element, ctx, isComponentRoot) {
1678
2416
  if (tag === "") {
1679
2417
  return children.map((child) => renderNodeH(child, ctx)).join("");
1680
2418
  }
1681
- if (tag === Show || tag === For) {
2419
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2420
+ return renderElementH(tag(props), ctx, isComponentRoot);
2421
+ }
2422
+ if (tag === Visible) {
1682
2423
  return renderElementH(tag(props), ctx, isComponentRoot);
1683
2424
  }
1684
2425
  if (isShowElement(element)) {
1685
- const when = readReactive4(props.when);
2426
+ const when = readReactive5(props.when);
1686
2427
  const content = when ? resolveShowChildren4(element, when) : props.fallback;
1687
2428
  return renderNodeMaybeRoot(content, ctx, isComponentRoot);
1688
2429
  }
1689
2430
  if (isForElement(element)) {
1690
2431
  return renderForElementH(element, ctx);
1691
2432
  }
2433
+ if (isSwitchElement(element)) {
2434
+ return renderNodeMaybeRoot(resolveSwitchContent4(element), ctx, isComponentRoot);
2435
+ }
2436
+ if (isMatchElement(element)) {
2437
+ const when = readReactive5(props.when);
2438
+ return renderNodeMaybeRoot(when ? resolveMatchChildren4(element, when) : null, ctx, isComponentRoot);
2439
+ }
2440
+ if (isIndexElement(element)) {
2441
+ return renderIndexElementH(element, ctx);
2442
+ }
2443
+ if (isKeyElement(element)) {
2444
+ const key = readReactive5(props.when);
2445
+ return renderNodeMaybeRoot(resolveKeyChildren4(element, key), ctx, isComponentRoot);
2446
+ }
2447
+ if (isDynamicElement(element)) {
2448
+ const dynamicTag = readReactive5(props.component);
2449
+ const dynamic = createDynamicElement4(element, dynamicTag);
2450
+ return dynamic ? renderElementH(dynamic, ctx, isComponentRoot) : "";
2451
+ }
2452
+ if (isPortalElement(element)) {
2453
+ return "";
2454
+ }
1692
2455
  if (typeof tag === "function") {
1693
2456
  return renderComponentH(tag, props, ctx);
1694
2457
  }
@@ -1735,13 +2498,7 @@ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
1735
2498
  if (isSignal(value) || isComputed(value)) {
1736
2499
  resolvedValue = value.value;
1737
2500
  }
1738
- if (resolvedValue === true) {
1739
- const attrName2 = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1740
- attrs += ` ${attrName2}`;
1741
- continue;
1742
- }
1743
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1744
- attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
2501
+ attrs += renderServerAttribute(key, resolvedValue);
1745
2502
  }
1746
2503
  if (eventParts.length > 0) {
1747
2504
  attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
@@ -1764,12 +2521,26 @@ function renderNodeMaybeRoot(node, ctx, isComponentRoot) {
1764
2521
  }
1765
2522
  function renderForElementH(element, ctx) {
1766
2523
  const props = element.props;
1767
- const each = readReactive4(props.each);
2524
+ const each = readReactive5(props.each);
1768
2525
  if (!Array.isArray(each) || typeof props.children !== "function") {
1769
- return "";
2526
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2527
+ }
2528
+ if (each.length === 0) {
2529
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1770
2530
  }
1771
2531
  return each.map((item, index) => renderNodeH(props.children(item, () => index), ctx)).join("");
1772
2532
  }
2533
+ function renderIndexElementH(element, ctx) {
2534
+ const props = element.props;
2535
+ const each = readReactive5(props.each);
2536
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2537
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2538
+ }
2539
+ if (each.length === 0) {
2540
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2541
+ }
2542
+ return each.map((item, index) => renderNodeH(props.children(() => item, index), ctx)).join("");
2543
+ }
1773
2544
  function resolveShowChildren4(element, value) {
1774
2545
  const children = element.props.children ?? element.children;
1775
2546
  if (typeof children === "function") {
@@ -1777,21 +2548,67 @@ function resolveShowChildren4(element, value) {
1777
2548
  }
1778
2549
  return children;
1779
2550
  }
1780
- function readReactive4(value) {
2551
+ function resolveSwitchContent4(element) {
2552
+ const props = element.props;
2553
+ const children = normalizeContent4(props.children ?? element.children);
2554
+ for (const child of children) {
2555
+ const match = getMatchElement4(child);
2556
+ if (!match) {
2557
+ continue;
2558
+ }
2559
+ const when = readReactive5(match.props.when);
2560
+ if (when) {
2561
+ return resolveMatchChildren4(match, when);
2562
+ }
2563
+ }
2564
+ return props.fallback;
2565
+ }
2566
+ function resolveMatchChildren4(element, value) {
2567
+ const children = element.props.children ?? element.children;
2568
+ if (typeof children === "function") {
2569
+ return children(value);
2570
+ }
2571
+ return children;
2572
+ }
2573
+ function resolveKeyChildren4(element, value) {
2574
+ const children = element.props.children ?? element.children;
2575
+ if (typeof children === "function") {
2576
+ return children(value);
2577
+ }
2578
+ return children;
2579
+ }
2580
+ function createDynamicElement4(element, tag) {
2581
+ if (typeof tag !== "string" && typeof tag !== "function") {
2582
+ return null;
2583
+ }
2584
+ const { component, ...props } = element.props;
2585
+ const children = normalizeContent4(props.children ?? element.children);
2586
+ return {
2587
+ tag,
2588
+ props,
2589
+ children
2590
+ };
2591
+ }
2592
+ function readReactive5(value) {
1781
2593
  return isSignal(value) || isComputed(value) ? value.value : value;
1782
2594
  }
1783
- // src/reactivity/batch.ts
1784
- var batchDepth = 0;
1785
- function batch(fn) {
1786
- batchDepth++;
1787
- try {
1788
- fn();
1789
- } finally {
1790
- batchDepth--;
1791
- if (batchDepth === 0) {
1792
- flushSync();
1793
- }
2595
+ function normalizeContent4(content) {
2596
+ if (content == null || typeof content === "boolean") {
2597
+ return [];
1794
2598
  }
2599
+ return Array.isArray(content) ? content : [content];
2600
+ }
2601
+ function isElementLike4(value) {
2602
+ return value != null && typeof value === "object" && "tag" in value;
2603
+ }
2604
+ function getMatchElement4(value) {
2605
+ if (!isElementLike4(value)) {
2606
+ return null;
2607
+ }
2608
+ if (isMatchElement(value)) {
2609
+ return value;
2610
+ }
2611
+ return value.tag === Match ? Match(value.props) : null;
1795
2612
  }
1796
2613
  // src/component/lifecycle.ts
1797
2614
  function onMounted(fn) {
@@ -1945,10 +2762,16 @@ function hydrateElement(element, cursor) {
1945
2762
  if (tag === "") {
1946
2763
  return hydrateArray(children, cursor);
1947
2764
  }
1948
- if (tag === Show || tag === For) {
2765
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1949
2766
  return hydrateElement(tag(props), cursor);
1950
2767
  }
1951
- if (isShowElement(element) || isForElement(element)) {
2768
+ if (tag === Visible) {
2769
+ return hydrateElement(tag(props), cursor);
2770
+ }
2771
+ if (isPortalElement(element)) {
2772
+ return renderControlFlowToDOM(element, cursor.parent, cursor.current, null);
2773
+ }
2774
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element)) {
1952
2775
  return hydrateControlFlow(element, cursor);
1953
2776
  }
1954
2777
  if (typeof tag === "function") {
@@ -1991,20 +2814,13 @@ function hydrateAttributes(el, props) {
1991
2814
  const disposers = [];
1992
2815
  const owner = getCurrentInstance();
1993
2816
  for (const [key, value] of Object.entries(props)) {
1994
- if (key === "children" || key === "key" || key === "ref" || isEventProp(key))
2817
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key))
1995
2818
  continue;
1996
2819
  if (isSignal(value) || isComputed(value)) {
2820
+ const state = { previousStyleProps: new Set };
1997
2821
  let initialized = false;
1998
2822
  const dispose = effect(() => {
1999
- const v = value.value;
2000
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
2001
- if (v == null || v === false) {
2002
- el.removeAttribute(attrName);
2003
- } else if (v === true) {
2004
- el.setAttribute(attrName, "");
2005
- } else {
2006
- el.setAttribute(attrName, String(v));
2007
- }
2823
+ setSingleAttribute(el, key, value.value, state);
2008
2824
  if (initialized) {
2009
2825
  queueUpdatedHooks(owner);
2010
2826
  }
@@ -2017,16 +2833,34 @@ function hydrateAttributes(el, props) {
2017
2833
  }
2018
2834
  function hydrateControlFlow(element, cursor) {
2019
2835
  if (isShowElement(element)) {
2020
- const when = readReactive5(element.props.when);
2836
+ const when = readReactive6(element.props.when);
2021
2837
  const content = when ? resolveShowChildren5(element, when) : element.props.fallback;
2022
2838
  return hydrateContent(content, cursor);
2023
2839
  }
2024
2840
  if (isForElement(element)) {
2025
2841
  const props = element.props;
2026
- const items = readReactive5(props.each);
2027
- const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(item, () => index)) : [];
2842
+ const items = readReactive6(props.each);
2843
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(item, () => index)) : props.fallback ? [props.fallback] : [];
2028
2844
  return hydrateArray(children, cursor);
2029
2845
  }
2846
+ if (isSwitchElement(element)) {
2847
+ return hydrateContent(resolveSwitchContent5(element), cursor);
2848
+ }
2849
+ if (isIndexElement(element)) {
2850
+ const props = element.props;
2851
+ const items = readReactive6(props.each);
2852
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(() => item, index)) : props.fallback ? [props.fallback] : [];
2853
+ return hydrateArray(children, cursor);
2854
+ }
2855
+ if (isKeyElement(element)) {
2856
+ const key = readReactive6(element.props.when);
2857
+ return hydrateContent(resolveKeyChildren5(element, key), cursor);
2858
+ }
2859
+ if (isDynamicElement(element)) {
2860
+ const tag = readReactive6(element.props.component);
2861
+ const dynamic = createDynamicElement5(element, tag);
2862
+ return dynamic ? hydrateElement(dynamic, cursor) : hydrateArray([], cursor);
2863
+ }
2030
2864
  return hydrateArray(element.children, cursor);
2031
2865
  }
2032
2866
  function hydrateContent(content, cursor) {
@@ -2042,9 +2876,68 @@ function resolveShowChildren5(element, value) {
2042
2876
  }
2043
2877
  return children;
2044
2878
  }
2045
- function readReactive5(value) {
2879
+ function resolveSwitchContent5(element) {
2880
+ const props = element.props;
2881
+ const children = normalizeContent5(props.children ?? element.children);
2882
+ for (const child of children) {
2883
+ const match = getMatchElement5(child);
2884
+ if (!match) {
2885
+ continue;
2886
+ }
2887
+ const when = readReactive6(match.props.when);
2888
+ if (when) {
2889
+ return resolveMatchChildren5(match, when);
2890
+ }
2891
+ }
2892
+ return props.fallback;
2893
+ }
2894
+ function resolveMatchChildren5(element, value) {
2895
+ const children = element.props.children ?? element.children;
2896
+ if (typeof children === "function") {
2897
+ return children(value);
2898
+ }
2899
+ return children;
2900
+ }
2901
+ function resolveKeyChildren5(element, value) {
2902
+ const children = element.props.children ?? element.children;
2903
+ if (typeof children === "function") {
2904
+ return children(value);
2905
+ }
2906
+ return children;
2907
+ }
2908
+ function createDynamicElement5(element, tag) {
2909
+ if (typeof tag !== "string" && typeof tag !== "function") {
2910
+ return null;
2911
+ }
2912
+ const { component, ...props } = element.props;
2913
+ const children = normalizeContent5(props.children ?? element.children);
2914
+ return {
2915
+ tag,
2916
+ props,
2917
+ children
2918
+ };
2919
+ }
2920
+ function readReactive6(value) {
2046
2921
  return isSignal(value) || isComputed(value) ? value.value : value;
2047
2922
  }
2923
+ function normalizeContent5(content) {
2924
+ if (content == null || typeof content === "boolean") {
2925
+ return [];
2926
+ }
2927
+ return Array.isArray(content) ? content : [content];
2928
+ }
2929
+ function isElementLike5(value) {
2930
+ return value != null && typeof value === "object" && "tag" in value;
2931
+ }
2932
+ function getMatchElement5(value) {
2933
+ if (!isElementLike5(value)) {
2934
+ return null;
2935
+ }
2936
+ if (isMatchElement(value)) {
2937
+ return value;
2938
+ }
2939
+ return value.tag === Match ? Match(value.props) : null;
2940
+ }
2048
2941
  function applyRef2(el, ref) {
2049
2942
  const value = ref;
2050
2943
  if (!value) {
@@ -2191,11 +3084,18 @@ export {
2191
3084
  createComponent,
2192
3085
  computed,
2193
3086
  batch,
3087
+ Visible,
3088
+ Switch,
2194
3089
  Show,
3090
+ Portal,
3091
+ Match,
3092
+ Key,
3093
+ Index,
2195
3094
  HtmlEscapedString,
2196
3095
  Fragment,
2197
- For
3096
+ For,
3097
+ Dynamic
2198
3098
  };
2199
3099
 
2200
- //# debugId=14DE79AF90B411D764756E2164756E21
3100
+ //# debugId=D6124451AF9E145564756E2164756E21
2201
3101
  //# sourceMappingURL=index.development.js.map