xote 7.1.0-beta.1 → 7.1.0-beta.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xote",
3
- "version": "7.1.0-beta.1",
3
+ "version": "7.1.0-beta.2",
4
4
  "repository": {
5
5
  "url": "https://github.com/brnrdog/xote"
6
6
  },
package/ppx/README.md CHANGED
@@ -89,6 +89,7 @@ Applied recursively to the component's returned JSX:
89
89
  | `<View.Text/Int/Float/Bool>` child | yes | thunked → reactive text node (leaf) |
90
90
  | `<View.Text/…>` child | no | left as-is (static text) |
91
91
  | Element / nested JSX | — | recurse into attributes and children |
92
+ | Fragment (`<>…</>`) | — | recurse into each child independently (so nested reactive regions stay separate — not collapsed into one thunk) |
92
93
  | Bare child, control flow (`if`/`switch` selecting different nodes) | yes | branches decomposed fine-grained, then wrapped in `View.tracked` — see below |
93
94
  | Bare child, otherwise (`{Signal.get(x)}`, `{"lit"}`, `{someNode}`) | — | wrapped in `View.child` — see [Bare value children](#bare-value-children) |
94
95
 
@@ -271,7 +272,7 @@ Or step by step from `example/`:
271
272
  sh setup.sh # link toolchain + Xote from the repo root (idempotent)
272
273
  sh ../build.sh # build the ppx
273
274
  npm run build # compile Demo.res through the ppx
274
- npm run verify # jsdom runtime check (52 assertions)
275
+ npm run verify # jsdom runtime check (60 assertions)
275
276
  ```
276
277
 
277
278
  ## Known limitations (it's a prototype)
package/ppx/ppx.ml CHANGED
@@ -1117,6 +1117,14 @@ let jsx_parts (e : expression) =
1117
1117
  | Pexp_apply (f, args) when has_jsx e -> Some (f, args)
1118
1118
  | _ -> None
1119
1119
 
1120
+ (* A JSX fragment `<>…</>` is a `::`/`[]` list carrying the JSX attribute (not a
1121
+ Pexp_apply, so jsx_parts misses it). Its children are node position. *)
1122
+ let is_jsx_fragment (e : expression) : bool =
1123
+ has_jsx e
1124
+ && (match e.pexp_desc with
1125
+ | Pexp_construct ({ txt = Longident.Lident ("::" | "[]"); _ }, _) -> true
1126
+ | _ -> false)
1127
+
1120
1128
  (* Lowercase leading char => intrinsic HTML/SVG element (children are nodes). *)
1121
1129
  let is_element (f : expression) : bool =
1122
1130
  match f.pexp_desc with
@@ -1151,6 +1159,15 @@ let rec fine_node (env : env) (e : expression) : expression =
1151
1159
  | Some (f, args) ->
1152
1160
  (* element or user component: attrs are value position, children nodes *)
1153
1161
  { e with pexp_desc = Pexp_apply (f, List.map (element_arg env) args) }
1162
+ | None when is_jsx_fragment e ->
1163
+ (* A fragment `<>…</>` is a JSX-tagged `::`/`[]` list, not a Pexp_apply, so
1164
+ jsx_parts misses it. Recurse fine_node into each child exactly like an
1165
+ element's children (map_children preserves the outer @JSX attribute), so
1166
+ nested reactive regions stay *independent*. Without this the whole fragment
1167
+ would be wrapped in one coarse thunk and any nested `if`/`switch` inside it
1168
+ would collapse into that single tracked scope — rebuilding every sibling on
1169
+ one signal change. *)
1170
+ map_children (fine_node env) e
1154
1171
  | None ->
1155
1172
  (match e.pexp_desc with
1156
1173
  | Pexp_ifthenelse _ | Pexp_match _ ->