@zubra/runtime 5.1.0 → 5.1.1

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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zubra/runtime",
3
- "version": "5.1.0",
3
+ "version": "5.1.1",
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