@fluixi/compiler 1.0.0-alpha.92 → 1.0.0-alpha.94

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 (102) hide show
  1. package/dist/analyze/intrinsics.cjs +31 -1
  2. package/dist/analyze/intrinsics.d.cts +14 -0
  3. package/dist/analyze/intrinsics.d.ts +14 -0
  4. package/dist/analyze/intrinsics.d.ts.map +1 -1
  5. package/dist/analyze/intrinsics.js +35 -0
  6. package/dist/analyze/intrinsics.mjs +31 -1
  7. package/dist/analyze/reactive-bindings.cjs +18 -0
  8. package/dist/analyze/reactive-bindings.mjs +18 -0
  9. package/dist/analyze/static-graph.cjs +22 -4
  10. package/dist/analyze/static-graph.d.ts.map +1 -1
  11. package/dist/analyze/static-graph.js +6 -4
  12. package/dist/analyze/static-graph.mjs +22 -4
  13. package/dist/{babel-GI375YZ2.mjs → babel-RJFQVFJW.mjs} +4 -4
  14. package/dist/{chunk-QZ4CJPYP.mjs → chunk-DP2QDWWH.mjs} +1 -1
  15. package/dist/{chunk-DWNWN5RH.mjs → chunk-E2RWTIYE.mjs} +21 -15
  16. package/dist/{chunk-XJ5H2MXY.mjs → chunk-HCCBEJEZ.mjs} +31 -1
  17. package/dist/{chunk-VOUI6XPV.mjs → chunk-HIZU7WI2.mjs} +1 -1
  18. package/dist/{chunk-VC6X44FS.mjs → chunk-ZR2QHTEX.mjs} +505 -68
  19. package/dist/codegen/backends/imperative.cjs +24 -6
  20. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  21. package/dist/codegen/backends/imperative.js +20 -4
  22. package/dist/codegen/backends/imperative.mjs +24 -6
  23. package/dist/frontend/babel/build-ir-lit.cjs +470 -63
  24. package/dist/frontend/babel/build-ir-lit.mjs +470 -63
  25. package/dist/frontend/babel/build-ir.cjs +470 -63
  26. package/dist/frontend/babel/build-ir.mjs +470 -63
  27. package/dist/frontend/babel/index.cjs +471 -64
  28. package/dist/frontend/babel/index.mjs +471 -64
  29. package/dist/frontend/babel/lower-template.cjs +470 -63
  30. package/dist/frontend/babel/lower-template.mjs +470 -63
  31. package/dist/frontend/babel/plugin.cjs +470 -63
  32. package/dist/frontend/babel/plugin.mjs +470 -63
  33. package/dist/index.cjs +360 -58
  34. package/dist/index.mjs +372 -58
  35. package/dist/integrations.cjs +1347 -98
  36. package/dist/integrations.d.ts.map +1 -1
  37. package/dist/integrations.js +44 -2
  38. package/dist/integrations.mjs +205 -19
  39. package/dist/lower/compile-template.cjs +354 -57
  40. package/dist/lower/compile-template.d.cts +13 -0
  41. package/dist/lower/compile-template.d.ts +13 -0
  42. package/dist/lower/compile-template.d.ts.map +1 -1
  43. package/dist/lower/compile-template.js +3 -0
  44. package/dist/lower/compile-template.mjs +366 -57
  45. package/dist/lower/entities.cjs +288 -0
  46. package/dist/lower/entities.d.cts +1 -0
  47. package/dist/lower/entities.d.ts +2 -0
  48. package/dist/lower/entities.d.ts.map +1 -0
  49. package/dist/lower/entities.js +54 -0
  50. package/dist/lower/entities.mjs +267 -0
  51. package/dist/lower/jsx.cjs +567 -7
  52. package/dist/lower/jsx.d.cts +8 -0
  53. package/dist/lower/jsx.d.ts +8 -0
  54. package/dist/lower/jsx.d.ts.map +1 -1
  55. package/dist/lower/jsx.js +205 -7
  56. package/dist/lower/jsx.mjs +567 -7
  57. package/dist/lower/template.cjs +332 -56
  58. package/dist/lower/template.d.ts.map +1 -1
  59. package/dist/lower/template.js +57 -49
  60. package/dist/lower/template.mjs +332 -56
  61. package/dist/resolve/builtins.cjs +1 -1
  62. package/dist/resolve/builtins.mjs +1 -1
  63. package/dist/resolve/component-globals.cjs +20 -1
  64. package/dist/resolve/component-globals.js +2 -2
  65. package/dist/resolve/component-globals.mjs +20 -1
  66. package/dist/resolve/write-globals.cjs +20 -1
  67. package/dist/resolve/write-globals.mjs +20 -1
  68. package/dist/{server-fns-BBZRZUPP.mjs → server-fns-JLSTKWPS.mjs} +4 -4
  69. package/dist/{server-functions-VEGLIFCE.mjs → server-functions-BGY3RD4R.mjs} +3 -3
  70. package/dist/transform/index.cjs +1123 -77
  71. package/dist/transform/index.mjs +1141 -91
  72. package/dist/transform/intrinsics.cjs +18 -0
  73. package/dist/transform/intrinsics.mjs +18 -0
  74. package/dist/transform/props.mjs +19 -14
  75. package/dist/transform/server-fns.mjs +19 -14
  76. package/dist/transform/source-locations.cjs +64 -3
  77. package/dist/transform/source-locations.d.cts +7 -2
  78. package/dist/transform/source-locations.d.ts +7 -2
  79. package/dist/transform/source-locations.d.ts.map +1 -1
  80. package/dist/transform/source-locations.js +68 -3
  81. package/dist/transform/source-locations.mjs +64 -3
  82. package/dist/transform/styles.cjs +588 -0
  83. package/dist/transform/styles.d.cts +211 -0
  84. package/dist/transform/styles.d.ts +212 -0
  85. package/dist/transform/styles.d.ts.map +1 -0
  86. package/dist/transform/styles.js +714 -0
  87. package/dist/transform/styles.mjs +653 -0
  88. package/dist/transform/templates.cjs +1122 -76
  89. package/dist/transform/templates.d.cts +13 -0
  90. package/dist/transform/templates.d.ts +13 -0
  91. package/dist/transform/templates.d.ts.map +1 -1
  92. package/dist/transform/templates.js +51 -14
  93. package/dist/transform/templates.mjs +1140 -90
  94. package/dist/{transform-UWZ7ZGJ2.mjs → transform-GBP6Y4UI.mjs} +603 -19
  95. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  96. package/dist/vite-styles.cjs +180 -0
  97. package/dist/vite-styles.d.cts +59 -0
  98. package/dist/vite-styles.d.ts +60 -0
  99. package/dist/vite-styles.d.ts.map +1 -0
  100. package/dist/vite-styles.js +198 -0
  101. package/dist/vite-styles.mjs +159 -0
  102. package/package.json +10 -3
