@jsenv/navi 0.29.111 → 0.29.112

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.
@@ -60266,14 +60266,20 @@ const ListUI = props => {
60266
60266
  onListVisibleItemsChange?.(tracker.visibleItemsSignal.peek());
60267
60267
  }
60268
60268
  });
60269
- // A new pass every time the list renders: its children are about to say
60270
- // again, in order, which rows of the collection they stand for.
60269
+ // A new pass every time the list's children are walked: they are about to
60270
+ // say again, in order, which rows of the collection they stand for. Given
60271
+ // back the very vnodes it already holds, preact skips them — the list
60272
+ // re-rendered on its own and nothing is said again, so nothing is asked
60273
+ // again either (see openPass).
60271
60274
  const virtualRef = useRef(null);
60272
60275
  if (!virtualRef.current) {
60273
60276
  virtualRef.current = createListVirtual();
60274
60277
  }
60275
60278
  const virtual = virtualRef.current;
60276
- virtual.openPass(renderBudget, scrolled ?? defaultScrolled);
60279
+ const childrenPreviousRef = useRef(undefined);
60280
+ const childrenWalked = childrenPreviousRef.current !== children;
60281
+ childrenPreviousRef.current = children;
60282
+ virtual.openPass(renderBudget, scrolled ?? defaultScrolled, childrenWalked);
60277
60283
  const {
60278
60284
  virtualItemSizeSignal,
60279
60285
  renderWindow,
@@ -62866,9 +62872,22 @@ const createListVirtual = () => {
62866
62872
  horizontal: false,
62867
62873
  virtualItemSizeSignal: null,
62868
62874
  renderSkeleton: undefined,
62869
- openPass: (renderBudget, scrolled) => {
62875
+ openPass: (renderBudget, scrolled, childrenWalked) => {
62870
62876
  virtual.renderBudget = renderBudget;
62871
62877
  virtual.scrolled = scrolled;
62878
+ // Places are handed out again only when the children are actually walked
62879
+ // again. A list re-rendering on its own — the render window moved, its
62880
+ // scroller resolved — hands preact the very children vnodes it already
62881
+ // holds, and preact skips them: nobody says where they sit, so nobody
62882
+ // may lose where they sat. Reopening the pass there would empty the
62883
+ // places without anyone refilling them, and the next row to render on
62884
+ // its own (an item being selected, a run following the window) would be
62885
+ // handed the first place — drawing itself as the top of the list, its
62886
+ // separator gone, and the one after it wearing a separator it should not
62887
+ // have.
62888
+ if (!childrenWalked) {
62889
+ return;
62890
+ }
62872
62891
  passId++;
62873
62892
  nextIndex = 0;
62874
62893
  },
@@ -63183,8 +63202,13 @@ const ListItems = ({
63183
63202
  }, `${ownerId}_group_${group.key}`));
63184
63203
  group = null;
63185
63204
  };
63205
+ // Which group a row belongs to, or undefined when it belongs to none. Asked
63206
+ // before the row is pushed as well as while pushing it: a row opening a
63207
+ // group is the one row that must not wear a separator (see below).
63208
+ const groupKeyOf = (item, rowIndex) => groupBy && item !== undefined ? groupBy(item, rowIndex) : undefined;
63209
+ const opensGroup = groupKey => groupKey !== undefined && (!group || group.key !== groupKey);
63186
63210
  const pushRow = (rowNode, item, rowIndex) => {
63187
- const groupKey = groupBy && item !== undefined ? groupBy(item, rowIndex) : undefined;
63211
+ const groupKey = groupKeyOf(item, rowIndex);
63188
63212
  if (groupKey === undefined) {
63189
63213
  closeGroup();
63190
63214
  rows.push(rowNode);
@@ -63258,7 +63282,13 @@ const ListItems = ({
63258
63282
  });
63259
63283
  }
63260
63284
  if (rowVnode) {
63261
- if (separator && rowIndex > 0) {
63285
+ // The first row of a group wears no separator: the gap it sits at is the
63286
+ // one between two groups, and that gap is the group wrapper's own — it
63287
+ // is a row of the list like any other and draws its separator itself
63288
+ // (see ListItemUI). Drawn here it would land inside the group instead,
63289
+ // as a hairline under the label.
63290
+ const drawSeparator = separator && rowIndex > 0 && !opensGroup(groupKeyOf(item, rowIndex));
63291
+ if (drawSeparator) {
63262
63292
  pushRow(cloneElement(resolveSeparatorVnode(separator, rowIndex - 1), {
63263
63293
  key: `${key}_separator`
63264
63294
  }), item, rowIndex);