sinwan 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/cjs/index.development.js +962 -94
  2. package/dist/cjs/index.development.js.map +14 -13
  3. package/dist/cjs/index.production.min.js +2 -2
  4. package/dist/cjs/index.production.min.js.map +14 -13
  5. package/dist/cjs/renderer/index.development.js +419 -13
  6. package/dist/cjs/renderer/index.development.js.map +9 -8
  7. package/dist/cjs/renderer/index.production.min.js +2 -2
  8. package/dist/cjs/renderer/index.production.min.js.map +9 -8
  9. package/dist/cjs/server/index.development.js +560 -48
  10. package/dist/cjs/server/index.development.js.map +9 -7
  11. package/dist/cjs/server/index.production.min.js +2 -2
  12. package/dist/cjs/server/index.production.min.js.map +9 -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 +962 -94
  18. package/dist/esm/index.development.js.map +14 -13
  19. package/dist/esm/index.production.min.js +2 -2
  20. package/dist/esm/index.production.min.js.map +14 -13
  21. package/dist/esm/renderer/index.development.js +419 -13
  22. package/dist/esm/renderer/index.development.js.map +9 -8
  23. package/dist/esm/renderer/index.production.min.js +2 -2
  24. package/dist/esm/renderer/index.production.min.js.map +9 -8
  25. package/dist/esm/server/index.development.js +560 -48
  26. package/dist/esm/server/index.development.js.map +9 -7
  27. package/dist/esm/server/index.production.min.js +2 -2
  28. package/dist/esm/server/index.production.min.js.map +9 -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/renderer/attributes.d.ts +11 -0
  33. package/dist/renderer/attributes.d.ts.map +1 -1
  34. package/dist/renderer/index.d.ts +1 -1
  35. package/dist/renderer/index.d.ts.map +1 -1
  36. package/dist/renderer/render-control-flow.d.ts +3 -3
  37. package/dist/renderer/render-control-flow.d.ts.map +1 -1
  38. package/dist/renderer/render-element.d.ts.map +1 -1
  39. package/dist/renderer/types.d.ts +8 -1
  40. package/dist/renderer/types.d.ts.map +1 -1
  41. package/dist/renderer/unmount.d.ts.map +1 -1
  42. package/dist/server/attribute-utils.d.ts +2 -0
  43. package/dist/server/attribute-utils.d.ts.map +1 -0
  44. package/dist/server/hydration-markers.d.ts.map +1 -1
  45. package/dist/server/renderer.d.ts.map +1 -1
  46. package/dist/server/stream.d.ts.map +1 -1
  47. package/package.json +5 -5
