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
@@ -578,9 +578,10 @@ function applyAttributes(el, props) {
578
578
  if (SKIP_PROPS.has(key) || isEventProp(key))
579
579
  continue;
580
580
  if (isSignal(value) || isComputed(value)) {
581
+ const state = { previousStyleProps: new Set };
581
582
  let initialized = false;
582
583
  const dispose = effect(() => {
583
- setSingleAttribute(el, key, value.value);
584
+ setSingleAttribute(el, key, value.value, state);
584
585
  if (initialized) {
585
586
  queueUpdatedHooks(owner);
586
587
  }
@@ -593,10 +594,10 @@ function applyAttributes(el, props) {
593
594
  }
594
595
  return disposers;
595
596
  }
596
- function setSingleAttribute(el, key, value) {
597
- const attrName = PROP_ALIASES[key] ?? key;
597
+ function setSingleAttribute(el, key, value, state) {
598
+ const attrName = resolveAttributeName(key);
598
599
  if (attrName === "style" && typeof value === "object" && value !== null) {
599
- applyStyle(el, value);
600
+ applyStyle(el, value, state);
600
601
  return;
601
602
  }
602
603
  if (attrName === "class" && typeof value === "object" && value !== null) {
@@ -605,6 +606,9 @@ function setSingleAttribute(el, key, value) {
605
606
  }
606
607
  if (value == null || value === false) {
607
608
  domOps.removeAttribute(el, attrName);
609
+ if (attrName === "style" && state) {
610
+ state.previousStyleProps.clear();
611
+ }
608
612
  if (DOM_PROPERTIES.has(attrName)) {
609
613
  domOps.setProperty(el, attrName, attrName === "value" ? "" : false);
610
614
  }
@@ -612,25 +616,59 @@ function setSingleAttribute(el, key, value) {
612
616
  }
613
617
  if (value === true) {
614
618
  domOps.setAttribute(el, attrName, "");
619
+ if (attrName === "style" && state) {
620
+ state.previousStyleProps.clear();
621
+ }
615
622
  if (DOM_PROPERTIES.has(attrName)) {
616
623
  domOps.setProperty(el, attrName, true);
617
624
  }
618
625
  return;
619
626
  }
620
627
  if (DOM_PROPERTIES.has(attrName)) {
628
+ if (attrName === "style" && state) {
629
+ state.previousStyleProps.clear();
630
+ }
621
631
  domOps.setProperty(el, attrName, value);
622
632
  return;
623
633
  }
634
+ if (attrName === "style" && state) {
635
+ state.previousStyleProps.clear();
636
+ }
624
637
  domOps.setAttribute(el, attrName, String(value));
625
638
  }
626
- function applyStyle(el, styles) {
639
+ function resolveAttributeName(key) {
640
+ return PROP_ALIASES[key] ?? key;
641
+ }
642
+ function applyStyle(el, styles, state) {
643
+ const nextProps = new Set;
627
644
  for (const [prop, val] of Object.entries(styles)) {
645
+ nextProps.add(prop);
646
+ if (val == null) {
647
+ removeStyleProperty(el, prop);
648
+ continue;
649
+ }
628
650
  if (prop.includes("-")) {
629
- el.style.setProperty(prop, val);
651
+ el.style.setProperty(prop, String(val));
630
652
  } else {
631
653
  el.style[prop] = val;
632
654
  }
633
655
  }
656
+ if (!state) {
657
+ return;
658
+ }
659
+ for (const previousProp of state.previousStyleProps) {
660
+ if (!nextProps.has(previousProp)) {
661
+ removeStyleProperty(el, previousProp);
662
+ }
663
+ }
664
+ state.previousStyleProps = nextProps;
665
+ }
666
+ function removeStyleProperty(el, prop) {
667
+ if (prop.includes("-")) {
668
+ el.style.removeProperty(prop);
669
+ } else {
670
+ el.style[prop] = "";
671
+ }
634
672
  }
635
673
  function applyClass(el, value) {
636
674
  let classStr;
@@ -643,10 +681,28 @@ function applyClass(el, value) {
643
681
  }
644
682
  domOps.setAttribute(el, "class", classStr);
645
683
  }
646
-
684
+ // src/reactivity/batch.ts
685
+ var batchDepth = 0;
686
+ function batch(fn) {
687
+ batchDepth++;
688
+ try {
689
+ fn();
690
+ } finally {
691
+ batchDepth--;
692
+ if (batchDepth === 0) {
693
+ flushSync();
694
+ }
695
+ }
696
+ }
647
697
  // src/component/control-flow.ts
648
698
  var SHOW_TYPE = Symbol.for("Sinwan.Show");
649
699
  var FOR_TYPE = Symbol.for("Sinwan.For");
700
+ var SWITCH_TYPE = Symbol.for("Sinwan.Switch");
701
+ var MATCH_TYPE = Symbol.for("Sinwan.Match");
702
+ var INDEX_TYPE = Symbol.for("Sinwan.Index");
703
+ var KEY_TYPE = Symbol.for("Sinwan.Key");
704
+ var DYNAMIC_TYPE = Symbol.for("Sinwan.Dynamic");
705
+ var PORTAL_TYPE = Symbol.for("Sinwan.Portal");
650
706
  function Show(props) {
651
707
  return {
652
708
  tag: SHOW_TYPE,
@@ -661,12 +717,114 @@ function For(props) {
661
717
  children: []
662
718
  };
663
719
  }
720
+ function Switch(props) {
721
+ return {
722
+ tag: SWITCH_TYPE,
723
+ props,
724
+ children: []
725
+ };
726
+ }
727
+ function Match(props) {
728
+ return {
729
+ tag: MATCH_TYPE,
730
+ props,
731
+ children: []
732
+ };
733
+ }
734
+ function Index(props) {
735
+ return {
736
+ tag: INDEX_TYPE,
737
+ props,
738
+ children: []
739
+ };
740
+ }
741
+ function Key(props) {
742
+ return {
743
+ tag: KEY_TYPE,
744
+ props,
745
+ children: []
746
+ };
747
+ }
748
+ function Dynamic(props) {
749
+ return {
750
+ tag: DYNAMIC_TYPE,
751
+ props,
752
+ children: []
753
+ };
754
+ }
755
+ function Visible(props) {
756
+ const {
757
+ when,
758
+ as = "span",
759
+ style,
760
+ children,
761
+ ...rest
762
+ } = props;
763
+ const visibleStyle = computed(() => {
764
+ const base = readReactive(style);
765
+ const visible = Boolean(readReactive(when));
766
+ if (typeof base === "string") {
767
+ return visible ? base : appendHiddenDisplay(base);
768
+ }
769
+ const styleObject = base && typeof base === "object" ? { ...base } : {};
770
+ styleObject.display = visible ? styleObject.display : "none";
771
+ return styleObject;
772
+ });
773
+ return {
774
+ tag: as,
775
+ props: {
776
+ ...rest,
777
+ style: visibleStyle,
778
+ children
779
+ },
780
+ children: normalizeChildren2(children)
781
+ };
782
+ }
783
+ function Portal(props) {
784
+ return {
785
+ tag: PORTAL_TYPE,
786
+ props,
787
+ children: []
788
+ };
789
+ }
664
790
  function isShowElement(element) {
665
791
  return element.tag === SHOW_TYPE;
666
792
  }
667
793
  function isForElement(element) {
668
794
  return element.tag === FOR_TYPE;
669
795
  }
796
+ function isSwitchElement(element) {
797
+ return element.tag === SWITCH_TYPE;
798
+ }
799
+ function isMatchElement(element) {
800
+ return element.tag === MATCH_TYPE;
801
+ }
802
+ function isIndexElement(element) {
803
+ return element.tag === INDEX_TYPE;
804
+ }
805
+ function isKeyElement(element) {
806
+ return element.tag === KEY_TYPE;
807
+ }
808
+ function isDynamicElement(element) {
809
+ return element.tag === DYNAMIC_TYPE;
810
+ }
811
+ function isPortalElement(element) {
812
+ return element.tag === PORTAL_TYPE;
813
+ }
814
+ function normalizeChildren2(children) {
815
+ if (children == null || typeof children === "boolean") {
816
+ return [];
817
+ }
818
+ return Array.isArray(children) ? children : [children];
819
+ }
820
+ function readReactive(value) {
821
+ return isSignal(value) || isComputed(value) ? value.value : value;
822
+ }
823
+ function appendHiddenDisplay(style) {
824
+ const trimmed = style.trim();
825
+ const separator = trimmed.length > 0 && !trimmed.endsWith(";") ? ";" : "";
826
+ return `${trimmed}${separator}display:none`;
827
+ }
670
828
 
671
829
  // src/renderer/unmount.ts
672
830
  function getMountedDomNodes(node) {
@@ -689,6 +847,8 @@ function getMountedDomNodes(node) {
689
847
  ];
690
848
  case "component":
691
849
  return node.children.flatMap((child) => getMountedDomNodes(child));
850
+ case "portal":
851
+ return [node.anchor];
692
852
  }
693
853
  }
694
854
  function unmountNode(node) {
@@ -733,6 +893,13 @@ function unmountNode(node) {
733
893
  unmountNode(child);
734
894
  }
735
895
  break;
896
+ case "portal":
897
+ node.dispose();
898
+ for (const child of node.children) {
899
+ removeMountedNode(child);
900
+ }
901
+ node.children = [];
902
+ break;
736
903
  }
737
904
  }
738
905
  function removeMountedNode(node) {
@@ -747,6 +914,9 @@ function removeMountedNode(node) {
747
914
 
748
915
  // src/renderer/render-control-flow.ts
749
916
  function renderControlFlowToDOM(element, parent, anchor, namespace) {
917
+ if (isPortalElement(element)) {
918
+ return renderPortal(element, parent, anchor, namespace);
919
+ }
750
920
  const startAnchor = domOps.createComment("Sinwan-b");
751
921
  const endAnchor = domOps.createComment("/Sinwan-b");
752
922
  insertNode(parent, startAnchor, anchor);
@@ -764,6 +934,14 @@ function renderControlFlowToDOM(element, parent, anchor, namespace) {
764
934
  disposeEffect = renderShowBlock(element, block, parent, namespace, owner);
765
935
  } else if (isForElement(element)) {
766
936
  disposeEffect = renderForBlock(element, block, parent, namespace, owner);
937
+ } else if (isSwitchElement(element)) {
938
+ disposeEffect = renderSwitchBlock(element, block, parent, namespace, owner);
939
+ } else if (isIndexElement(element)) {
940
+ disposeEffect = renderIndexBlock(element, block, parent, namespace, owner);
941
+ } else if (isKeyElement(element)) {
942
+ disposeEffect = renderKeyBlock(element, block, parent, namespace, owner);
943
+ } else if (isDynamicElement(element)) {
944
+ disposeEffect = renderDynamicBlock(element, block, parent, namespace, owner);
767
945
  }
768
946
  return block;
769
947
  }
@@ -771,7 +949,7 @@ function renderShowBlock(element, block, parent, namespace, owner) {
771
949
  let initialized = false;
772
950
  return effect(() => {
773
951
  clearChildren(block);
774
- const when = readReactive(element.props.when);
952
+ const when = readReactive2(element.props.when);
775
953
  const content = withOptionalInstance(owner, () => when ? resolveShowChildren(element, when) : element.props.fallback);
776
954
  block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
777
955
  if (initialized) {
@@ -785,7 +963,7 @@ function renderForBlock(element, block, parent, namespace, owner) {
785
963
  let records = [];
786
964
  return effect(() => {
787
965
  const props = element.props;
788
- const items = readReactive(props.each);
966
+ const items = readReactive2(props.each);
789
967
  const list = Array.isArray(items) ? items : [];
790
968
  const renderChild = props.children;
791
969
  if (typeof renderChild !== "function") {
@@ -797,6 +975,19 @@ function renderForBlock(element, block, parent, namespace, owner) {
797
975
  initialized = true;
798
976
  return;
799
977
  }
978
+ if (list.length === 0) {
979
+ clearChildren(block);
980
+ records = [];
981
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
982
+ if (initialized) {
983
+ fireMountedAndQueueUpdated(owner);
984
+ }
985
+ initialized = true;
986
+ return;
987
+ }
988
+ if (records.length === 0 && block.children.length > 0) {
989
+ clearChildren(block);
990
+ }
800
991
  const oldByKey = new Map;
801
992
  for (const record of records) {
802
993
  oldByKey.set(record.key, record);
@@ -836,6 +1027,137 @@ function renderForBlock(element, block, parent, namespace, owner) {
836
1027
  initialized = true;
837
1028
  });
838
1029
  }
1030
+ function renderSwitchBlock(element, block, parent, namespace, owner) {
1031
+ let initialized = false;
1032
+ return effect(() => {
1033
+ clearChildren(block);
1034
+ const content = withOptionalInstance(owner, () => resolveSwitchContent(element));
1035
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1036
+ if (initialized) {
1037
+ fireMountedAndQueueUpdated(owner);
1038
+ }
1039
+ initialized = true;
1040
+ });
1041
+ }
1042
+ function renderIndexBlock(element, block, parent, namespace, owner) {
1043
+ let initialized = false;
1044
+ let records = [];
1045
+ return effect(() => {
1046
+ const props = element.props;
1047
+ const items = readReactive2(props.each);
1048
+ const list = Array.isArray(items) ? items : [];
1049
+ const renderChild = props.children;
1050
+ if (typeof renderChild !== "function") {
1051
+ clearChildren(block);
1052
+ records = [];
1053
+ if (initialized) {
1054
+ queueUpdatedHooks(owner);
1055
+ }
1056
+ initialized = true;
1057
+ return;
1058
+ }
1059
+ if (list.length === 0) {
1060
+ clearChildren(block);
1061
+ records = [];
1062
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
1063
+ if (initialized) {
1064
+ fireMountedAndQueueUpdated(owner);
1065
+ }
1066
+ initialized = true;
1067
+ return;
1068
+ }
1069
+ if (records.length === 0 && block.children.length > 0) {
1070
+ clearChildren(block);
1071
+ }
1072
+ for (let index = 0;index < list.length; index++) {
1073
+ const existing = records[index];
1074
+ if (existing) {
1075
+ existing.item.value = list[index];
1076
+ continue;
1077
+ }
1078
+ const itemSignal = signal(list[index]);
1079
+ const record = {
1080
+ item: itemSignal,
1081
+ mounted: withOptionalInstance(owner, () => renderNodeToDOM(renderChild(() => itemSignal.value, index), parent, block.endAnchor, namespace))
1082
+ };
1083
+ records.push(record);
1084
+ }
1085
+ while (records.length > list.length) {
1086
+ const removed = records.pop();
1087
+ removeMountedNode(removed.mounted);
1088
+ }
1089
+ block.children = records.map((record) => record.mounted);
1090
+ if (initialized) {
1091
+ fireMountedAndQueueUpdated(owner);
1092
+ }
1093
+ initialized = true;
1094
+ });
1095
+ }
1096
+ function renderKeyBlock(element, block, parent, namespace, owner) {
1097
+ let initialized = false;
1098
+ let hasKey = false;
1099
+ let currentKey;
1100
+ return effect(() => {
1101
+ const key = readReactive2(element.props.when);
1102
+ if (hasKey && Object.is(currentKey, key)) {
1103
+ return;
1104
+ }
1105
+ currentKey = key;
1106
+ hasKey = true;
1107
+ clearChildren(block);
1108
+ const content = withOptionalInstance(owner, () => resolveKeyChildren(element, key));
1109
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1110
+ if (initialized) {
1111
+ fireMountedAndQueueUpdated(owner);
1112
+ }
1113
+ initialized = true;
1114
+ });
1115
+ }
1116
+ function renderDynamicBlock(element, block, parent, namespace, owner) {
1117
+ let initialized = false;
1118
+ let hasTag = false;
1119
+ let currentTag;
1120
+ return effect(() => {
1121
+ const tag = readReactive2(element.props.component);
1122
+ if (hasTag && Object.is(currentTag, tag)) {
1123
+ return;
1124
+ }
1125
+ currentTag = tag;
1126
+ hasTag = true;
1127
+ clearChildren(block);
1128
+ const content = tag ? createDynamicElement(element, tag) : null;
1129
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1130
+ if (initialized) {
1131
+ fireMountedAndQueueUpdated(owner);
1132
+ }
1133
+ initialized = true;
1134
+ });
1135
+ }
1136
+ function renderPortal(element, parent, anchor, namespace) {
1137
+ const placeholder = domOps.createComment("Sinwan-p");
1138
+ insertNode(parent, placeholder, anchor);
1139
+ const owner = getCurrentInstance();
1140
+ let disposeEffect = () => {};
1141
+ const portal = {
1142
+ type: "portal",
1143
+ anchor: placeholder,
1144
+ children: [],
1145
+ dispose: () => disposeEffect()
1146
+ };
1147
+ let initialized = false;
1148
+ disposeEffect = effect(() => {
1149
+ clearPortalChildren(portal);
1150
+ const target = resolvePortalTarget(element.props.mount);
1151
+ if (target) {
1152
+ portal.children = renderBlockContent(element.props.children ?? element.children, target, null, namespace, owner);
1153
+ }
1154
+ if (initialized) {
1155
+ fireMountedAndQueueUpdated(owner);
1156
+ }
1157
+ initialized = true;
1158
+ });
1159
+ return portal;
1160
+ }
839
1161
  function resolveShowChildren(element, value) {
840
1162
  const children = element.props.children ?? element.children;
841
1163
  if (typeof children === "function") {
@@ -843,6 +1165,47 @@ function resolveShowChildren(element, value) {
843
1165
  }
844
1166
  return children;
845
1167
  }
1168
+ function resolveSwitchContent(element) {
1169
+ const props = element.props;
1170
+ const children = normalizeContent(props.children ?? element.children);
1171
+ for (const child of children) {
1172
+ const match = getMatchElement(child);
1173
+ if (!match) {
1174
+ continue;
1175
+ }
1176
+ const when = readReactive2(match.props.when);
1177
+ if (when) {
1178
+ return resolveMatchChildren(match, when);
1179
+ }
1180
+ }
1181
+ return props.fallback;
1182
+ }
1183
+ function resolveMatchChildren(element, value) {
1184
+ const children = element.props.children ?? element.children;
1185
+ if (typeof children === "function") {
1186
+ return children(value);
1187
+ }
1188
+ return children;
1189
+ }
1190
+ function resolveKeyChildren(element, value) {
1191
+ const children = element.props.children ?? element.children;
1192
+ if (typeof children === "function") {
1193
+ return children(value);
1194
+ }
1195
+ return children;
1196
+ }
1197
+ function createDynamicElement(element, tag) {
1198
+ if (typeof tag !== "string" && typeof tag !== "function") {
1199
+ return null;
1200
+ }
1201
+ const { component, ...props } = element.props;
1202
+ const children = normalizeContent(props.children ?? element.children);
1203
+ return {
1204
+ tag,
1205
+ props,
1206
+ children
1207
+ };
1208
+ }
846
1209
  function renderBlockContent(content, parent, anchor, namespace, owner) {
847
1210
  if (content == null || typeof content === "boolean") {
848
1211
  return [];
@@ -856,6 +1219,12 @@ function clearChildren(block) {
856
1219
  }
857
1220
  block.children = [];
858
1221
  }
1222
+ function clearPortalChildren(portal) {
1223
+ for (const child of portal.children) {
1224
+ removeMountedNode(child);
1225
+ }
1226
+ portal.children = [];
1227
+ }
859
1228
  function moveBeforeEnd(parent, mounted, endAnchor) {
860
1229
  for (const node of getMountedDomNodes(mounted)) {
861
1230
  domOps.insertBefore(parent, node, endAnchor);
@@ -870,9 +1239,43 @@ function fireMountedAndQueueUpdated(owner) {
870
1239
  function withOptionalInstance(owner, fn) {
871
1240
  return owner ? withInstance(owner, fn) : fn();
872
1241
  }
873
- function readReactive(value) {
1242
+ function readReactive2(value) {
874
1243
  return isSignal(value) || isComputed(value) ? value.value : value;
875
1244
  }
1245
+ function normalizeContent(content) {
1246
+ if (content == null || typeof content === "boolean") {
1247
+ return [];
1248
+ }
1249
+ return Array.isArray(content) ? content : [content];
1250
+ }
1251
+ function isElementLike(value) {
1252
+ return value != null && typeof value === "object" && "tag" in value;
1253
+ }
1254
+ function getMatchElement(value) {
1255
+ if (!isElementLike(value)) {
1256
+ return null;
1257
+ }
1258
+ if (isMatchElement(value)) {
1259
+ return value;
1260
+ }
1261
+ return value.tag === Match ? Match(value.props) : null;
1262
+ }
1263
+ function resolvePortalTarget(value) {
1264
+ const target = readReactive2(value);
1265
+ if (target == null) {
1266
+ return typeof document === "undefined" ? null : document.body;
1267
+ }
1268
+ if (typeof target === "string") {
1269
+ return document.querySelector(target);
1270
+ }
1271
+ if (typeof target === "function") {
1272
+ return target();
1273
+ }
1274
+ if (typeof target === "object" && "nodeType" in target) {
1275
+ return target;
1276
+ }
1277
+ return null;
1278
+ }
876
1279
  function insertNode(parent, child, anchor) {
877
1280
  if (anchor) {
878
1281
  domOps.insertBefore(parent, child, anchor);
@@ -905,10 +1308,13 @@ function renderElementToDOM(element, parent, anchor = null, namespace = null) {
905
1308
  if (tag === "" || tag === Fragment) {
906
1309
  return renderFragmentToDOM(children, parent, anchor, namespace);
907
1310
  }
908
- if (tag === Show || tag === For) {
1311
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1312
+ return renderElementToDOM(tag(props), parent, anchor, namespace);
1313
+ }
1314
+ if (tag === Visible) {
909
1315
  return renderElementToDOM(tag(props), parent, anchor, namespace);
910
1316
  }
911
- if (isShowElement(element) || isForElement(element)) {
1317
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element) || isPortalElement(element)) {
912
1318
  return renderControlFlowToDOM(element, parent, anchor, namespace);
913
1319
  }
914
1320
  if (typeof tag === "function") {
@@ -1221,6 +1627,37 @@ function isSafeHtml(value) {
1221
1627
  return value instanceof HtmlEscapedString;
1222
1628
  }
1223
1629
 
1630
+ // src/server/attribute-utils.ts
1631
+ var PROP_ALIASES2 = {
1632
+ className: "class",
1633
+ htmlFor: "for",
1634
+ tabIndex: "tabindex",
1635
+ crossOrigin: "crossorigin"
1636
+ };
1637
+ function renderServerAttribute(key, value) {
1638
+ const attrName = PROP_ALIASES2[key] ?? key;
1639
+ if (value == null || value === false) {
1640
+ return "";
1641
+ }
1642
+ if (value === true) {
1643
+ return ` ${attrName}`;
1644
+ }
1645
+ const attrValue = attrName === "class" && typeof value === "object" ? stringifyClass(value) : attrName === "style" && typeof value === "object" ? stringifyStyle(value) : String(value);
1646
+ return ` ${attrName}="${escapeHtml(attrValue)}"`;
1647
+ }
1648
+ function stringifyClass(value) {
1649
+ if (Array.isArray(value)) {
1650
+ return value.filter(Boolean).join(" ");
1651
+ }
1652
+ return Object.entries(value).filter(([, enabled]) => Boolean(enabled)).map(([name]) => name).join(" ");
1653
+ }
1654
+ function stringifyStyle(value) {
1655
+ return Object.entries(value).filter(([, val]) => val != null && val !== false).map(([prop, val]) => `${toKebabCase(prop)}:${String(val)}`).join(";");
1656
+ }
1657
+ function toKebabCase(value) {
1658
+ return value.includes("-") ? value : value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
1659
+ }
1660
+
1224
1661
  // src/server/renderer.ts
1225
1662
  var componentCache = new WeakMap;
1226
1663
  var pageRegistry = new Map;
@@ -1268,13 +1705,41 @@ async function renderToString(node) {
1268
1705
  }
1269
1706
  async function renderElement(element) {
1270
1707
  const { tag, props, children } = element;
1708
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1709
+ return renderElement(tag(props));
1710
+ }
1711
+ if (tag === Visible) {
1712
+ return renderElement(tag(props));
1713
+ }
1271
1714
  if (isShowElement(element)) {
1272
- const when = readReactive2(props.when);
1715
+ const when = readReactive3(props.when);
1273
1716
  return renderToString(when ? resolveShowChildren2(element, when) : props.fallback);
1274
1717
  }
1275
1718
  if (isForElement(element)) {
1276
1719
  return renderForElement(element);
1277
1720
  }
1721
+ if (isSwitchElement(element)) {
1722
+ return renderToString(resolveSwitchContent2(element));
1723
+ }
1724
+ if (isMatchElement(element)) {
1725
+ const when = readReactive3(props.when);
1726
+ return renderToString(when ? resolveMatchChildren2(element, when) : null);
1727
+ }
1728
+ if (isIndexElement(element)) {
1729
+ return renderIndexElement(element);
1730
+ }
1731
+ if (isKeyElement(element)) {
1732
+ const key = readReactive3(props.when);
1733
+ return renderToString(resolveKeyChildren2(element, key));
1734
+ }
1735
+ if (isDynamicElement(element)) {
1736
+ const tag2 = readReactive3(props.component);
1737
+ const dynamic = createDynamicElement2(element, tag2);
1738
+ return dynamic ? renderElement(dynamic) : "";
1739
+ }
1740
+ if (isPortalElement(element)) {
1741
+ return "";
1742
+ }
1278
1743
  if (typeof tag === "function") {
1279
1744
  const result = await tag(props);
1280
1745
  return renderToString(result);
@@ -1314,17 +1779,10 @@ function renderAttributes(props) {
1314
1779
  if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
1315
1780
  continue;
1316
1781
  }
1317
- const resolvedValue = readReactive2(value);
1782
+ const resolvedValue = readReactive3(value);
1318
1783
  if (resolvedValue == null || resolvedValue === false)
1319
1784
  continue;
1320
- const attrName = key === "className" ? "class" : key;
1321
- const finalName = attrName === "htmlFor" ? "for" : attrName;
1322
- if (resolvedValue === true) {
1323
- attrs += ` ${finalName}`;
1324
- continue;
1325
- }
1326
- const attrValue = escapeHtml(String(resolvedValue));
1327
- attrs += ` ${finalName}="${attrValue}"`;
1785
+ attrs += renderServerAttribute(key, resolvedValue);
1328
1786
  }
1329
1787
  return attrs;
1330
1788
  }
@@ -1338,14 +1796,70 @@ async function renderChildren(children, props) {
1338
1796
  function isSlots(children) {
1339
1797
  return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
1340
1798
  }
1341
- async function renderForElement(element) {
1342
- const props = element.props;
1343
- const each = readReactive2(props.each);
1344
- if (!Array.isArray(each) || typeof props.children !== "function") {
1345
- return "";
1799
+ async function renderForElement(element) {
1800
+ const props = element.props;
1801
+ const each = readReactive3(props.each);
1802
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1803
+ return props.fallback ? renderToString(props.fallback) : "";
1804
+ }
1805
+ if (each.length === 0) {
1806
+ return props.fallback ? renderToString(props.fallback) : "";
1807
+ }
1808
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
1809
+ return rendered.join("");
1810
+ }
1811
+ async function renderIndexElement(element) {
1812
+ const props = element.props;
1813
+ const each = readReactive3(props.each);
1814
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1815
+ return props.fallback ? renderToString(props.fallback) : "";
1816
+ }
1817
+ if (each.length === 0) {
1818
+ return props.fallback ? renderToString(props.fallback) : "";
1819
+ }
1820
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(() => item, index))));
1821
+ return rendered.join("");
1822
+ }
1823
+ function resolveSwitchContent2(element) {
1824
+ const props = element.props;
1825
+ const children = normalizeContent2(props.children ?? element.children);
1826
+ for (const child of children) {
1827
+ const match = getMatchElement2(child);
1828
+ if (!match) {
1829
+ continue;
1830
+ }
1831
+ const when = readReactive3(match.props.when);
1832
+ if (when) {
1833
+ return resolveMatchChildren2(match, when);
1834
+ }
1835
+ }
1836
+ return props.fallback;
1837
+ }
1838
+ function resolveMatchChildren2(element, value) {
1839
+ const children = element.props.children ?? element.children;
1840
+ if (typeof children === "function") {
1841
+ return children(value);
1842
+ }
1843
+ return children;
1844
+ }
1845
+ function resolveKeyChildren2(element, value) {
1846
+ const children = element.props.children ?? element.children;
1847
+ if (typeof children === "function") {
1848
+ return children(value);
1849
+ }
1850
+ return children;
1851
+ }
1852
+ function createDynamicElement2(element, tag) {
1853
+ if (typeof tag !== "string" && typeof tag !== "function") {
1854
+ return null;
1346
1855
  }
1347
- const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
1348
- return rendered.join("");
1856
+ const { component, ...props } = element.props;
1857
+ const children = normalizeContent2(props.children ?? element.children);
1858
+ return {
1859
+ tag,
1860
+ props,
1861
+ children
1862
+ };
1349
1863
  }
1350
1864
  function resolveShowChildren2(element, value) {
1351
1865
  const children = element.props.children ?? element.children;
@@ -1354,9 +1868,27 @@ function resolveShowChildren2(element, value) {
1354
1868
  }
1355
1869
  return children;
1356
1870
  }
1357
- function readReactive2(value) {
1871
+ function readReactive3(value) {
1358
1872
  return isSignal(value) || isComputed(value) ? value.value : value;
1359
1873
  }
1874
+ function normalizeContent2(content) {
1875
+ if (content == null || typeof content === "boolean") {
1876
+ return [];
1877
+ }
1878
+ return Array.isArray(content) ? content : [content];
1879
+ }
1880
+ function isElementLike2(value) {
1881
+ return value != null && typeof value === "object" && "tag" in value;
1882
+ }
1883
+ function getMatchElement2(value) {
1884
+ if (!isElementLike2(value)) {
1885
+ return null;
1886
+ }
1887
+ if (isMatchElement(value)) {
1888
+ return value;
1889
+ }
1890
+ return value.tag === Match ? Match(value.props) : null;
1891
+ }
1360
1892
  // src/hydration/markers.ts
1361
1893
  var COMP_ID_ATTR = "data-sinwan-id";
1362
1894
  var COMP_ID_PREFIX = "c";
@@ -1481,8 +2013,16 @@ async function streamNode(node, controller, encoder) {
1481
2013
  }
1482
2014
  async function streamElement(element, controller, encoder) {
1483
2015
  const { tag, props, children } = element;
2016
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2017
+ await streamElement(tag(props), controller, encoder);
2018
+ return;
2019
+ }
2020
+ if (tag === Visible) {
2021
+ await streamElement(tag(props), controller, encoder);
2022
+ return;
2023
+ }
1484
2024
  if (isShowElement(element)) {
1485
- const when = readReactive3(props.when);
2025
+ const when = readReactive4(props.when);
1486
2026
  await streamNode(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder);
1487
2027
  return;
1488
2028
  }
@@ -1490,6 +2030,35 @@ async function streamElement(element, controller, encoder) {
1490
2030
  await streamForElement(element, controller, encoder);
1491
2031
  return;
1492
2032
  }
2033
+ if (isSwitchElement(element)) {
2034
+ await streamNode(resolveSwitchContent3(element), controller, encoder);
2035
+ return;
2036
+ }
2037
+ if (isMatchElement(element)) {
2038
+ const when = readReactive4(props.when);
2039
+ await streamNode(when ? resolveMatchChildren3(element, when) : null, controller, encoder);
2040
+ return;
2041
+ }
2042
+ if (isIndexElement(element)) {
2043
+ await streamIndexElement(element, controller, encoder);
2044
+ return;
2045
+ }
2046
+ if (isKeyElement(element)) {
2047
+ const key = readReactive4(props.when);
2048
+ await streamNode(resolveKeyChildren3(element, key), controller, encoder);
2049
+ return;
2050
+ }
2051
+ if (isDynamicElement(element)) {
2052
+ const dynamicTag = readReactive4(props.component);
2053
+ const dynamic = createDynamicElement3(element, dynamicTag);
2054
+ if (dynamic) {
2055
+ await streamElement(dynamic, controller, encoder);
2056
+ }
2057
+ return;
2058
+ }
2059
+ if (isPortalElement(element)) {
2060
+ return;
2061
+ }
1493
2062
  if (typeof tag === "function") {
1494
2063
  const result = await tag(props);
1495
2064
  await streamNode(result, controller, encoder);
@@ -1524,16 +2093,10 @@ function renderAttributes2(props) {
1524
2093
  if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
1525
2094
  continue;
1526
2095
  }
1527
- const resolvedValue = readReactive3(value);
2096
+ const resolvedValue = readReactive4(value);
1528
2097
  if (resolvedValue == null || resolvedValue === false)
1529
2098
  continue;
1530
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1531
- if (resolvedValue === true) {
1532
- attrs += ` ${attrName}`;
1533
- continue;
1534
- }
1535
- const attrValue = escapeHtml(String(resolvedValue));
1536
- attrs += ` ${attrName}="${attrValue}"`;
2099
+ attrs += renderServerAttribute(key, resolvedValue);
1537
2100
  }
1538
2101
  return attrs;
1539
2102
  }
@@ -1578,12 +2141,16 @@ async function streamHydratableElement(element, controller, encoder, ctx, isComp
1578
2141
  }
1579
2142
  return;
1580
2143
  }
1581
- if (tag === Show || tag === For) {
2144
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2145
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
2146
+ return;
2147
+ }
2148
+ if (tag === Visible) {
1582
2149
  await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
1583
2150
  return;
1584
2151
  }
1585
2152
  if (isShowElement(element)) {
1586
- const when = readReactive3(props.when);
2153
+ const when = readReactive4(props.when);
1587
2154
  await streamHydratableNodeToController(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder, ctx, isComponentRoot);
1588
2155
  return;
1589
2156
  }
@@ -1591,6 +2158,35 @@ async function streamHydratableElement(element, controller, encoder, ctx, isComp
1591
2158
  await streamHydratableForElement(element, controller, encoder, ctx);
1592
2159
  return;
1593
2160
  }
2161
+ if (isSwitchElement(element)) {
2162
+ await streamHydratableNodeToController(resolveSwitchContent3(element), controller, encoder, ctx, isComponentRoot);
2163
+ return;
2164
+ }
2165
+ if (isMatchElement(element)) {
2166
+ const when = readReactive4(props.when);
2167
+ await streamHydratableNodeToController(when ? resolveMatchChildren3(element, when) : null, controller, encoder, ctx, isComponentRoot);
2168
+ return;
2169
+ }
2170
+ if (isIndexElement(element)) {
2171
+ await streamHydratableIndexElement(element, controller, encoder, ctx);
2172
+ return;
2173
+ }
2174
+ if (isKeyElement(element)) {
2175
+ const key = readReactive4(props.when);
2176
+ await streamHydratableNodeToController(resolveKeyChildren3(element, key), controller, encoder, ctx, isComponentRoot);
2177
+ return;
2178
+ }
2179
+ if (isDynamicElement(element)) {
2180
+ const dynamicTag = readReactive4(props.component);
2181
+ const dynamic = createDynamicElement3(element, dynamicTag);
2182
+ if (dynamic) {
2183
+ await streamHydratableElement(dynamic, controller, encoder, ctx, isComponentRoot);
2184
+ }
2185
+ return;
2186
+ }
2187
+ if (isPortalElement(element)) {
2188
+ return;
2189
+ }
1594
2190
  if (typeof tag === "function") {
1595
2191
  await streamHydratableComponent(tag, props, controller, encoder, ctx, true);
1596
2192
  return;
@@ -1633,14 +2229,42 @@ async function streamHydratableIntrinsic(tag, props, children, controller, encod
1633
2229
  }
1634
2230
  async function streamHydratableForElement(element, controller, encoder, ctx) {
1635
2231
  const props = element.props;
1636
- const each = readReactive3(props.each);
2232
+ const each = readReactive4(props.each);
1637
2233
  if (!Array.isArray(each) || typeof props.children !== "function") {
2234
+ if (props.fallback) {
2235
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2236
+ }
2237
+ return;
2238
+ }
2239
+ if (each.length === 0) {
2240
+ if (props.fallback) {
2241
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2242
+ }
1638
2243
  return;
1639
2244
  }
1640
2245
  for (let index = 0;index < each.length; index++) {
1641
2246
  await streamHydratableNodeToController(props.children(each[index], () => index), controller, encoder, ctx);
1642
2247
  }
1643
2248
  }
2249
+ async function streamHydratableIndexElement(element, controller, encoder, ctx) {
2250
+ const props = element.props;
2251
+ const each = readReactive4(props.each);
2252
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2253
+ if (props.fallback) {
2254
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2255
+ }
2256
+ return;
2257
+ }
2258
+ if (each.length === 0) {
2259
+ if (props.fallback) {
2260
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2261
+ }
2262
+ return;
2263
+ }
2264
+ for (let index = 0;index < each.length; index++) {
2265
+ await streamHydratableNodeToController(props.children(() => each[index], index), controller, encoder, ctx);
2266
+ }
2267
+ }
1644
2268
  function renderHydratableAttributes(props, ctx, isComponentRoot) {
1645
2269
  let attrs = "";
1646
2270
  if (isComponentRoot) {
@@ -1655,15 +2279,10 @@ function renderHydratableAttributes(props, ctx, isComponentRoot) {
1655
2279
  eventParts.push(`${toEventName(key)}:${ctx.eventIndex++}`);
1656
2280
  continue;
1657
2281
  }
1658
- const resolvedValue = readReactive3(value);
2282
+ const resolvedValue = readReactive4(value);
1659
2283
  if (resolvedValue == null || resolvedValue === false)
1660
2284
  continue;
1661
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1662
- if (resolvedValue === true) {
1663
- attrs += ` ${attrName}`;
1664
- continue;
1665
- }
1666
- attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
2285
+ attrs += renderServerAttribute(key, resolvedValue);
1667
2286
  }
1668
2287
  if (eventParts.length > 0) {
1669
2288
  attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
@@ -1675,14 +2294,42 @@ function enqueue(controller, encoder, html) {
1675
2294
  }
1676
2295
  async function streamForElement(element, controller, encoder) {
1677
2296
  const props = element.props;
1678
- const each = readReactive3(props.each);
2297
+ const each = readReactive4(props.each);
1679
2298
  if (!Array.isArray(each) || typeof props.children !== "function") {
2299
+ if (props.fallback) {
2300
+ await streamNode(props.fallback, controller, encoder);
2301
+ }
2302
+ return;
2303
+ }
2304
+ if (each.length === 0) {
2305
+ if (props.fallback) {
2306
+ await streamNode(props.fallback, controller, encoder);
2307
+ }
1680
2308
  return;
1681
2309
  }
1682
2310
  for (let index = 0;index < each.length; index++) {
1683
2311
  await streamNode(props.children(each[index], () => index), controller, encoder);
1684
2312
  }
1685
2313
  }
2314
+ async function streamIndexElement(element, controller, encoder) {
2315
+ const props = element.props;
2316
+ const each = readReactive4(props.each);
2317
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2318
+ if (props.fallback) {
2319
+ await streamNode(props.fallback, controller, encoder);
2320
+ }
2321
+ return;
2322
+ }
2323
+ if (each.length === 0) {
2324
+ if (props.fallback) {
2325
+ await streamNode(props.fallback, controller, encoder);
2326
+ }
2327
+ return;
2328
+ }
2329
+ for (let index = 0;index < each.length; index++) {
2330
+ await streamNode(props.children(() => each[index], index), controller, encoder);
2331
+ }
2332
+ }
1686
2333
  function resolveShowChildren3(element, value) {
1687
2334
  const children = element.props.children ?? element.children;
1688
2335
  if (typeof children === "function") {
@@ -1690,9 +2337,68 @@ function resolveShowChildren3(element, value) {
1690
2337
  }
1691
2338
  return children;
1692
2339
  }
1693
- function readReactive3(value) {
2340
+ function resolveSwitchContent3(element) {
2341
+ const props = element.props;
2342
+ const children = normalizeContent3(props.children ?? element.children);
2343
+ for (const child of children) {
2344
+ const match = getMatchElement3(child);
2345
+ if (!match) {
2346
+ continue;
2347
+ }
2348
+ const when = readReactive4(match.props.when);
2349
+ if (when) {
2350
+ return resolveMatchChildren3(match, when);
2351
+ }
2352
+ }
2353
+ return props.fallback;
2354
+ }
2355
+ function resolveMatchChildren3(element, value) {
2356
+ const children = element.props.children ?? element.children;
2357
+ if (typeof children === "function") {
2358
+ return children(value);
2359
+ }
2360
+ return children;
2361
+ }
2362
+ function resolveKeyChildren3(element, value) {
2363
+ const children = element.props.children ?? element.children;
2364
+ if (typeof children === "function") {
2365
+ return children(value);
2366
+ }
2367
+ return children;
2368
+ }
2369
+ function createDynamicElement3(element, tag) {
2370
+ if (typeof tag !== "string" && typeof tag !== "function") {
2371
+ return null;
2372
+ }
2373
+ const { component, ...props } = element.props;
2374
+ const children = normalizeContent3(props.children ?? element.children);
2375
+ return {
2376
+ tag,
2377
+ props,
2378
+ children
2379
+ };
2380
+ }
2381
+ function readReactive4(value) {
1694
2382
  return isSignal(value) || isComputed(value) ? value.value : value;
1695
2383
  }
2384
+ function normalizeContent3(content) {
2385
+ if (content == null || typeof content === "boolean") {
2386
+ return [];
2387
+ }
2388
+ return Array.isArray(content) ? content : [content];
2389
+ }
2390
+ function isElementLike3(value) {
2391
+ return value != null && typeof value === "object" && "tag" in value;
2392
+ }
2393
+ function getMatchElement3(value) {
2394
+ if (!isElementLike3(value)) {
2395
+ return null;
2396
+ }
2397
+ if (isMatchElement(value)) {
2398
+ return value;
2399
+ }
2400
+ return value.tag === Match ? Match(value.props) : null;
2401
+ }
1696
2402
  // src/server/hydration-markers.ts
1697
2403
  function createHydrationContext() {
1698
2404
  return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
@@ -1762,17 +2468,42 @@ function renderElementH(element, ctx, isComponentRoot) {
1762
2468
  if (tag === "") {
1763
2469
  return children.map((child) => renderNodeH(child, ctx)).join("");
1764
2470
  }
1765
- if (tag === Show || tag === For) {
2471
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2472
+ return renderElementH(tag(props), ctx, isComponentRoot);
2473
+ }
2474
+ if (tag === Visible) {
1766
2475
  return renderElementH(tag(props), ctx, isComponentRoot);
1767
2476
  }
1768
2477
  if (isShowElement(element)) {
1769
- const when = readReactive4(props.when);
2478
+ const when = readReactive5(props.when);
1770
2479
  const content = when ? resolveShowChildren4(element, when) : props.fallback;
1771
2480
  return renderNodeMaybeRoot(content, ctx, isComponentRoot);
1772
2481
  }
1773
2482
  if (isForElement(element)) {
1774
2483
  return renderForElementH(element, ctx);
1775
2484
  }
2485
+ if (isSwitchElement(element)) {
2486
+ return renderNodeMaybeRoot(resolveSwitchContent4(element), ctx, isComponentRoot);
2487
+ }
2488
+ if (isMatchElement(element)) {
2489
+ const when = readReactive5(props.when);
2490
+ return renderNodeMaybeRoot(when ? resolveMatchChildren4(element, when) : null, ctx, isComponentRoot);
2491
+ }
2492
+ if (isIndexElement(element)) {
2493
+ return renderIndexElementH(element, ctx);
2494
+ }
2495
+ if (isKeyElement(element)) {
2496
+ const key = readReactive5(props.when);
2497
+ return renderNodeMaybeRoot(resolveKeyChildren4(element, key), ctx, isComponentRoot);
2498
+ }
2499
+ if (isDynamicElement(element)) {
2500
+ const dynamicTag = readReactive5(props.component);
2501
+ const dynamic = createDynamicElement4(element, dynamicTag);
2502
+ return dynamic ? renderElementH(dynamic, ctx, isComponentRoot) : "";
2503
+ }
2504
+ if (isPortalElement(element)) {
2505
+ return "";
2506
+ }
1776
2507
  if (typeof tag === "function") {
1777
2508
  return renderComponentH(tag, props, ctx);
1778
2509
  }
@@ -1819,13 +2550,7 @@ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
1819
2550
  if (isSignal(value) || isComputed(value)) {
1820
2551
  resolvedValue = value.value;
1821
2552
  }
1822
- if (resolvedValue === true) {
1823
- const attrName2 = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1824
- attrs += ` ${attrName2}`;
1825
- continue;
1826
- }
1827
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1828
- attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
2553
+ attrs += renderServerAttribute(key, resolvedValue);
1829
2554
  }
1830
2555
  if (eventParts.length > 0) {
1831
2556
  attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
@@ -1848,12 +2573,26 @@ function renderNodeMaybeRoot(node, ctx, isComponentRoot) {
1848
2573
  }
1849
2574
  function renderForElementH(element, ctx) {
1850
2575
  const props = element.props;
1851
- const each = readReactive4(props.each);
2576
+ const each = readReactive5(props.each);
1852
2577
  if (!Array.isArray(each) || typeof props.children !== "function") {
1853
- return "";
2578
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2579
+ }
2580
+ if (each.length === 0) {
2581
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1854
2582
  }
1855
2583
  return each.map((item, index) => renderNodeH(props.children(item, () => index), ctx)).join("");
1856
2584
  }
2585
+ function renderIndexElementH(element, ctx) {
2586
+ const props = element.props;
2587
+ const each = readReactive5(props.each);
2588
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2589
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2590
+ }
2591
+ if (each.length === 0) {
2592
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2593
+ }
2594
+ return each.map((item, index) => renderNodeH(props.children(() => item, index), ctx)).join("");
2595
+ }
1857
2596
  function resolveShowChildren4(element, value) {
1858
2597
  const children = element.props.children ?? element.children;
1859
2598
  if (typeof children === "function") {
@@ -1861,9 +2600,68 @@ function resolveShowChildren4(element, value) {
1861
2600
  }
1862
2601
  return children;
1863
2602
  }
1864
- function readReactive4(value) {
2603
+ function resolveSwitchContent4(element) {
2604
+ const props = element.props;
2605
+ const children = normalizeContent4(props.children ?? element.children);
2606
+ for (const child of children) {
2607
+ const match = getMatchElement4(child);
2608
+ if (!match) {
2609
+ continue;
2610
+ }
2611
+ const when = readReactive5(match.props.when);
2612
+ if (when) {
2613
+ return resolveMatchChildren4(match, when);
2614
+ }
2615
+ }
2616
+ return props.fallback;
2617
+ }
2618
+ function resolveMatchChildren4(element, value) {
2619
+ const children = element.props.children ?? element.children;
2620
+ if (typeof children === "function") {
2621
+ return children(value);
2622
+ }
2623
+ return children;
2624
+ }
2625
+ function resolveKeyChildren4(element, value) {
2626
+ const children = element.props.children ?? element.children;
2627
+ if (typeof children === "function") {
2628
+ return children(value);
2629
+ }
2630
+ return children;
2631
+ }
2632
+ function createDynamicElement4(element, tag) {
2633
+ if (typeof tag !== "string" && typeof tag !== "function") {
2634
+ return null;
2635
+ }
2636
+ const { component, ...props } = element.props;
2637
+ const children = normalizeContent4(props.children ?? element.children);
2638
+ return {
2639
+ tag,
2640
+ props,
2641
+ children
2642
+ };
2643
+ }
2644
+ function readReactive5(value) {
1865
2645
  return isSignal(value) || isComputed(value) ? value.value : value;
1866
2646
  }
2647
+ function normalizeContent4(content) {
2648
+ if (content == null || typeof content === "boolean") {
2649
+ return [];
2650
+ }
2651
+ return Array.isArray(content) ? content : [content];
2652
+ }
2653
+ function isElementLike4(value) {
2654
+ return value != null && typeof value === "object" && "tag" in value;
2655
+ }
2656
+ function getMatchElement4(value) {
2657
+ if (!isElementLike4(value)) {
2658
+ return null;
2659
+ }
2660
+ if (isMatchElement(value)) {
2661
+ return value;
2662
+ }
2663
+ return value.tag === Match ? Match(value.props) : null;
2664
+ }
1867
2665
  // src/index.ts
1868
2666
  var exports_src = {};
1869
2667
  __export(exports_src, {
@@ -1910,25 +2708,19 @@ __export(exports_src, {
1910
2708
  createComponent: () => createComponent,
1911
2709
  computed: () => computed,
1912
2710
  batch: () => batch,
2711
+ Visible: () => Visible,
2712
+ Switch: () => Switch,
1913
2713
  Show: () => Show,
2714
+ Portal: () => Portal,
2715
+ Match: () => Match,
2716
+ Key: () => Key,
2717
+ Index: () => Index,
1914
2718
  HtmlEscapedString: () => HtmlEscapedString,
1915
2719
  Fragment: () => Fragment,
1916
- For: () => For
2720
+ For: () => For,
2721
+ Dynamic: () => Dynamic
1917
2722
  });
1918
2723
  module.exports = __toCommonJS(exports_src);
1919
- // src/reactivity/batch.ts
1920
- var batchDepth = 0;
1921
- function batch(fn) {
1922
- batchDepth++;
1923
- try {
1924
- fn();
1925
- } finally {
1926
- batchDepth--;
1927
- if (batchDepth === 0) {
1928
- flushSync();
1929
- }
1930
- }
1931
- }
1932
2724
  // src/component/lifecycle.ts
1933
2725
  function onMounted(fn) {
1934
2726
  const instance = getCurrentInstance();
@@ -2081,10 +2873,16 @@ function hydrateElement(element, cursor) {
2081
2873
  if (tag === "") {
2082
2874
  return hydrateArray(children, cursor);
2083
2875
  }
2084
- if (tag === Show || tag === For) {
2876
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2877
+ return hydrateElement(tag(props), cursor);
2878
+ }
2879
+ if (tag === Visible) {
2085
2880
  return hydrateElement(tag(props), cursor);
2086
2881
  }
2087
- if (isShowElement(element) || isForElement(element)) {
2882
+ if (isPortalElement(element)) {
2883
+ return renderControlFlowToDOM(element, cursor.parent, cursor.current, null);
2884
+ }
2885
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element)) {
2088
2886
  return hydrateControlFlow(element, cursor);
2089
2887
  }
2090
2888
  if (typeof tag === "function") {
@@ -2127,20 +2925,13 @@ function hydrateAttributes(el, props) {
2127
2925
  const disposers = [];
2128
2926
  const owner = getCurrentInstance();
2129
2927
  for (const [key, value] of Object.entries(props)) {
2130
- if (key === "children" || key === "key" || key === "ref" || isEventProp(key))
2928
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key))
2131
2929
  continue;
2132
2930
  if (isSignal(value) || isComputed(value)) {
2931
+ const state = { previousStyleProps: new Set };
2133
2932
  let initialized = false;
2134
2933
  const dispose = effect(() => {
2135
- const v = value.value;
2136
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
2137
- if (v == null || v === false) {
2138
- el.removeAttribute(attrName);
2139
- } else if (v === true) {
2140
- el.setAttribute(attrName, "");
2141
- } else {
2142
- el.setAttribute(attrName, String(v));
2143
- }
2934
+ setSingleAttribute(el, key, value.value, state);
2144
2935
  if (initialized) {
2145
2936
  queueUpdatedHooks(owner);
2146
2937
  }
@@ -2153,16 +2944,34 @@ function hydrateAttributes(el, props) {
2153
2944
  }
2154
2945
  function hydrateControlFlow(element, cursor) {
2155
2946
  if (isShowElement(element)) {
2156
- const when = readReactive5(element.props.when);
2947
+ const when = readReactive6(element.props.when);
2157
2948
  const content = when ? resolveShowChildren5(element, when) : element.props.fallback;
2158
2949
  return hydrateContent(content, cursor);
2159
2950
  }
2160
2951
  if (isForElement(element)) {
2161
2952
  const props = element.props;
2162
- const items = readReactive5(props.each);
2163
- const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(item, () => index)) : [];
2953
+ const items = readReactive6(props.each);
2954
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(item, () => index)) : props.fallback ? [props.fallback] : [];
2955
+ return hydrateArray(children, cursor);
2956
+ }
2957
+ if (isSwitchElement(element)) {
2958
+ return hydrateContent(resolveSwitchContent5(element), cursor);
2959
+ }
2960
+ if (isIndexElement(element)) {
2961
+ const props = element.props;
2962
+ const items = readReactive6(props.each);
2963
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(() => item, index)) : props.fallback ? [props.fallback] : [];
2164
2964
  return hydrateArray(children, cursor);
2165
2965
  }
2966
+ if (isKeyElement(element)) {
2967
+ const key = readReactive6(element.props.when);
2968
+ return hydrateContent(resolveKeyChildren5(element, key), cursor);
2969
+ }
2970
+ if (isDynamicElement(element)) {
2971
+ const tag = readReactive6(element.props.component);
2972
+ const dynamic = createDynamicElement5(element, tag);
2973
+ return dynamic ? hydrateElement(dynamic, cursor) : hydrateArray([], cursor);
2974
+ }
2166
2975
  return hydrateArray(element.children, cursor);
2167
2976
  }
2168
2977
  function hydrateContent(content, cursor) {
@@ -2178,9 +2987,68 @@ function resolveShowChildren5(element, value) {
2178
2987
  }
2179
2988
  return children;
2180
2989
  }
2181
- function readReactive5(value) {
2990
+ function resolveSwitchContent5(element) {
2991
+ const props = element.props;
2992
+ const children = normalizeContent5(props.children ?? element.children);
2993
+ for (const child of children) {
2994
+ const match = getMatchElement5(child);
2995
+ if (!match) {
2996
+ continue;
2997
+ }
2998
+ const when = readReactive6(match.props.when);
2999
+ if (when) {
3000
+ return resolveMatchChildren5(match, when);
3001
+ }
3002
+ }
3003
+ return props.fallback;
3004
+ }
3005
+ function resolveMatchChildren5(element, value) {
3006
+ const children = element.props.children ?? element.children;
3007
+ if (typeof children === "function") {
3008
+ return children(value);
3009
+ }
3010
+ return children;
3011
+ }
3012
+ function resolveKeyChildren5(element, value) {
3013
+ const children = element.props.children ?? element.children;
3014
+ if (typeof children === "function") {
3015
+ return children(value);
3016
+ }
3017
+ return children;
3018
+ }
3019
+ function createDynamicElement5(element, tag) {
3020
+ if (typeof tag !== "string" && typeof tag !== "function") {
3021
+ return null;
3022
+ }
3023
+ const { component, ...props } = element.props;
3024
+ const children = normalizeContent5(props.children ?? element.children);
3025
+ return {
3026
+ tag,
3027
+ props,
3028
+ children
3029
+ };
3030
+ }
3031
+ function readReactive6(value) {
2182
3032
  return isSignal(value) || isComputed(value) ? value.value : value;
2183
3033
  }
3034
+ function normalizeContent5(content) {
3035
+ if (content == null || typeof content === "boolean") {
3036
+ return [];
3037
+ }
3038
+ return Array.isArray(content) ? content : [content];
3039
+ }
3040
+ function isElementLike5(value) {
3041
+ return value != null && typeof value === "object" && "tag" in value;
3042
+ }
3043
+ function getMatchElement5(value) {
3044
+ if (!isElementLike5(value)) {
3045
+ return null;
3046
+ }
3047
+ if (isMatchElement(value)) {
3048
+ return value;
3049
+ }
3050
+ return value.tag === Match ? Match(value.props) : null;
3051
+ }
2184
3052
  function applyRef2(el, ref) {
2185
3053
  const value = ref;
2186
3054
  if (!value) {
@@ -2284,5 +3152,5 @@ function hydrate(component, container, props) {
2284
3152
  };
2285
3153
  }
2286
3154
 
2287
- //# debugId=82414CC0A24D81DC64756E2164756E21
3155
+ //# debugId=B2FFEB8D17EB811D64756E2164756E21
2288
3156
  //# sourceMappingURL=index.development.js.map