@zubra/runtime 5.1.0 → 5.1.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.
@@ -877,13 +877,24 @@ const isContent = (node) => node.nodeType === 1 || (node.nodeType === TEXT && no
877
877
  * The slot for each of `nodes` (an element's children, in order). Comments and whitespace are
878
878
  * frameworks' markers (Lit's parts, Svelte's anchors): a comment goes with the content after it
879
879
  * and whitespace with the content before it, so a framework's range stays together in one slot.
880
+ * Empty text nodes come in pairs (Vue brackets each fragment, a v-for, with two): both go with
881
+ * the content between them, since Vue moves that content through the start anchor's parent.
880
882
  */
881
883
  function assignSlots(nodes) {
882
884
  const named = nodes.map((node) => (isContent(node) ? slotName(node) : null));
883
- const after = (i) => { for (let j = i + 1; j < nodes.length; j++) if (named[j]) return named[j]; return null; };
884
- const before = (i) => { for (let j = i - 1; j >= 0; j--) if (named[j]) return named[j]; return null; };
885
+ // The slot of the nearest content after (step 1) or before (step -1) node i.
886
+ const near = (i, step) => { for (let j = i + step; nodes[j]; j += step) if (named[j]) return named[j]; return null; };
887
+ // An empty text node right before content opens a range; otherwise it closes the last one,
888
+ // and both take the slot of the first content between them.
889
+ const open = [];
890
+ nodes.forEach((node, i) => {
891
+ if (node.nodeType !== TEXT || node.data) return;
892
+ if (!open.length || named[i + 1] && nodes[i + 1].data == null) return open.push(i);
893
+ const start = open.pop();
894
+ named[start] = named[i] = named.slice(start + 1, i).find(Boolean);
895
+ });
885
896
  return nodes.map((node, i) => named[i]
886
- ?? (node.nodeType === COMMENT ? after(i) ?? before(i) : before(i) ?? after(i))
897
+ ?? (node.nodeType === COMMENT ? near(i, 1) ?? near(i, -1) : near(i, -1) ?? near(i, 1))
887
898
  ?? 'default');
888
899
  }
889
900
  let nativeText, nativeHTML; // looked up on first use, so the module loads without a DOM
@@ -1013,10 +1024,11 @@ function routeChildren(host, context, slots, tag) {
1013
1024
  for (const node of actual) if (node.nodeType === 1 && slotName(node) !== slot.name) insert(node, null);
1014
1025
  show(slot);
1015
1026
  }
1016
- // Content a parent adds inside a slot itself (its zb-if or zb-each there) is slotted too.
1027
+ // Content a parent adds inside a slot itself (its zb-if or zb-each there) is slotted too;
1028
+ // a fallback showing there is the component's own, so it stays unmarked.
1017
1029
  if (context.slotted) {
1018
1030
  for (const slot of context.slots.values()) {
1019
- if (!slot.region) continue;
1031
+ if (!slot.region?.provided) continue;
1020
1032
  for (let node = slot.region.open.nextSibling; node && node !== slot.region.close; node = node.nextSibling) {
1021
1033
  mark(node, context.slotted);
1022
1034
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zubra/runtime",
3
- "version": "5.1.0",
3
+ "version": "5.1.2",
4
4
  "description": "Browser runtime for Zubra compiled components, built on the TC39 Signals API",
5
5
  "license": "ISC",
6
6
  "repository": {
package/src/element.js CHANGED
@@ -892,13 +892,24 @@ const isContent = (node) => node.nodeType === 1 || (node.nodeType === TEXT && no
892
892
  * The slot for each of `nodes` (an element's children, in order). Comments and whitespace are
893
893
  * frameworks' markers (Lit's parts, Svelte's anchors): a comment goes with the content after it
894
894
  * and whitespace with the content before it, so a framework's range stays together in one slot.
895
+ * Empty text nodes come in pairs (Vue brackets each fragment, a v-for, with two): both go with
896
+ * the content between them, since Vue moves that content through the start anchor's parent.
895
897
  */
896
898
  function assignSlots(nodes) {
897
899
  const named = nodes.map((node) => (isContent(node) ? slotName(node) : null));
898
- const after = (i) => { for (let j = i + 1; j < nodes.length; j++) if (named[j]) return named[j]; return null; };
899
- const before = (i) => { for (let j = i - 1; j >= 0; j--) if (named[j]) return named[j]; return null; };
900
+ // The slot of the nearest content after (step 1) or before (step -1) node i.
901
+ const near = (i, step) => { for (let j = i + step; nodes[j]; j += step) if (named[j]) return named[j]; return null; };
902
+ // An empty text node right before content opens a range; otherwise it closes the last one,
903
+ // and both take the slot of the first content between them.
904
+ const open = [];
905
+ nodes.forEach((node, i) => {
906
+ if (node.nodeType !== TEXT || node.data) return;
907
+ if (!open.length || named[i + 1] && nodes[i + 1].data == null) return open.push(i);
908
+ const start = open.pop();
909
+ named[start] = named[i] = named.slice(start + 1, i).find(Boolean);
910
+ });
900
911
  return nodes.map((node, i) => named[i]
901
- ?? (node.nodeType === COMMENT ? after(i) ?? before(i) : before(i) ?? after(i))
912
+ ?? (node.nodeType === COMMENT ? near(i, 1) ?? near(i, -1) : near(i, -1) ?? near(i, 1))
902
913
  ?? 'default');
903
914
  }
904
915
  let nativeText, nativeHTML; // looked up on first use, so the module loads without a DOM
@@ -1028,10 +1039,11 @@ function routeChildren(host, context, slots, tag) {
1028
1039
  for (const node of actual) if (node.nodeType === 1 && slotName(node) !== slot.name) insert(node, null);
1029
1040
  show(slot);
1030
1041
  }
1031
- // Content a parent adds inside a slot itself (its zb-if or zb-each there) is slotted too.
1042
+ // Content a parent adds inside a slot itself (its zb-if or zb-each there) is slotted too;
1043
+ // a fallback showing there is the component's own, so it stays unmarked.
1032
1044
  if (context.slotted) {
1033
1045
  for (const slot of context.slots.values()) {
1034
- if (!slot.region) continue;
1046
+ if (!slot.region?.provided) continue;
1035
1047
  for (let node = slot.region.open.nextSibling; node && node !== slot.region.close; node = node.nextSibling) {
1036
1048
  mark(node, context.slotted);
1037
1049
  }