@@ -511,9 +511,10 @@ function applyAttributes(el, props) {
511
511
  if (SKIP_PROPS.has(key) || isEventProp(key))
512
512
  continue;
513
513
  if (isSignal(value) || isComputed(value)) {
514
+ const state = { previousStyleProps: new Set };
514
515
  let initialized = false;
515
516
  const dispose = effect(() => {
516
- setSingleAttribute(el, key, value.value);
517
+ setSingleAttribute(el, key, value.value, state);
517
518
  if (initialized) {
518
519
  queueUpdatedHooks(owner);
519
520
  }
@@ -526,10 +527,10 @@ function applyAttributes(el, props) {
526
527
  }
527
528
  return disposers;
528
529
  }
529
- function setSingleAttribute(el, key, value) {
530
- const attrName = PROP_ALIASES[key] ?? key;
530
+ function setSingleAttribute(el, key, value, state) {
531
+ const attrName = resolveAttributeName(key);
531
532
  if (attrName === "style" && typeof value === "object" && value !== null) {
532
- applyStyle(el, value);
533
+ applyStyle(el, value, state);
533
534
  return;
534
535
  }
535
536
  if (attrName === "class" && typeof value === "object" && value !== null) {
@@ -538,6 +539,9 @@ function setSingleAttribute(el, key, value) {
538
539
  }
539
540
  if (value == null || value === false) {
540
541
  domOps.removeAttribute(el, attrName);
542
+ if (attrName === "style" && state) {
543
+ state.previousStyleProps.clear();
544
+ }
541
545
  if (DOM_PROPERTIES.has(attrName)) {
542
546
  domOps.setProperty(el, attrName, attrName === "value" ? "" : false);
543
547
  }
@@ -545,25 +549,59 @@ function setSingleAttribute(el, key, value) {
545
549
  }
546
550
  if (value === true) {
547
551
  domOps.setAttribute(el, attrName, "");
552
+ if (attrName === "style" && state) {
553
+ state.previousStyleProps.clear();
554
+ }
548
555
  if (DOM_PROPERTIES.has(attrName)) {
549
556
  domOps.setProperty(el, attrName, true);
550
557
  }
551
558
  return;
552
559
  }
553
560
  if (DOM_PROPERTIES.has(attrName)) {
561
+ if (attrName === "style" && state) {
562
+ state.previousStyleProps.clear();
563
+ }
554
564
  domOps.setProperty(el, attrName, value);
555
565
  return;
556
566
  }
567
+ if (attrName === "style" && state) {
568
+ state.previousStyleProps.clear();
569
+ }
557
570
  domOps.setAttribute(el, attrName, String(value));
558
571
  }
559
- function applyStyle(el, styles) {
572
+ function resolveAttributeName(key) {
573
+ return PROP_ALIASES[key] ?? key;
574
+ }
575
+ function applyStyle(el, styles, state) {
576
+ const nextProps = new Set;
560
577
  for (const [prop, val] of Object.entries(styles)) {
578
+ nextProps.add(prop);
579
+ if (val == null) {
580
+ removeStyleProperty(el, prop);
581
+ continue;
582
+ }
561
583
  if (prop.includes("-")) {
562
- el.style.setProperty(prop, val);
584
+ el.style.setProperty(prop, String(val));
563
585
  } else {
564
586
  el.style[prop] = val;
565
587
  }
566
588
  }
589
+ if (!state) {
590
+ return;
591
+ }
592
+ for (const previousProp of state.previousStyleProps) {
593
+ if (!nextProps.has(previousProp)) {
594
+ removeStyleProperty(el, previousProp);
595
+ }
596
+ }
597
+ state.previousStyleProps = nextProps;
598
+ }
599
+ function removeStyleProperty(el, prop) {
600
+ if (prop.includes("-")) {
601
+ el.style.removeProperty(prop);
602
+ } else {
603
+ el.style[prop] = "";
604
+ }
567
605
  }
568
606
  function applyClass(el, value) {
569
607
  let classStr;
@@ -576,10 +614,28 @@ function applyClass(el, value) {
576
614
  }
577
615
  domOps.setAttribute(el, "class", classStr);
578
616
  }
579
-
617
+ // src/reactivity/batch.ts
618
+ var batchDepth = 0;
619
+ function batch(fn) {
620
+ batchDepth++;
621
+ try {
622
+ fn();
623
+ } finally {
624
+ batchDepth--;
625
+ if (batchDepth === 0) {
626
+ flushSync();
627
+ }
628
+ }
629
+ }
580
630
  // src/component/control-flow.ts
581
631
  var SHOW_TYPE = Symbol.for("Sinwan.Show");
582
632
  var FOR_TYPE = Symbol.for("Sinwan.For");
633
+ var SWITCH_TYPE = Symbol.for("Sinwan.Switch");
634
+ var MATCH_TYPE = Symbol.for("Sinwan.Match");
635
+ var INDEX_TYPE = Symbol.for("Sinwan.Index");
636
+ var KEY_TYPE = Symbol.for("Sinwan.Key");
637
+ var DYNAMIC_TYPE = Symbol.for("Sinwan.Dynamic");
638
+ var PORTAL_TYPE = Symbol.for("Sinwan.Portal");
583
639
  function Show(props) {
584
640
  return {
585
641
  tag: SHOW_TYPE,
@@ -594,12 +650,114 @@ function For(props) {
594
650
  children: []
595
651
  };
596
652
  }
653
+ function Switch(props) {
654
+ return {
655
+ tag: SWITCH_TYPE,
656
+ props,
657
+ children: []
658
+ };
659
+ }
660
+ function Match(props) {
661
+ return {
662
+ tag: MATCH_TYPE,
663
+ props,
664
+ children: []
665
+ };
666
+ }
667
+ function Index(props) {
668
+ return {
669
+ tag: INDEX_TYPE,
670
+ props,
671
+ children: []
672
+ };
673
+ }
674
+ function Key(props) {
675
+ return {
676
+ tag: KEY_TYPE,
677
+ props,
678
+ children: []
679
+ };
680
+ }
681
+ function Dynamic(props) {
682
+ return {
683
+ tag: DYNAMIC_TYPE,
684
+ props,
685
+ children: []
686
+ };
687
+ }
688
+ function Visible(props) {
689
+ const {
690
+ when,
691
+ as = "span",
692
+ style,
693
+ children,
694
+ ...rest
695
+ } = props;
696
+ const visibleStyle = computed(() => {
697
+ const base = readReactive(style);
698
+ const visible = Boolean(readReactive(when));
699
+ if (typeof base === "string") {
700
+ return visible ? base : appendHiddenDisplay(base);
701
+ }
702
+ const styleObject = base && typeof base === "object" ? { ...base } : {};
703
+ styleObject.display = visible ? styleObject.display : "none";
704
+ return styleObject;
705
+ });
706
+ return {
707
+ tag: as,
708
+ props: {
709
+ ...rest,
710
+ style: visibleStyle,
711
+ children
712
+ },
713
+ children: normalizeChildren2(children)
714
+ };
715
+ }
716
+ function Portal(props) {
717
+ return {
718
+ tag: PORTAL_TYPE,
719
+ props,
720
+ children: []
721
+ };
722
+ }
597
723
  function isShowElement(element) {
598
724
  return element.tag === SHOW_TYPE;
599
725
  }
600
726
  function isForElement(element) {
601
727
  return element.tag === FOR_TYPE;
602
728
  }
729
+ function isSwitchElement(element) {
730
+ return element.tag === SWITCH_TYPE;
731
+ }
732
+ function isMatchElement(element) {
733
+ return element.tag === MATCH_TYPE;
734
+ }
735
+ function isIndexElement(element) {
736
+ return element.tag === INDEX_TYPE;
737
+ }
738
+ function isKeyElement(element) {
739
+ return element.tag === KEY_TYPE;
740
+ }
741
+ function isDynamicElement(element) {
742
+ return element.tag === DYNAMIC_TYPE;
743
+ }
744
+ function isPortalElement(element) {
745
+ return element.tag === PORTAL_TYPE;
746
+ }
747
+ function normalizeChildren2(children) {
748
+ if (children == null || typeof children === "boolean") {
749
+ return [];
750
+ }
751
+ return Array.isArray(children) ? children : [children];
752
+ }
753
+ function readReactive(value) {
754
+ return isSignal(value) || isComputed(value) ? value.value : value;
755
+ }
756
+ function appendHiddenDisplay(style) {
757
+ const trimmed = style.trim();
758
+ const separator = trimmed.length > 0 && !trimmed.endsWith(";") ? ";" : "";
759
+ return `${trimmed}${separator}display:none`;
760
+ }
603
761
 
604
762
  // src/renderer/unmount.ts
605
763
  function getMountedDomNodes(node) {
@@ -622,6 +780,8 @@ function getMountedDomNodes(node) {
622
780
  ];
623
781
  case "component":
624
782
  return node.children.flatMap((child) => getMountedDomNodes(child));
783
+ case "portal":
784
+ return [node.anchor];
625
785
  }
626
786
  }
627
787
  function unmountNode(node) {
@@ -666,6 +826,13 @@ function unmountNode(node) {
666
826
  unmountNode(child);
667
827
  }
668
828
  break;
829
+ case "portal":
830
+ node.dispose();
831
+ for (const child of node.children) {
832
+ removeMountedNode(child);
833
+ }
834
+ node.children = [];
835
+ break;
669
836
  }
670
837
  }
671
838
  function removeMountedNode(node) {
@@ -680,6 +847,9 @@ function removeMountedNode(node) {
680
847
 
681
848
  // src/renderer/render-control-flow.ts
682
849
  function renderControlFlowToDOM(element, parent, anchor, namespace) {
850
+ if (isPortalElement(element)) {
851
+ return renderPortal(element, parent, anchor, namespace);
852
+ }
683
853
  const startAnchor = domOps.createComment("Sinwan-b");
684
854
  const endAnchor = domOps.createComment("/Sinwan-b");
685
855
  insertNode(parent, startAnchor, anchor);
@@ -697,6 +867,14 @@ function renderControlFlowToDOM(element, parent, anchor, namespace) {
697
867
  disposeEffect = renderShowBlock(element, block, parent, namespace, owner);
698
868
  } else if (isForElement(element)) {
699
869
  disposeEffect = renderForBlock(element, block, parent, namespace, owner);
870
+ } else if (isSwitchElement(element)) {
871
+ disposeEffect = renderSwitchBlock(element, block, parent, namespace, owner);
872
+ } else if (isIndexElement(element)) {
873
+ disposeEffect = renderIndexBlock(element, block, parent, namespace, owner);
874
+ } else if (isKeyElement(element)) {
875
+ disposeEffect = renderKeyBlock(element, block, parent, namespace, owner);
876
+ } else if (isDynamicElement(element)) {
877
+ disposeEffect = renderDynamicBlock(element, block, parent, namespace, owner);
700
878
  }
701
879
  return block;
702
880
  }
@@ -704,7 +882,7 @@ function renderShowBlock(element, block, parent, namespace, owner) {
704
882
  let initialized = false;
705
883
  return effect(() => {
706
884
  clearChildren(block);
707
- const when = readReactive(element.props.when);
885
+ const when = readReactive2(element.props.when);
708
886
  const content = withOptionalInstance(owner, () => when ? resolveShowChildren(element, when) : element.props.fallback);
709
887
  block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
710
888
  if (initialized) {
@@ -718,7 +896,7 @@ function renderForBlock(element, block, parent, namespace, owner) {
718
896
  let records = [];
719
897
  return effect(() => {
720
898
  const props = element.props;
721
- const items = readReactive(props.each);
899
+ const items = readReactive2(props.each);
722
900
  const list = Array.isArray(items) ? items : [];
723
901
  const renderChild = props.children;
724
902
  if (typeof renderChild !== "function") {
@@ -730,6 +908,19 @@ function renderForBlock(element, block, parent, namespace, owner) {
730
908
  initialized = true;
731
909
  return;
732
910
  }
911
+ if (list.length === 0) {
912
+ clearChildren(block);
913
+ records = [];
914
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
915
+ if (initialized) {
916
+ fireMountedAndQueueUpdated(owner);
917
+ }
918
+ initialized = true;
919
+ return;
920
+ }
921
+ if (records.length === 0 && block.children.length > 0) {
922
+ clearChildren(block);
923
+ }
733
924
  const oldByKey = new Map;
734
925
  for (const record of records) {
735
926
  oldByKey.set(record.key, record);
@@ -769,6 +960,137 @@ function renderForBlock(element, block, parent, namespace, owner) {
769
960
  initialized = true;
770
961
  });
771
962
  }
963
+ function renderSwitchBlock(element, block, parent, namespace, owner) {
964
+ let initialized = false;
965
+ return effect(() => {
966
+ clearChildren(block);
967
+ const content = withOptionalInstance(owner, () => resolveSwitchContent(element));
968
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
969
+ if (initialized) {
970
+ fireMountedAndQueueUpdated(owner);
971
+ }
972
+ initialized = true;
973
+ });
974
+ }
975
+ function renderIndexBlock(element, block, parent, namespace, owner) {
976
+ let initialized = false;
977
+ let records = [];
978
+ return effect(() => {
979
+ const props = element.props;
980
+ const items = readReactive2(props.each);
981
+ const list = Array.isArray(items) ? items : [];
982
+ const renderChild = props.children;
983
+ if (typeof renderChild !== "function") {
984
+ clearChildren(block);
985
+ records = [];
986
+ if (initialized) {
987
+ queueUpdatedHooks(owner);
988
+ }
989
+ initialized = true;
990
+ return;
991
+ }
992
+ if (list.length === 0) {
993
+ clearChildren(block);
994
+ records = [];
995
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
996
+ if (initialized) {
997
+ fireMountedAndQueueUpdated(owner);
998
+ }
999
+ initialized = true;
1000
+ return;
1001
+ }
1002
+ if (records.length === 0 && block.children.length > 0) {
1003
+ clearChildren(block);
1004
+ }
1005
+ for (let index = 0;index < list.length; index++) {
1006
+ const existing = records[index];
1007
+ if (existing) {
1008
+ existing.item.value = list[index];
1009
+ continue;
1010
+ }
1011
+ const itemSignal = signal(list[index]);
1012
+ const record = {
1013
+ item: itemSignal,
1014
+ mounted: withOptionalInstance(owner, () => renderNodeToDOM(renderChild(() => itemSignal.value, index), parent, block.endAnchor, namespace))
1015
+ };
1016
+ records.push(record);
1017
+ }
1018
+ while (records.length > list.length) {
1019
+ const removed = records.pop();
1020
+ removeMountedNode(removed.mounted);
1021
+ }
1022
+ block.children = records.map((record) => record.mounted);
1023
+ if (initialized) {
1024
+ fireMountedAndQueueUpdated(owner);
1025
+ }
1026
+ initialized = true;
1027
+ });
1028
+ }
1029
+ function renderKeyBlock(element, block, parent, namespace, owner) {
1030
+ let initialized = false;
1031
+ let hasKey = false;
1032
+ let currentKey;
1033
+ return effect(() => {
1034
+ const key = readReactive2(element.props.when);
1035
+ if (hasKey && Object.is(currentKey, key)) {
1036
+ return;
1037
+ }
1038
+ currentKey = key;
1039
+ hasKey = true;
1040
+ clearChildren(block);
1041
+ const content = withOptionalInstance(owner, () => resolveKeyChildren(element, key));
1042
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1043
+ if (initialized) {
1044
+ fireMountedAndQueueUpdated(owner);
1045
+ }
1046
+ initialized = true;
1047
+ });
1048
+ }
1049
+ function renderDynamicBlock(element, block, parent, namespace, owner) {
1050
+ let initialized = false;
1051
+ let hasTag = false;
1052
+ let currentTag;
1053
+ return effect(() => {
1054
+ const tag = readReactive2(element.props.component);
1055
+ if (hasTag && Object.is(currentTag, tag)) {
1056
+ return;
1057
+ }
1058
+ currentTag = tag;
1059
+ hasTag = true;
1060
+ clearChildren(block);
1061
+ const content = tag ? createDynamicElement(element, tag) : null;
1062
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1063
+ if (initialized) {
1064
+ fireMountedAndQueueUpdated(owner);
1065
+ }
1066
+ initialized = true;
1067
+ });
1068
+ }
1069
+ function renderPortal(element, parent, anchor, namespace) {
1070
+ const placeholder = domOps.createComment("Sinwan-p");
1071
+ insertNode(parent, placeholder, anchor);
1072
+ const owner = getCurrentInstance();
1073
+ let disposeEffect = () => {};
1074
+ const portal = {
1075
+ type: "portal",
1076
+ anchor: placeholder,
1077
+ children: [],
1078
+ dispose: () => disposeEffect()
1079
+ };
1080
+ let initialized = false;
1081
+ disposeEffect = effect(() => {
1082
+ clearPortalChildren(portal);
1083
+ const target = resolvePortalTarget(element.props.mount);
1084
+ if (target) {
1085
+ portal.children = renderBlockContent(element.props.children ?? element.children, target, null, namespace, owner);
1086
+ }
1087
+ if (initialized) {
1088
+ fireMountedAndQueueUpdated(owner);
1089
+ }
1090
+ initialized = true;
1091
+ });
1092
+ return portal;
1093
+ }
772
1094
  function resolveShowChildren(element, value) {
773
1095
  const children = element.props.children ?? element.children;
774
1096
  if (typeof children === "function") {
@@ -776,6 +1098,47 @@ function resolveShowChildren(element, value) {
776
1098
  }
777
1099
  return children;
778
1100
  }
1101
+ function resolveSwitchContent(element) {
1102
+ const props = element.props;
1103
+ const children = normalizeContent(props.children ?? element.children);
1104
+ for (const child of children) {
1105
+ const match = getMatchElement(child);
1106
+ if (!match) {
1107
+ continue;
1108
+ }
1109
+ const when = readReactive2(match.props.when);
1110
+ if (when) {
1111
+ return resolveMatchChildren(match, when);
1112
+ }
1113
+ }
1114
+ return props.fallback;
1115
+ }
1116
+ function resolveMatchChildren(element, value) {
1117
+ const children = element.props.children ?? element.children;
1118
+ if (typeof children === "function") {
1119
+ return children(value);
1120
+ }
1121
+ return children;
1122
+ }
1123
+ function resolveKeyChildren(element, value) {
1124
+ const children = element.props.children ?? element.children;
1125
+ if (typeof children === "function") {
1126
+ return children(value);
1127
+ }
1128
+ return children;
1129
+ }
1130
+ function createDynamicElement(element, tag) {
1131
+ if (typeof tag !== "string" && typeof tag !== "function") {
1132
+ return null;
1133
+ }
1134
+ const { component, ...props } = element.props;
1135
+ const children = normalizeContent(props.children ?? element.children);
1136
+ return {
1137
+ tag,
1138
+ props,
1139
+ children
1140
+ };
1141
+ }
779
1142
  function renderBlockContent(content, parent, anchor, namespace, owner) {
780
1143
  if (content == null || typeof content === "boolean") {
781
1144
  return [];
@@ -789,6 +1152,12 @@ function clearChildren(block) {
789
1152
  }
790
1153
  block.children = [];
791
1154
  }
1155
+ function clearPortalChildren(portal) {
1156
+ for (const child of portal.children) {
1157
+ removeMountedNode(child);
1158
+ }
1159
+ portal.children = [];
1160
+ }
792
1161
  function moveBeforeEnd(parent, mounted, endAnchor) {
793
1162
  for (const node of getMountedDomNodes(mounted)) {
794
1163
  domOps.insertBefore(parent, node, endAnchor);
@@ -803,9 +1172,43 @@ function fireMountedAndQueueUpdated(owner) {
803
1172
  function withOptionalInstance(owner, fn) {
804
1173
  return owner ? withInstance(owner, fn) : fn();
805
1174
  }
806
- function readReactive(value) {
1175
+ function readReactive2(value) {
807
1176
  return isSignal(value) || isComputed(value) ? value.value : value;
808
1177
  }
1178
+ function normalizeContent(content) {
1179
+ if (content == null || typeof content === "boolean") {
1180
+ return [];
1181
+ }
1182
+ return Array.isArray(content) ? content : [content];
1183
+ }
1184
+ function isElementLike(value) {
1185
+ return value != null && typeof value === "object" && "tag" in value;
1186
+ }
1187
+ function getMatchElement(value) {
1188
+ if (!isElementLike(value)) {
1189
+ return null;
1190
+ }
1191
+ if (isMatchElement(value)) {
1192
+ return value;
1193
+ }
1194
+ return value.tag === Match ? Match(value.props) : null;
1195
+ }
1196
+ function resolvePortalTarget(value) {
1197
+ const target = readReactive2(value);
1198
+ if (target == null) {
1199
+ return typeof document === "undefined" ? null : document.body;
1200
+ }
1201
+ if (typeof target === "string") {
1202
+ return document.querySelector(target);
1203
+ }
1204
+ if (typeof target === "function") {
1205
+ return target();
1206
+ }
1207
+ if (typeof target === "object" && "nodeType" in target) {
1208
+ return target;
1209
+ }
1210
+ return null;
1211
+ }
809
1212
  function insertNode(parent, child, anchor) {
810
1213
  if (anchor) {
811
1214
  domOps.insertBefore(parent, child, anchor);
@@ -838,10 +1241,13 @@ function renderElementToDOM(element, parent, anchor = null, namespace = null) {
838
1241
  if (tag === "" || tag === Fragment) {
839
1242
  return renderFragmentToDOM(children, parent, anchor, namespace);
840
1243
  }
841
- if (tag === Show || tag === For) {
1244
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1245
+ return renderElementToDOM(tag(props), parent, anchor, namespace);
1246
+ }
1247
+ if (tag === Visible) {
842
1248
  return renderElementToDOM(tag(props), parent, anchor, namespace);
843
1249
  }
844
- if (isShowElement(element) || isForElement(element)) {
1250
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element) || isPortalElement(element)) {
845
1251
  return renderControlFlowToDOM(element, parent, anchor, namespace);
846
1252
  }
847
1253
  if (typeof tag === "function") {
@@ -1137,6 +1543,37 @@ function isSafeHtml(value) {
1137
1543
  return value instanceof HtmlEscapedString;
1138
1544
  }
1139
1545
 
1546
+ // src/server/attribute-utils.ts
1547
+ var PROP_ALIASES2 = {
1548
+ className: "class",
1549
+ htmlFor: "for",
1550
+ tabIndex: "tabindex",
1551
+ crossOrigin: "crossorigin"
1552
+ };
1553
+ function renderServerAttribute(key, value) {
1554
+ const attrName = PROP_ALIASES2[key] ?? key;
1555
+ if (value == null || value === false) {
1556
+ return "";
1557
+ }
1558
+ if (value === true) {
1559
+ return ` ${attrName}`;
1560
+ }
1561
+ const attrValue = attrName === "class" && typeof value === "object" ? stringifyClass(value) : attrName === "style" && typeof value === "object" ? stringifyStyle(value) : String(value);
1562
+ return ` ${attrName}="${escapeHtml(attrValue)}"`;
1563
+ }
1564
+ function stringifyClass(value) {
1565
+ if (Array.isArray(value)) {
1566
+ return value.filter(Boolean).join(" ");
1567
+ }
1568
+ return Object.entries(value).filter(([, enabled]) => Boolean(enabled)).map(([name]) => name).join(" ");
1569
+ }
1570
+ function stringifyStyle(value) {
1571
+ return Object.entries(value).filter(([, val]) => val != null && val !== false).map(([prop, val]) => `${toKebabCase(prop)}:${String(val)}`).join(";");
1572
+ }
1573
+ function toKebabCase(value) {
1574
+ return value.includes("-") ? value : value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
1575
+ }
1576
+
1140
1577
  // src/server/renderer.ts
1141
1578
  var componentCache = new WeakMap;
1142
1579
  var pageRegistry = new Map;
@@ -1184,13 +1621,41 @@ async function renderToString(node) {
1184
1621
  }
1185
1622
  async function renderElement(element) {
1186
1623
  const { tag, props, children } = element;
1624
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1625
+ return renderElement(tag(props));
1626
+ }
1627
+ if (tag === Visible) {
1628
+ return renderElement(tag(props));
1629
+ }
1187
1630
  if (isShowElement(element)) {
1188
- const when = readReactive2(props.when);
1631
+ const when = readReactive3(props.when);
1189
1632
  return renderToString(when ? resolveShowChildren2(element, when) : props.fallback);
1190
1633
  }
1191
1634
  if (isForElement(element)) {
1192
1635
  return renderForElement(element);
1193
1636
  }
1637
+ if (isSwitchElement(element)) {
1638
+ return renderToString(resolveSwitchContent2(element));
1639
+ }
1640
+ if (isMatchElement(element)) {
1641
+ const when = readReactive3(props.when);
1642
+ return renderToString(when ? resolveMatchChildren2(element, when) : null);
1643
+ }
1644
+ if (isIndexElement(element)) {
1645
+ return renderIndexElement(element);
1646
+ }
1647
+ if (isKeyElement(element)) {
1648
+ const key = readReactive3(props.when);
1649
+ return renderToString(resolveKeyChildren2(element, key));
1650
+ }
1651
+ if (isDynamicElement(element)) {
1652
+ const tag2 = readReactive3(props.component);
1653
+ const dynamic = createDynamicElement2(element, tag2);
1654
+ return dynamic ? renderElement(dynamic) : "";
1655
+ }
1656
+ if (isPortalElement(element)) {
1657
+ return "";
1658
+ }
1194
1659
  if (typeof tag === "function") {
1195
1660
  const result = await tag(props);
1196
1661
  return renderToString(result);
@@ -1230,17 +1695,10 @@ function renderAttributes(props) {
1230
1695
  if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
1231
1696
  continue;
1232
1697
  }
1233
- const resolvedValue = readReactive2(value);
1698
+ const resolvedValue = readReactive3(value);
1234
1699
  if (resolvedValue == null || resolvedValue === false)
1235
1700
  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}"`;
1701
+ attrs += renderServerAttribute(key, resolvedValue);
1244
1702
  }
1245
1703
  return attrs;
1246
1704
  }
@@ -1251,17 +1709,73 @@ async function renderChildren(children, props) {
1251
1709
  }
1252
1710
  return renderToString(children);
1253
1711
  }
1254
- function isSlots(children) {
1255
- return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
1712
+ function isSlots(children) {
1713
+ return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
1714
+ }
1715
+ async function renderForElement(element) {
1716
+ const props = element.props;
1717
+ const each = readReactive3(props.each);
1718
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1719
+ return props.fallback ? renderToString(props.fallback) : "";
1720
+ }
1721
+ if (each.length === 0) {
1722
+ return props.fallback ? renderToString(props.fallback) : "";
1723
+ }
1724
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
1725
+ return rendered.join("");
1726
+ }
1727
+ async function renderIndexElement(element) {
1728
+ const props = element.props;
1729
+ const each = readReactive3(props.each);
1730
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1731
+ return props.fallback ? renderToString(props.fallback) : "";
1732
+ }
1733
+ if (each.length === 0) {
1734
+ return props.fallback ? renderToString(props.fallback) : "";
1735
+ }
1736
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(() => item, index))));
1737
+ return rendered.join("");
1738
+ }
1739
+ function resolveSwitchContent2(element) {
1740
+ const props = element.props;
1741
+ const children = normalizeContent2(props.children ?? element.children);
1742
+ for (const child of children) {
1743
+ const match = getMatchElement2(child);
1744
+ if (!match) {
1745
+ continue;
1746
+ }
1747
+ const when = readReactive3(match.props.when);
1748
+ if (when) {
1749
+ return resolveMatchChildren2(match, when);
1750
+ }
1751
+ }
1752
+ return props.fallback;
1753
+ }
1754
+ function resolveMatchChildren2(element, value) {
1755
+ const children = element.props.children ?? element.children;
1756
+ if (typeof children === "function") {
1757
+ return children(value);
1758
+ }
1759
+ return children;
1760
+ }
1761
+ function resolveKeyChildren2(element, value) {
1762
+ const children = element.props.children ?? element.children;
1763
+ if (typeof children === "function") {
1764
+ return children(value);
1765
+ }
1766
+ return children;
1256
1767
  }
1257
- async function renderForElement(element) {
1258
- const props = element.props;
1259
- const each = readReactive2(props.each);
1260
- if (!Array.isArray(each) || typeof props.children !== "function") {
1261
- return "";
1768
+ function createDynamicElement2(element, tag) {
1769
+ if (typeof tag !== "string" && typeof tag !== "function") {
1770
+ return null;
1262
1771
  }
1263
- const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
1264
- return rendered.join("");
1772
+ const { component, ...props } = element.props;
1773
+ const children = normalizeContent2(props.children ?? element.children);
1774
+ return {
1775
+ tag,
1776
+ props,
1777
+ children
1778
+ };
1265
1779
  }
1266
1780
  function resolveShowChildren2(element, value) {
1267
1781
  const children = element.props.children ?? element.children;
@@ -1270,9 +1784,27 @@ function resolveShowChildren2(element, value) {
1270
1784
  }
1271
1785
  return children;
1272
1786
  }
1273
- function readReactive2(value) {
1787
+ function readReactive3(value) {
1274
1788
  return isSignal(value) || isComputed(value) ? value.value : value;
1275
1789
  }
1790
+ function normalizeContent2(content) {
1791
+ if (content == null || typeof content === "boolean") {
1792
+ return [];
1793
+ }
1794
+ return Array.isArray(content) ? content : [content];
1795
+ }
1796
+ function isElementLike2(value) {
1797
+ return value != null && typeof value === "object" && "tag" in value;
1798
+ }
1799
+ function getMatchElement2(value) {
1800
+ if (!isElementLike2(value)) {
1801
+ return null;
1802
+ }
1803
+ if (isMatchElement(value)) {
1804
+ return value;
1805
+ }
1806
+ return value.tag === Match ? Match(value.props) : null;
1807
+ }
1276
1808
  // src/hydration/markers.ts
1277
1809
  var COMP_ID_ATTR = "data-sinwan-id";
1278
1810
  var COMP_ID_PREFIX = "c";
@@ -1397,8 +1929,16 @@ async function streamNode(node, controller, encoder) {
1397
1929
  }
1398
1930
  async function streamElement(element, controller, encoder) {
1399
1931
  const { tag, props, children } = element;
1932
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1933
+ await streamElement(tag(props), controller, encoder);
1934
+ return;
1935
+ }
1936
+ if (tag === Visible) {
1937
+ await streamElement(tag(props), controller, encoder);
1938
+ return;
1939
+ }
1400
1940
  if (isShowElement(element)) {
1401
- const when = readReactive3(props.when);
1941
+ const when = readReactive4(props.when);
1402
1942
  await streamNode(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder);
1403
1943
  return;
1404
1944
  }
@@ -1406,6 +1946,35 @@ async function streamElement(element, controller, encoder) {
1406
1946
  await streamForElement(element, controller, encoder);
1407
1947
  return;
1408
1948
  }
1949
+ if (isSwitchElement(element)) {
1950
+ await streamNode(resolveSwitchContent3(element), controller, encoder);
1951
+ return;
1952
+ }
1953
+ if (isMatchElement(element)) {
1954
+ const when = readReactive4(props.when);
1955
+ await streamNode(when ? resolveMatchChildren3(element, when) : null, controller, encoder);
1956
+ return;
1957
+ }
1958
+ if (isIndexElement(element)) {
1959
+ await streamIndexElement(element, controller, encoder);
1960
+ return;
1961
+ }
1962
+ if (isKeyElement(element)) {
1963
+ const key = readReactive4(props.when);
1964
+ await streamNode(resolveKeyChildren3(element, key), controller, encoder);
1965
+ return;
1966
+ }
1967
+ if (isDynamicElement(element)) {
1968
+ const dynamicTag = readReactive4(props.component);
1969
+ const dynamic = createDynamicElement3(element, dynamicTag);
1970
+ if (dynamic) {
1971
+ await streamElement(dynamic, controller, encoder);
1972
+ }
1973
+ return;
1974
+ }
1975
+ if (isPortalElement(element)) {
1976
+ return;
1977
+ }
1409
1978
  if (typeof tag === "function") {
1410
1979
  const result = await tag(props);
1411
1980
  await streamNode(result, controller, encoder);
@@ -1440,16 +2009,10 @@ function renderAttributes2(props) {
1440
2009
  if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
1441
2010
  continue;
1442
2011
  }
1443
- const resolvedValue = readReactive3(value);
2012
+ const resolvedValue = readReactive4(value);
1444
2013
  if (resolvedValue == null || resolvedValue === false)
1445
2014
  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}"`;
2015
+ attrs += renderServerAttribute(key, resolvedValue);
1453
2016
  }
1454
2017
  return attrs;
1455
2018
  }
@@ -1494,12 +2057,16 @@ async function streamHydratableElement(element, controller, encoder, ctx, isComp
1494
2057
  }
1495
2058
  return;
1496
2059
  }
1497
- if (tag === Show || tag === For) {
2060
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2061
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
2062
+ return;
2063
+ }
2064
+ if (tag === Visible) {
1498
2065
  await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
1499
2066
  return;
1500
2067
  }
1501
2068
  if (isShowElement(element)) {
1502
- const when = readReactive3(props.when);
2069
+ const when = readReactive4(props.when);
1503
2070
  await streamHydratableNodeToController(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder, ctx, isComponentRoot);
1504
2071
  return;
1505
2072
  }
@@ -1507,6 +2074,35 @@ async function streamHydratableElement(element, controller, encoder, ctx, isComp
1507
2074
  await streamHydratableForElement(element, controller, encoder, ctx);
1508
2075
  return;
1509
2076
  }
2077
+ if (isSwitchElement(element)) {
2078
+ await streamHydratableNodeToController(resolveSwitchContent3(element), controller, encoder, ctx, isComponentRoot);
2079
+ return;
2080
+ }
2081
+ if (isMatchElement(element)) {
2082
+ const when = readReactive4(props.when);
2083
+ await streamHydratableNodeToController(when ? resolveMatchChildren3(element, when) : null, controller, encoder, ctx, isComponentRoot);
2084
+ return;
2085
+ }
2086
+ if (isIndexElement(element)) {
2087
+ await streamHydratableIndexElement(element, controller, encoder, ctx);
2088
+ return;
2089
+ }
2090
+ if (isKeyElement(element)) {
2091
+ const key = readReactive4(props.when);
2092
+ await streamHydratableNodeToController(resolveKeyChildren3(element, key), controller, encoder, ctx, isComponentRoot);
2093
+ return;
2094
+ }
2095
+ if (isDynamicElement(element)) {
2096
+ const dynamicTag = readReactive4(props.component);
2097
+ const dynamic = createDynamicElement3(element, dynamicTag);
2098
+ if (dynamic) {
2099
+ await streamHydratableElement(dynamic, controller, encoder, ctx, isComponentRoot);
2100
+ }
2101
+ return;
2102
+ }
2103
+ if (isPortalElement(element)) {
2104
+ return;
2105
+ }
1510
2106
  if (typeof tag === "function") {
1511
2107
  await streamHydratableComponent(tag, props, controller, encoder, ctx, true);
1512
2108
  return;
@@ -1549,14 +2145,42 @@ async function streamHydratableIntrinsic(tag, props, children, controller, encod
1549
2145
  }
1550
2146
  async function streamHydratableForElement(element, controller, encoder, ctx) {
1551
2147
  const props = element.props;
1552
- const each = readReactive3(props.each);
2148
+ const each = readReactive4(props.each);
1553
2149
  if (!Array.isArray(each) || typeof props.children !== "function") {
2150
+ if (props.fallback) {
2151
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2152
+ }
2153
+ return;
2154
+ }
2155
+ if (each.length === 0) {
2156
+ if (props.fallback) {
2157
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2158
+ }
1554
2159
  return;
1555
2160
  }
1556
2161
  for (let index = 0;index < each.length; index++) {
1557
2162
  await streamHydratableNodeToController(props.children(each[index], () => index), controller, encoder, ctx);
1558
2163
  }
1559
2164
  }
2165
+ async function streamHydratableIndexElement(element, controller, encoder, ctx) {
2166
+ const props = element.props;
2167
+ const each = readReactive4(props.each);
2168
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2169
+ if (props.fallback) {
2170
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2171
+ }
2172
+ return;
2173
+ }
2174
+ if (each.length === 0) {
2175
+ if (props.fallback) {
2176
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2177
+ }
2178
+ return;
2179
+ }
2180
+ for (let index = 0;index < each.length; index++) {
2181
+ await streamHydratableNodeToController(props.children(() => each[index], index), controller, encoder, ctx);
2182
+ }
2183
+ }
1560
2184
  function renderHydratableAttributes(props, ctx, isComponentRoot) {
1561
2185
  let attrs = "";
1562
2186
  if (isComponentRoot) {
@@ -1571,15 +2195,10 @@ function renderHydratableAttributes(props, ctx, isComponentRoot) {
1571
2195
  eventParts.push(`${toEventName(key)}:${ctx.eventIndex++}`);
1572
2196
  continue;
1573
2197
  }
1574
- const resolvedValue = readReactive3(value);
2198
+ const resolvedValue = readReactive4(value);
1575
2199
  if (resolvedValue == null || resolvedValue === false)
1576
2200
  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))}"`;
2201
+ attrs += renderServerAttribute(key, resolvedValue);
1583
2202
  }
1584
2203
  if (eventParts.length > 0) {
1585
2204
  attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
@@ -1591,14 +2210,42 @@ function enqueue(controller, encoder, html) {
1591
2210
  }
1592
2211
  async function streamForElement(element, controller, encoder) {
1593
2212
  const props = element.props;
1594
- const each = readReactive3(props.each);
2213
+ const each = readReactive4(props.each);
1595
2214
  if (!Array.isArray(each) || typeof props.children !== "function") {
2215
+ if (props.fallback) {
2216
+ await streamNode(props.fallback, controller, encoder);
2217
+ }
2218
+ return;
2219
+ }
2220
+ if (each.length === 0) {
2221
+ if (props.fallback) {
2222
+ await streamNode(props.fallback, controller, encoder);
2223
+ }
1596
2224
  return;
1597
2225
  }
1598
2226
  for (let index = 0;index < each.length; index++) {
1599
2227
  await streamNode(props.children(each[index], () => index), controller, encoder);
1600
2228
  }
1601
2229
  }
2230
+ async function streamIndexElement(element, controller, encoder) {
2231
+ const props = element.props;
2232
+ const each = readReactive4(props.each);
2233
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2234
+ if (props.fallback) {
2235
+ await streamNode(props.fallback, controller, encoder);
2236
+ }
2237
+ return;
2238
+ }
2239
+ if (each.length === 0) {
2240
+ if (props.fallback) {
2241
+ await streamNode(props.fallback, controller, encoder);
2242
+ }
2243
+ return;
2244
+ }
2245
+ for (let index = 0;index < each.length; index++) {
2246
+ await streamNode(props.children(() => each[index], index), controller, encoder);
2247
+ }
2248
+ }
1602
2249
  function resolveShowChildren3(element, value) {
1603
2250
  const children = element.props.children ?? element.children;
1604
2251
  if (typeof children === "function") {
@@ -1606,9 +2253,68 @@ function resolveShowChildren3(element, value) {
1606
2253
  }
1607
2254
  return children;
1608
2255
  }
1609
- function readReactive3(value) {
2256
+ function resolveSwitchContent3(element) {
2257
+ const props = element.props;
2258
+ const children = normalizeContent3(props.children ?? element.children);
2259
+ for (const child of children) {
2260
+ const match = getMatchElement3(child);
2261
+ if (!match) {
2262
+ continue;
2263
+ }
2264
+ const when = readReactive4(match.props.when);
2265
+ if (when) {
2266
+ return resolveMatchChildren3(match, when);
2267
+ }
2268
+ }
2269
+ return props.fallback;
2270
+ }
2271
+ function resolveMatchChildren3(element, value) {
2272
+ const children = element.props.children ?? element.children;
2273
+ if (typeof children === "function") {
2274
+ return children(value);
2275
+ }
2276
+ return children;
2277
+ }
2278
+ function resolveKeyChildren3(element, value) {
2279
+ const children = element.props.children ?? element.children;
2280
+ if (typeof children === "function") {
2281
+ return children(value);
2282
+ }
2283
+ return children;
2284
+ }
2285
+ function createDynamicElement3(element, tag) {
2286
+ if (typeof tag !== "string" && typeof tag !== "function") {
2287
+ return null;
2288
+ }
2289
+ const { component, ...props } = element.props;
2290
+ const children = normalizeContent3(props.children ?? element.children);
2291
+ return {
2292
+ tag,
2293
+ props,
2294
+ children
2295
+ };
2296
+ }
2297
+ function readReactive4(value) {
1610
2298
  return isSignal(value) || isComputed(value) ? value.value : value;
1611
2299
  }
2300
+ function normalizeContent3(content) {
2301
+ if (content == null || typeof content === "boolean") {
2302
+ return [];
2303
+ }
2304
+ return Array.isArray(content) ? content : [content];
2305
+ }
2306
+ function isElementLike3(value) {
2307
+ return value != null && typeof value === "object" && "tag" in value;
2308
+ }
2309
+ function getMatchElement3(value) {
2310
+ if (!isElementLike3(value)) {
2311
+ return null;
2312
+ }
2313
+ if (isMatchElement(value)) {
2314
+ return value;
2315
+ }
2316
+ return value.tag === Match ? Match(value.props) : null;
2317
+ }
1612
2318
  // src/server/hydration-markers.ts
1613
2319
  function createHydrationContext() {
1614
2320
  return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
@@ -1678,17 +2384,42 @@ function renderElementH(element, ctx, isComponentRoot) {
1678
2384
  if (tag === "") {
1679
2385
  return children.map((child) => renderNodeH(child, ctx)).join("");
1680
2386
  }
1681
- if (tag === Show || tag === For) {
2387
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2388
+ return renderElementH(tag(props), ctx, isComponentRoot);
2389
+ }
2390
+ if (tag === Visible) {
1682
2391
  return renderElementH(tag(props), ctx, isComponentRoot);
1683
2392
  }
1684
2393
  if (isShowElement(element)) {
1685
- const when = readReactive4(props.when);
2394
+ const when = readReactive5(props.when);
1686
2395
  const content = when ? resolveShowChildren4(element, when) : props.fallback;
1687
2396
  return renderNodeMaybeRoot(content, ctx, isComponentRoot);
1688
2397
  }
1689
2398
  if (isForElement(element)) {
1690
2399
  return renderForElementH(element, ctx);
1691
2400
  }
2401
+ if (isSwitchElement(element)) {
2402
+ return renderNodeMaybeRoot(resolveSwitchContent4(element), ctx, isComponentRoot);
2403
+ }
2404
+ if (isMatchElement(element)) {
2405
+ const when = readReactive5(props.when);
2406
+ return renderNodeMaybeRoot(when ? resolveMatchChildren4(element, when) : null, ctx, isComponentRoot);
2407
+ }
2408
+ if (isIndexElement(element)) {
2409
+ return renderIndexElementH(element, ctx);
2410
+ }
2411
+ if (isKeyElement(element)) {
2412
+ const key = readReactive5(props.when);
2413
+ return renderNodeMaybeRoot(resolveKeyChildren4(element, key), ctx, isComponentRoot);
2414
+ }
2415
+ if (isDynamicElement(element)) {
2416
+ const dynamicTag = readReactive5(props.component);
2417
+ const dynamic = createDynamicElement4(element, dynamicTag);
2418
+ return dynamic ? renderElementH(dynamic, ctx, isComponentRoot) : "";
2419
+ }
2420
+ if (isPortalElement(element)) {
2421
+ return "";
2422
+ }
1692
2423
  if (typeof tag === "function") {
1693
2424
  return renderComponentH(tag, props, ctx);
1694
2425
  }
@@ -1735,13 +2466,7 @@ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
1735
2466
  if (isSignal(value) || isComputed(value)) {
1736
2467
  resolvedValue = value.value;
1737
2468
  }
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))}"`;
2469
+ attrs += renderServerAttribute(key, resolvedValue);
1745
2470
  }
1746
2471
  if (eventParts.length > 0) {
1747
2472
  attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
@@ -1764,12 +2489,26 @@ function renderNodeMaybeRoot(node, ctx, isComponentRoot) {
1764
2489
  }
1765
2490
  function renderForElementH(element, ctx) {
1766
2491
  const props = element.props;
1767
- const each = readReactive4(props.each);
2492
+ const each = readReactive5(props.each);
1768
2493
  if (!Array.isArray(each) || typeof props.children !== "function") {
1769
- return "";
2494
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2495
+ }
2496
+ if (each.length === 0) {
2497
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1770
2498
  }
1771
2499
  return each.map((item, index) => renderNodeH(props.children(item, () => index), ctx)).join("");
1772
2500
  }
2501
+ function renderIndexElementH(element, ctx) {
2502
+ const props = element.props;
2503
+ const each = readReactive5(props.each);
2504
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2505
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2506
+ }
2507
+ if (each.length === 0) {
2508
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2509
+ }
2510
+ return each.map((item, index) => renderNodeH(props.children(() => item, index), ctx)).join("");
2511
+ }
1773
2512
  function resolveShowChildren4(element, value) {
1774
2513
  const children = element.props.children ?? element.children;
1775
2514
  if (typeof children === "function") {
@@ -1777,21 +2516,67 @@ function resolveShowChildren4(element, value) {
1777
2516
  }
1778
2517
  return children;
1779
2518
  }
1780
- function readReactive4(value) {
2519
+ function resolveSwitchContent4(element) {
2520
+ const props = element.props;
2521
+ const children = normalizeContent4(props.children ?? element.children);
2522
+ for (const child of children) {
2523
+ const match = getMatchElement4(child);
2524
+ if (!match) {
2525
+ continue;
2526
+ }
2527
+ const when = readReactive5(match.props.when);
2528
+ if (when) {
2529
+ return resolveMatchChildren4(match, when);
2530
+ }
2531
+ }
2532
+ return props.fallback;
2533
+ }
2534
+ function resolveMatchChildren4(element, value) {
2535
+ const children = element.props.children ?? element.children;
2536
+ if (typeof children === "function") {
2537
+ return children(value);
2538
+ }
2539
+ return children;
2540
+ }
2541
+ function resolveKeyChildren4(element, value) {
2542
+ const children = element.props.children ?? element.children;
2543
+ if (typeof children === "function") {
2544
+ return children(value);
2545
+ }
2546
+ return children;
2547
+ }
2548
+ function createDynamicElement4(element, tag) {
2549
+ if (typeof tag !== "string" && typeof tag !== "function") {
2550
+ return null;
2551
+ }
2552
+ const { component, ...props } = element.props;
2553
+ const children = normalizeContent4(props.children ?? element.children);
2554
+ return {
2555
+ tag,
2556
+ props,
2557
+ children
2558
+ };
2559
+ }
2560
+ function readReactive5(value) {
1781
2561
  return isSignal(value) || isComputed(value) ? value.value : value;
1782
2562
  }
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
- }
2563
+ function normalizeContent4(content) {
2564
+ if (content == null || typeof content === "boolean") {
2565
+ return [];
2566
+ }
2567
+ return Array.isArray(content) ? content : [content];
2568
+ }
2569
+ function isElementLike4(value) {
2570
+ return value != null && typeof value === "object" && "tag" in value;
2571
+ }
2572
+ function getMatchElement4(value) {
2573
+ if (!isElementLike4(value)) {
2574
+ return null;
1794
2575
  }
2576
+ if (isMatchElement(value)) {
2577
+ return value;
2578
+ }
2579
+ return value.tag === Match ? Match(value.props) : null;
1795
2580
  }
1796
2581
  // src/component/lifecycle.ts
1797
2582
  function onMounted(fn) {
@@ -1945,10 +2730,16 @@ function hydrateElement(element, cursor) {
1945
2730
  if (tag === "") {
1946
2731
  return hydrateArray(children, cursor);
1947
2732
  }
1948
- if (tag === Show || tag === For) {
2733
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2734
+ return hydrateElement(tag(props), cursor);
2735
+ }
2736
+ if (tag === Visible) {
1949
2737
  return hydrateElement(tag(props), cursor);
1950
2738
  }
1951
- if (isShowElement(element) || isForElement(element)) {
2739
+ if (isPortalElement(element)) {
2740
+ return renderControlFlowToDOM(element, cursor.parent, cursor.current, null);
2741
+ }
2742
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element)) {
1952
2743
  return hydrateControlFlow(element, cursor);
1953
2744
  }
1954
2745
  if (typeof tag === "function") {
@@ -1991,20 +2782,13 @@ function hydrateAttributes(el, props) {
1991
2782
  const disposers = [];
1992
2783
  const owner = getCurrentInstance();
1993
2784
  for (const [key, value] of Object.entries(props)) {
1994
- if (key === "children" || key === "key" || key === "ref" || isEventProp(key))
2785
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key))
1995
2786
  continue;
1996
2787
  if (isSignal(value) || isComputed(value)) {
2788
+ const state = { previousStyleProps: new Set };
1997
2789
  let initialized = false;
1998
2790
  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
- }
2791
+ setSingleAttribute(el, key, value.value, state);
2008
2792
  if (initialized) {
2009
2793
  queueUpdatedHooks(owner);
2010
2794
  }
@@ -2017,16 +2801,34 @@ function hydrateAttributes(el, props) {
2017
2801
  }
2018
2802
  function hydrateControlFlow(element, cursor) {
2019
2803
  if (isShowElement(element)) {
2020
- const when = readReactive5(element.props.when);
2804
+ const when = readReactive6(element.props.when);
2021
2805
  const content = when ? resolveShowChildren5(element, when) : element.props.fallback;
2022
2806
  return hydrateContent(content, cursor);
2023
2807
  }
2024
2808
  if (isForElement(element)) {
2025
2809
  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)) : [];
2810
+ const items = readReactive6(props.each);
2811
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(item, () => index)) : props.fallback ? [props.fallback] : [];
2812
+ return hydrateArray(children, cursor);
2813
+ }
2814
+ if (isSwitchElement(element)) {
2815
+ return hydrateContent(resolveSwitchContent5(element), cursor);
2816
+ }
2817
+ if (isIndexElement(element)) {
2818
+ const props = element.props;
2819
+ const items = readReactive6(props.each);
2820
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(() => item, index)) : props.fallback ? [props.fallback] : [];
2028
2821
  return hydrateArray(children, cursor);
2029
2822
  }
2823
+ if (isKeyElement(element)) {
2824
+ const key = readReactive6(element.props.when);
2825
+ return hydrateContent(resolveKeyChildren5(element, key), cursor);
2826
+ }
2827
+ if (isDynamicElement(element)) {
2828
+ const tag = readReactive6(element.props.component);
2829
+ const dynamic = createDynamicElement5(element, tag);
2830
+ return dynamic ? hydrateElement(dynamic, cursor) : hydrateArray([], cursor);
2831
+ }
2030
2832
  return hydrateArray(element.children, cursor);
2031
2833
  }
2032
2834
  function hydrateContent(content, cursor) {
@@ -2042,9 +2844,68 @@ function resolveShowChildren5(element, value) {
2042
2844
  }
2043
2845
  return children;
2044
2846
  }
2045
- function readReactive5(value) {
2847
+ function resolveSwitchContent5(element) {
2848
+ const props = element.props;
2849
+ const children = normalizeContent5(props.children ?? element.children);
2850
+ for (const child of children) {
2851
+ const match = getMatchElement5(child);
2852
+ if (!match) {
2853
+ continue;
2854
+ }
2855
+ const when = readReactive6(match.props.when);
2856
+ if (when) {
2857
+ return resolveMatchChildren5(match, when);
2858
+ }
2859
+ }
2860
+ return props.fallback;
2861
+ }
2862
+ function resolveMatchChildren5(element, value) {
2863
+ const children = element.props.children ?? element.children;
2864
+ if (typeof children === "function") {
2865
+ return children(value);
2866
+ }
2867
+ return children;
2868
+ }
2869
+ function resolveKeyChildren5(element, value) {
2870
+ const children = element.props.children ?? element.children;
2871
+ if (typeof children === "function") {
2872
+ return children(value);
2873
+ }
2874
+ return children;
2875
+ }
2876
+ function createDynamicElement5(element, tag) {
2877
+ if (typeof tag !== "string" && typeof tag !== "function") {
2878
+ return null;
2879
+ }
2880
+ const { component, ...props } = element.props;
2881
+ const children = normalizeContent5(props.children ?? element.children);
2882
+ return {
2883
+ tag,
2884
+ props,
2885
+ children
2886
+ };
2887
+ }
2888
+ function readReactive6(value) {
2046
2889
  return isSignal(value) || isComputed(value) ? value.value : value;
2047
2890
  }
2891
+ function normalizeContent5(content) {
2892
+ if (content == null || typeof content === "boolean") {
2893
+ return [];
2894
+ }
2895
+ return Array.isArray(content) ? content : [content];
2896
+ }
2897
+ function isElementLike5(value) {
2898
+ return value != null && typeof value === "object" && "tag" in value;
2899
+ }
2900
+ function getMatchElement5(value) {
2901
+ if (!isElementLike5(value)) {
2902
+ return null;
2903
+ }
2904
+ if (isMatchElement(value)) {
2905
+ return value;
2906
+ }
2907
+ return value.tag === Match ? Match(value.props) : null;
2908
+ }
2048
2909
  function applyRef2(el, ref) {
2049
2910
  const value = ref;
2050
2911
  if (!value) {
@@ -2191,11 +3052,18 @@ export {
2191
3052
  createComponent,
2192
3053
  computed,
2193
3054
  batch,
3055
+ Visible,
3056
+ Switch,
2194
3057
  Show,
3058
+ Portal,
3059
+ Match,
3060
+ Key,
3061
+ Index,
2195
3062
  HtmlEscapedString,
2196
3063
  Fragment,
2197
- For
3064
+ For,
3065
+ Dynamic
2198
3066
  };
2199
3067
 
2200
- //# debugId=14DE79AF90B411D764756E2164756E21
3068
+ //# debugId=5F7C902C8127620064756E2164756E21
2201
3069
  //# sourceMappingURL=index.development.js.map