@@ -1,4 +1,36 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
+
3
+ // ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.6.0/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
4
+ var comma = ",".charCodeAt(0);
5
+ var semicolon = ";".charCodeAt(0);
6
+ var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7
+ var intToChar = new Uint8Array(64);
8
+ var charToInt = new Uint8Array(128);
9
+ for (let i = 0; i < chars.length; i++) {
10
+ const c = chars.charCodeAt(i);
11
+ intToChar[i] = c;
12
+ charToInt[c] = i;
13
+ }
14
+ var bufLength = 1024 * 16;
15
+
16
+ // src/transform/styles.ts
17
+ var SCOPE_ATTR = "data-fx-s";
18
+ function applyTemplateStyles(ir, t) {
19
+ const walk2 = (node) => {
20
+ const children = node.children;
21
+ if (children) {
22
+ for (let i = children.length - 1; i >= 0; i--) {
23
+ const child = children[i];
24
+ if (child.kind === "element" && child.tag === "style" && t.owner) children.splice(i, 1);
25
+ else walk2(child);
26
+ }
27
+ }
28
+ if (t.scope && node.kind === "element" && node.tag !== "style" && node.props && !node.props.some((p) => p.name === SCOPE_ATTR)) {
29
+ node.props.unshift({ name: SCOPE_ATTR, kind: "attr", literal: t.scope });
30
+ }
31
+ };
32
+ walk2(ir);
33
+ }
2
34
 
3
35
  // src/optimize/analyze-static.ts
4
36
  function propReason(prop) {
@@ -442,6 +474,7 @@ var INTRINSICS = {
442
474
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
443
475
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
444
476
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
477
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
445
478
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
446
479
  // name. Still worth having: no import to write, and when a shorter form is
447
480
  // designed, the change is this line rather than a compiler pass.
@@ -452,6 +485,19 @@ var INTRINSICS = {
452
485
  // dependency analysis must not guess at.
453
486
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
454
487
  $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
488
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
489
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
490
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
491
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
492
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
493
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
494
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
495
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
496
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
497
+ // handle as far as reads go: the same accessor with `set` on it.
498
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
499
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
500
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
455
501
  // An environment variable, public or server-only; the browser build refuses a secret.
456
502
  $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
457
503
  };
@@ -629,13 +675,16 @@ function emitComponent(name, props, children, used, templates, at) {
629
675
  used.add("createComponent");
630
676
  const spreads = props.filter((p) => p.kind === "spread");
631
677
  const normal = props.filter((p) => p.kind !== "spread");
632
- const entries = normal.map(
633
- (p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
634
- );
678
+ const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
635
679
  if (children.length > 0) {
636
- entries.push(`get children() { return ${emitChildren(children, used, templates)}; }`);
680
+ bodies.push(["children", emitChildren(children, used, templates)]);
681
+ }
682
+ let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
683
+ if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
684
+ const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => (${body})`);
685
+ const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
686
+ obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
637
687
  }
638
- let obj = `{ ${entries.join(", ")} }`;
639
688
  if (spreads.length > 0) {
640
689
  used.add("mergeProps");
641
690
  obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
@@ -717,7 +766,8 @@ function emitNode(node, used, templates) {
717
766
  } else {
718
767
  used.add("spread");
719
768
  const svgFlag = node.svg ? ", isSVG: true" : "";
720
- const customFlag = node.tag.includes("-") ? ", isCustomElement: true" : "";
769
+ const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
770
+ const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
721
771
  parts.push(
722
772
  `spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
723
773
  );
@@ -832,6 +882,271 @@ function cleanTemplateText(value) {
832
882
  return out;
833
883
  }
834
884
 
885
+ // src/lower/entities.ts
886
+ var NAMED = {
887
+ quot: 34,
888
+ amp: 38,
889
+ apos: 39,
890
+ lt: 60,
891
+ gt: 62,
892
+ nbsp: 160,
893
+ iexcl: 161,
894
+ cent: 162,
895
+ pound: 163,
896
+ curren: 164,
897
+ yen: 165,
898
+ brvbar: 166,
899
+ sect: 167,
900
+ uml: 168,
901
+ copy: 169,
902
+ ordf: 170,
903
+ laquo: 171,
904
+ not: 172,
905
+ shy: 173,
906
+ reg: 174,
907
+ macr: 175,
908
+ deg: 176,
909
+ plusmn: 177,
910
+ sup2: 178,
911
+ sup3: 179,
912
+ acute: 180,
913
+ micro: 181,
914
+ para: 182,
915
+ middot: 183,
916
+ cedil: 184,
917
+ sup1: 185,
918
+ ordm: 186,
919
+ raquo: 187,
920
+ frac14: 188,
921
+ frac12: 189,
922
+ frac34: 190,
923
+ iquest: 191,
924
+ Agrave: 192,
925
+ Aacute: 193,
926
+ Acirc: 194,
927
+ Atilde: 195,
928
+ Auml: 196,
929
+ Aring: 197,
930
+ AElig: 198,
931
+ Ccedil: 199,
932
+ Egrave: 200,
933
+ Eacute: 201,
934
+ Ecirc: 202,
935
+ Euml: 203,
936
+ Igrave: 204,
937
+ Iacute: 205,
938
+ Icirc: 206,
939
+ Iuml: 207,
940
+ ETH: 208,
941
+ Ntilde: 209,
942
+ Ograve: 210,
943
+ Oacute: 211,
944
+ Ocirc: 212,
945
+ Otilde: 213,
946
+ Ouml: 214,
947
+ times: 215,
948
+ Oslash: 216,
949
+ Ugrave: 217,
950
+ Uacute: 218,
951
+ Ucirc: 219,
952
+ Uuml: 220,
953
+ Yacute: 221,
954
+ THORN: 222,
955
+ szlig: 223,
956
+ agrave: 224,
957
+ aacute: 225,
958
+ acirc: 226,
959
+ atilde: 227,
960
+ auml: 228,
961
+ aring: 229,
962
+ aelig: 230,
963
+ ccedil: 231,
964
+ egrave: 232,
965
+ eacute: 233,
966
+ ecirc: 234,
967
+ euml: 235,
968
+ igrave: 236,
969
+ iacute: 237,
970
+ icirc: 238,
971
+ iuml: 239,
972
+ eth: 240,
973
+ ntilde: 241,
974
+ ograve: 242,
975
+ oacute: 243,
976
+ ocirc: 244,
977
+ otilde: 245,
978
+ ouml: 246,
979
+ divide: 247,
980
+ oslash: 248,
981
+ ugrave: 249,
982
+ uacute: 250,
983
+ ucirc: 251,
984
+ uuml: 252,
985
+ yacute: 253,
986
+ thorn: 254,
987
+ yuml: 255,
988
+ OElig: 338,
989
+ oelig: 339,
990
+ Scaron: 352,
991
+ scaron: 353,
992
+ Yuml: 376,
993
+ fnof: 402,
994
+ circ: 710,
995
+ tilde: 732,
996
+ Alpha: 913,
997
+ Beta: 914,
998
+ Gamma: 915,
999
+ Delta: 916,
1000
+ Epsilon: 917,
1001
+ Zeta: 918,
1002
+ Eta: 919,
1003
+ Theta: 920,
1004
+ Iota: 921,
1005
+ Kappa: 922,
1006
+ Lambda: 923,
1007
+ Mu: 924,
1008
+ Nu: 925,
1009
+ Xi: 926,
1010
+ Omicron: 927,
1011
+ Pi: 928,
1012
+ Rho: 929,
1013
+ Sigma: 931,
1014
+ Tau: 932,
1015
+ Upsilon: 933,
1016
+ Phi: 934,
1017
+ Chi: 935,
1018
+ Psi: 936,
1019
+ Omega: 937,
1020
+ alpha: 945,
1021
+ beta: 946,
1022
+ gamma: 947,
1023
+ delta: 948,
1024
+ epsilon: 949,
1025
+ zeta: 950,
1026
+ eta: 951,
1027
+ theta: 952,
1028
+ iota: 953,
1029
+ kappa: 954,
1030
+ lambda: 955,
1031
+ mu: 956,
1032
+ nu: 957,
1033
+ xi: 958,
1034
+ omicron: 959,
1035
+ pi: 960,
1036
+ rho: 961,
1037
+ sigmaf: 962,
1038
+ sigma: 963,
1039
+ tau: 964,
1040
+ upsilon: 965,
1041
+ phi: 966,
1042
+ chi: 967,
1043
+ psi: 968,
1044
+ omega: 969,
1045
+ thetasym: 977,
1046
+ upsih: 978,
1047
+ piv: 982,
1048
+ ensp: 8194,
1049
+ emsp: 8195,
1050
+ thinsp: 8201,
1051
+ zwnj: 8204,
1052
+ zwj: 8205,
1053
+ lrm: 8206,
1054
+ rlm: 8207,
1055
+ ndash: 8211,
1056
+ mdash: 8212,
1057
+ lsquo: 8216,
1058
+ rsquo: 8217,
1059
+ sbquo: 8218,
1060
+ ldquo: 8220,
1061
+ rdquo: 8221,
1062
+ bdquo: 8222,
1063
+ dagger: 8224,
1064
+ Dagger: 8225,
1065
+ bull: 8226,
1066
+ hellip: 8230,
1067
+ permil: 8240,
1068
+ prime: 8242,
1069
+ Prime: 8243,
1070
+ lsaquo: 8249,
1071
+ rsaquo: 8250,
1072
+ oline: 8254,
1073
+ frasl: 8260,
1074
+ euro: 8364,
1075
+ image: 8465,
1076
+ weierp: 8472,
1077
+ real: 8476,
1078
+ trade: 8482,
1079
+ alefsym: 8501,
1080
+ larr: 8592,
1081
+ uarr: 8593,
1082
+ rarr: 8594,
1083
+ darr: 8595,
1084
+ harr: 8596,
1085
+ crarr: 8629,
1086
+ lArr: 8656,
1087
+ uArr: 8657,
1088
+ rArr: 8658,
1089
+ dArr: 8659,
1090
+ hArr: 8660,
1091
+ forall: 8704,
1092
+ part: 8706,
1093
+ exist: 8707,
1094
+ empty: 8709,
1095
+ nabla: 8711,
1096
+ isin: 8712,
1097
+ notin: 8713,
1098
+ ni: 8715,
1099
+ prod: 8719,
1100
+ sum: 8721,
1101
+ minus: 8722,
1102
+ lowast: 8727,
1103
+ radic: 8730,
1104
+ prop: 8733,
1105
+ infin: 8734,
1106
+ ang: 8736,
1107
+ and: 8743,
1108
+ or: 8744,
1109
+ cap: 8745,
1110
+ cup: 8746,
1111
+ int: 8747,
1112
+ there4: 8756,
1113
+ sim: 8764,
1114
+ cong: 8773,
1115
+ asymp: 8776,
1116
+ ne: 8800,
1117
+ equiv: 8801,
1118
+ le: 8804,
1119
+ ge: 8805,
1120
+ sub: 8834,
1121
+ sup: 8835,
1122
+ nsub: 8836,
1123
+ sube: 8838,
1124
+ supe: 8839,
1125
+ oplus: 8853,
1126
+ otimes: 8855,
1127
+ perp: 8869,
1128
+ sdot: 8901,
1129
+ lceil: 8968,
1130
+ rceil: 8969,
1131
+ lfloor: 8970,
1132
+ rfloor: 8971,
1133
+ lang: 9001,
1134
+ rang: 9002,
1135
+ loz: 9674,
1136
+ spades: 9824,
1137
+ clubs: 9827,
1138
+ hearts: 9829,
1139
+ diams: 9830
1140
+ };
1141
+ var REFERENCE = /&(?:#[xX]([0-9a-fA-F]{1,6})|#([0-9]{1,7})|([a-zA-Z][a-zA-Z0-9]{1,31}));/g;
1142
+ function decodeEntities(value) {
1143
+ if (!value.includes("&")) return value;
1144
+ return value.replace(REFERENCE, (match, hex, dec, name) => {
1145
+ const code = hex ? parseInt(hex, 16) : dec ? parseInt(dec, 10) : Object.prototype.hasOwnProperty.call(NAMED, name) ? NAMED[name] : void 0;
1146
+ return code !== void 0 && code <= 1114111 ? String.fromCodePoint(code) : match;
1147
+ });
1148
+ }
1149
+
835
1150
  // src/lower/template.ts
836
1151
  var DELEGATED = /* @__PURE__ */ new Set([
837
1152
  "click",
@@ -850,6 +1165,7 @@ var DELEGATED = /* @__PURE__ */ new Set([
850
1165
  function escapeTemplate(s) {
851
1166
  return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
852
1167
  }
1168
+ var CONTAINER = "container";
853
1169
  function capitalize(s) {
854
1170
  return s.charAt(0).toUpperCase() + s.slice(1);
855
1171
  }
@@ -904,10 +1220,6 @@ var Lowerer = class {
904
1220
  if (hasElse) i = elseIdx;
905
1221
  continue;
906
1222
  }
907
- if (child.attributes.some((a) => a.kind === "EachDirective")) {
908
- out.push(this.lowerEach(child));
909
- continue;
910
- }
911
1223
  }
912
1224
  const node = this.lowerNode(child);
913
1225
  if (node) out.push(node);
@@ -921,7 +1233,7 @@ var Lowerer = class {
921
1233
  switch (node.kind) {
922
1234
  case "Text": {
923
1235
  if (node.raw) return { kind: "text", value: node.value };
924
- const cleaned = cleanTemplateText(node.value);
1236
+ const cleaned = decodeEntities(cleanTemplateText(node.value));
925
1237
  return cleaned ? { kind: "text", value: cleaned } : null;
926
1238
  }
927
1239
  case "Comment":
@@ -949,13 +1261,16 @@ var Lowerer = class {
949
1261
  node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
950
1262
  return node;
951
1263
  }
1264
+ const each = this.lowerEach(el);
1265
+ const children = each ? [each] : this.lowerChildren(el.children);
1266
+ if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
952
1267
  const at = this.tagAt(el);
953
1268
  return {
954
1269
  kind: "element",
955
1270
  tag: el.tag,
956
1271
  svg: el.namespace === "svg",
957
- props: this.lowerAttributes(el.attributes),
958
- children: this.lowerChildren(el.children),
1272
+ props: this.lowerAttributes(el.attributes, true),
1273
+ children,
959
1274
  static: false,
960
1275
  ...at ? { at } : {}
961
1276
  };
@@ -1027,10 +1342,14 @@ var Lowerer = class {
1027
1342
  const at = this.tagAt(el);
1028
1343
  return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
1029
1344
  }
1030
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
1345
+ /**
1346
+ * `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
1347
+ * content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
1348
+ * it is. Null when the element has no `each`.
1349
+ */
1031
1350
  lowerEach(el) {
1032
1351
  const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
1033
- if (!eachDir || eachDir.kind !== "EachDirective") return this.lowerNode(el);
1352
+ if (!eachDir || eachDir.kind !== "EachDirective") return null;
1034
1353
  const each = this.hole(eachDir.hole);
1035
1354
  const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
1036
1355
  if (eachDir.key) {
@@ -1040,12 +1359,12 @@ var Lowerer = class {
1040
1359
  const arrow = this.itemArrow(el);
1041
1360
  let childrenCode;
1042
1361
  if (arrow) {
1043
- const bodyIR = { kind: "expr", code: arrow.body, reactive: arrow.bodyReactive };
1044
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
1045
- childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
1362
+ const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
1363
+ childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
1046
1364
  } else {
1047
- const repeated = this.stripAndLower(el, (a) => a.kind === "EachDirective");
1048
- childrenCode = `() => ${paren(this.emit(repeated), "arrowBody")}`;
1365
+ const content = this.lowerChildren(el.children);
1366
+ const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
1367
+ childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
1049
1368
  }
1050
1369
  const children = [{ kind: "expr", code: childrenCode, reactive: false }];
1051
1370
  const at = this.tagAt(el);
@@ -1062,33 +1381,23 @@ var Lowerer = class {
1062
1381
  const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
1063
1382
  return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
1064
1383
  }
1065
- /** Same element (minus each/key) but with explicit IR children. */
1066
- rebuildWithChildren(el, children) {
1067
- const props = this.lowerAttributes(
1068
- el.attributes.filter((a) => a.kind !== "EachDirective")
1069
- );
1070
- if (el.kind === "Element") {
1071
- const at = this.tagAt(el);
1072
- return {
1073
- kind: "element",
1074
- tag: el.tag,
1075
- svg: el.namespace === "svg",
1076
- props,
1077
- children,
1078
- static: false,
1079
- ...at ? { at } : {}
1080
- };
1081
- }
1082
- return { kind: "component", name: el.tag, props, children };
1083
- }
1084
1384
  // --- attributes ---------------------------------------------------------
1085
- lowerAttributes(attrs) {
1385
+ /**
1386
+ * `element`: a DOM element, where each class:/style: value that moves is its own accessor.
1387
+ * A component gets the object as before, rebuilt whole when any value moves.
1388
+ */
1389
+ lowerAttributes(attrs, element = false) {
1390
+ let anyReactive = false;
1391
+ const entry = (name, h) => {
1392
+ anyReactive ||= h.reactive;
1393
+ if (!element || !h.reactive) return `${JSON.stringify(name)}: ${h.code}`;
1394
+ const accessor = `() => ${paren(h.code, "arrowBody")}`;
1395
+ return `${JSON.stringify(name)}: ${h.at ? markHole(accessor, h.at.line, h.at.column) : accessor}`;
1396
+ };
1086
1397
  const props = [];
1087
1398
  const classEntries = [];
1088
- let classReactive = false;
1089
1399
  let classAt;
1090
1400
  const styleEntries = [];
1091
- let styleReactive = false;
1092
1401
  let styleAt;
1093
1402
  const usePairs = [];
1094
1403
  for (const a of attrs) {
@@ -1128,15 +1437,13 @@ var Lowerer = class {
1128
1437
  break;
1129
1438
  case "ClassDirective": {
1130
1439
  const h = this.hole(a.hole);
1131
- classEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1132
- classReactive = classReactive || h.reactive;
1440
+ classEntries.push(entry(a.name, h));
1133
1441
  classAt ??= h.at;
1134
1442
  break;
1135
1443
  }
1136
1444
  case "StyleDirective": {
1137
1445
  const h = this.hole(a.hole);
1138
- styleEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1139
- styleReactive = styleReactive || h.reactive;
1446
+ styleEntries.push(entry(a.name, h));
1140
1447
  styleAt ??= h.at;
1141
1448
  break;
1142
1449
  }
@@ -1156,18 +1463,19 @@ var Lowerer = class {
1156
1463
  name: "classList",
1157
1464
  kind: "attr",
1158
1465
  expr: `{ ${classEntries.join(", ")} }`,
1159
- reactive: classReactive,
1466
+ reactive: !element && anyReactive,
1160
1467
  ...classAt ? { at: classAt } : {}
1161
1468
  });
1162
1469
  }
1163
1470
  if (styleEntries.length > 0) {
1164
- props.push({
1165
- name: "style",
1166
- kind: "attr",
1167
- expr: `{ ${styleEntries.join(", ")} }`,
1168
- reactive: styleReactive,
1169
- ...styleAt ? { at: styleAt } : {}
1170
- });
1471
+ const entries = `{ ${styleEntries.join(", ")} }`;
1472
+ const base = props.findIndex((p) => p.name === "style");
1473
+ if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: !element && anyReactive, ...styleAt ? { at: styleAt } : {} });
1474
+ else {
1475
+ const prop = props[base];
1476
+ const value = prop.expr === void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
1477
+ props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
1478
+ }
1171
1479
  }
1172
1480
  if (usePairs.length > 0) {
1173
1481
  props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
@@ -1256,7 +1564,7 @@ var Lowerer = class {
1256
1564
  return base;
1257
1565
  }
1258
1566
  if (v.kind === "static") {
1259
- base.literal = v.value;
1567
+ base.literal = decodeEntities(v.value);
1260
1568
  return base;
1261
1569
  }
1262
1570
  if (v.kind === "hole") {
@@ -1269,7 +1577,7 @@ var Lowerer = class {
1269
1577
  let reactive = false;
1270
1578
  let at;
1271
1579
  const body = v.parts.map((p) => {
1272
- if ("text" in p) return escapeTemplate(p.text);
1580
+ if ("text" in p) return escapeTemplate(decodeEntities(p.text));
1273
1581
  const h = this.hole(p.hole);
1274
1582
  reactive = reactive || h.reactive;
1275
1583
  at ??= h.at;
@@ -1316,6 +1624,7 @@ function compilePieces(pieces, holes, options = {}) {
1316
1624
  ...options.sourceFile ? { sourceFile: options.sourceFile } : {},
1317
1625
  ...options.positionAt ? { positionAt: options.positionAt } : {}
1318
1626
  });
1627
+ if (options.templateStyles) applyTemplateStyles(ir, options.templateStyles);
1319
1628
  analyzeStatic(ir);
1320
1629
  resolveComponentSources(ir, {
1321
1630
  resolver: createComponentResolver(options.resolve ?? []),