react-virtuoso 0.0.0-prepend → 0.0.0-semantic-release

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/dist/index.mjs CHANGED
@@ -34,6 +34,9 @@ function joinProc(...procs) {
34
34
  procs.map(call);
35
35
  };
36
36
  }
37
+ function isDefined(arg) {
38
+ return arg !== void 0;
39
+ }
37
40
  function noop() {
38
41
  }
39
42
  function subscribe(emitter, subscription) {
@@ -184,7 +187,7 @@ function skip(times) {
184
187
  };
185
188
  }
186
189
  function throttleTime(interval) {
187
- let currentValue;
190
+ let currentValue = null;
188
191
  let timeout;
189
192
  return (done) => (value) => {
190
193
  currentValue = value;
@@ -392,7 +395,22 @@ function systemToComponent(systemSpec, map2, Root) {
392
395
  const usePublisher2 = (key) => {
393
396
  return React.useCallback(curry2to1(publish, React.useContext(Context)[key]), [key]);
394
397
  };
395
- const useEmitterValue2 = (key) => {
398
+ const useEmitterValue18 = (key) => {
399
+ const system2 = React.useContext(Context);
400
+ const source = system2[key];
401
+ const cb = React.useCallback(
402
+ (c) => {
403
+ return subscribe(source, c);
404
+ },
405
+ [source]
406
+ );
407
+ return React.useSyncExternalStore(
408
+ cb,
409
+ () => getValue(source),
410
+ () => getValue(source)
411
+ );
412
+ };
413
+ const useEmitterValueLegacy = (key) => {
396
414
  const system2 = React.useContext(Context);
397
415
  const source = system2[key];
398
416
  const [value, setValue] = React.useState(curry1to0(getValue, source));
@@ -406,6 +424,7 @@ function systemToComponent(systemSpec, map2, Root) {
406
424
  );
407
425
  return value;
408
426
  };
427
+ const useEmitterValue2 = React.version.startsWith("18") ? useEmitterValue18 : useEmitterValueLegacy;
409
428
  const useEmitter2 = (key, callback) => {
410
429
  const context = React.useContext(Context);
411
430
  const source = context[key];
@@ -428,17 +447,33 @@ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
428
447
  return LogLevel2;
429
448
  })(LogLevel || {});
430
449
  const CONSOLE_METHOD_MAP = {
431
- [0]: "debug",
432
- [1]: "log",
433
- [2]: "warn",
434
- [3]: "error"
450
+ [
451
+ 0
452
+ /* DEBUG */
453
+ ]: "debug",
454
+ [
455
+ 1
456
+ /* INFO */
457
+ ]: "log",
458
+ [
459
+ 2
460
+ /* WARN */
461
+ ]: "warn",
462
+ [
463
+ 3
464
+ /* ERROR */
465
+ ]: "error"
435
466
  };
436
467
  const getGlobalThis = () => typeof globalThis === "undefined" ? window : globalThis;
437
468
  const loggerSystem = system(
438
469
  () => {
439
- const logLevel = statefulStream(3);
470
+ const logLevel = statefulStream(
471
+ 3
472
+ /* ERROR */
473
+ );
440
474
  const log = statefulStream((label, message, level = 1) => {
441
- const currentLevel = getGlobalThis()["VIRTUOSO_LOG_LEVEL"] ?? getValue(logLevel);
475
+ var _a;
476
+ const currentLevel = (_a = getGlobalThis()["VIRTUOSO_LOG_LEVEL"]) != null ? _a : getValue(logLevel);
442
477
  if (level >= currentLevel) {
443
478
  console[CONSOLE_METHOD_MAP[level]](
444
479
  "%creact-virtuoso: %c%s %o",
@@ -464,10 +499,12 @@ function useSizeWithElRef(callback, enabled = true) {
464
499
  if (typeof ResizeObserver !== "undefined") {
465
500
  const observer = React.useMemo(() => {
466
501
  return new ResizeObserver((entries) => {
467
- const element = entries[0].target;
468
- if (element.offsetParent !== null) {
469
- callback(element);
470
- }
502
+ requestAnimationFrame(() => {
503
+ const element = entries[0].target;
504
+ if (element.offsetParent !== null) {
505
+ callback(element);
506
+ }
507
+ });
471
508
  });
472
509
  }, [callback]);
473
510
  callbackRef = (elRef) => {
@@ -487,24 +524,26 @@ function useSizeWithElRef(callback, enabled = true) {
487
524
  function useSize(callback, enabled = true) {
488
525
  return useSizeWithElRef(callback, enabled).callbackRef;
489
526
  }
490
- function useChangedListContentsSizes(callback, itemSize, enabled, scrollContainerStateCallback, log, gap, customScrollParent) {
527
+ function useChangedListContentsSizes(callback, itemSize, enabled, scrollContainerStateCallback, log, gap, customScrollParent, horizontalDirection) {
491
528
  const memoedCallback = React.useCallback(
492
529
  (el) => {
493
- const ranges = getChangedChildSizes(el.children, itemSize, "offsetHeight", log);
530
+ const ranges = getChangedChildSizes(el.children, itemSize, horizontalDirection ? "offsetWidth" : "offsetHeight", log);
494
531
  let scrollableElement = el.parentElement;
495
532
  while (!scrollableElement.dataset["virtuosoScroller"]) {
496
533
  scrollableElement = scrollableElement.parentElement;
497
534
  }
498
535
  const windowScrolling = scrollableElement.lastElementChild.dataset["viewportType"] === "window";
499
- const scrollTop = customScrollParent ? customScrollParent.scrollTop : windowScrolling ? window.pageYOffset || document.documentElement.scrollTop : scrollableElement.scrollTop;
500
- const scrollHeight = customScrollParent ? customScrollParent.scrollHeight : windowScrolling ? document.documentElement.scrollHeight : scrollableElement.scrollHeight;
501
- const viewportHeight = customScrollParent ? customScrollParent.offsetHeight : windowScrolling ? window.innerHeight : scrollableElement.offsetHeight;
536
+ const scrollTop = customScrollParent ? horizontalDirection ? customScrollParent.scrollLeft : customScrollParent.scrollTop : windowScrolling ? horizontalDirection ? window.pageXOffset || document.documentElement.scrollLeft : window.pageYOffset || document.documentElement.scrollTop : horizontalDirection ? scrollableElement.scrollLeft : scrollableElement.scrollTop;
537
+ const scrollHeight = customScrollParent ? horizontalDirection ? customScrollParent.scrollWidth : customScrollParent.scrollHeight : windowScrolling ? horizontalDirection ? document.documentElement.scrollWidth : document.documentElement.scrollHeight : horizontalDirection ? scrollableElement.scrollWidth : scrollableElement.scrollHeight;
538
+ const viewportHeight = customScrollParent ? horizontalDirection ? customScrollParent.offsetWidth : customScrollParent.offsetHeight : windowScrolling ? horizontalDirection ? window.innerWidth : window.innerHeight : horizontalDirection ? scrollableElement.offsetWidth : scrollableElement.offsetHeight;
502
539
  scrollContainerStateCallback({
503
540
  scrollTop: Math.max(scrollTop, 0),
504
541
  scrollHeight,
505
542
  viewportHeight
506
543
  });
507
- gap == null ? void 0 : gap(resolveGapValue$1("row-gap", getComputedStyle(el).rowGap, log));
544
+ gap == null ? void 0 : gap(
545
+ horizontalDirection ? resolveGapValue$1("column-gap", getComputedStyle(el).columnGap, log) : resolveGapValue$1("row-gap", getComputedStyle(el).rowGap, log)
546
+ );
508
547
  if (ranges !== null) {
509
548
  callback(ranges);
510
549
  }
@@ -549,7 +588,7 @@ function resolveGapValue$1(property, value, log) {
549
588
  if (value === "normal") {
550
589
  return 0;
551
590
  }
552
- return parseInt(value ?? "0", 10);
591
+ return parseInt(value != null ? value : "0", 10);
553
592
  }
554
593
  function correctItemSize(el, dimension) {
555
594
  return Math.round(el.getBoundingClientRect()[dimension]);
@@ -557,7 +596,7 @@ function correctItemSize(el, dimension) {
557
596
  function approximatelyEqual(num1, num2) {
558
597
  return Math.abs(num1 - num2) < 1.01;
559
598
  }
560
- function useScrollTop(scrollContainerStateCallback, smoothScrollTargetReached, scrollerElement, scrollerRefCallback = noop, customScrollParent) {
599
+ function useScrollTop(scrollContainerStateCallback, smoothScrollTargetReached, scrollerElement, scrollerRefCallback = noop, customScrollParent, horizontalDirection) {
561
600
  const scrollerRef = React.useRef(null);
562
601
  const scrollTopTarget = React.useRef(null);
563
602
  const timeoutRef = React.useRef(null);
@@ -565,9 +604,9 @@ function useScrollTop(scrollContainerStateCallback, smoothScrollTargetReached, s
565
604
  (ev) => {
566
605
  const el = ev.target;
567
606
  const windowScroll = el === window || el === document;
568
- const scrollTop = windowScroll ? window.pageYOffset || document.documentElement.scrollTop : el.scrollTop;
569
- const scrollHeight = windowScroll ? document.documentElement.scrollHeight : el.scrollHeight;
570
- const viewportHeight = windowScroll ? window.innerHeight : el.offsetHeight;
607
+ const scrollTop = horizontalDirection ? windowScroll ? window.pageXOffset || document.documentElement.scrollLeft : el.scrollLeft : windowScroll ? window.pageYOffset || document.documentElement.scrollTop : el.scrollTop;
608
+ const scrollHeight = horizontalDirection ? windowScroll ? document.documentElement.scrollWidth : el.scrollWidth : windowScroll ? document.documentElement.scrollHeight : el.scrollHeight;
609
+ const viewportHeight = horizontalDirection ? windowScroll ? window.innerWidth : el.offsetWidth : windowScroll ? window.innerHeight : el.offsetHeight;
571
610
  const call2 = () => {
572
611
  scrollContainerStateCallback({
573
612
  scrollTop: Math.max(scrollTop, 0),
@@ -605,7 +644,7 @@ function useScrollTop(scrollContainerStateCallback, smoothScrollTargetReached, s
605
644
  }, [scrollerRef, handler, scrollerElement, scrollerRefCallback, customScrollParent]);
606
645
  function scrollToCallback(location) {
607
646
  const scrollerElement2 = scrollerRef.current;
608
- if (!scrollerElement2 || "offsetHeight" in scrollerElement2 && scrollerElement2.offsetHeight === 0) {
647
+ if (!scrollerElement2 || (horizontalDirection ? "offsetWidth" in scrollerElement2 && scrollerElement2.offsetWidth === 0 : "offsetHeight" in scrollerElement2 && scrollerElement2.offsetHeight === 0)) {
609
648
  return;
610
649
  }
611
650
  const isSmooth = location.behavior === "smooth";
@@ -613,13 +652,16 @@ function useScrollTop(scrollContainerStateCallback, smoothScrollTargetReached, s
613
652
  let scrollHeight;
614
653
  let scrollTop;
615
654
  if (scrollerElement2 === window) {
616
- scrollHeight = Math.max(correctItemSize(document.documentElement, "height"), document.documentElement.scrollHeight);
617
- offsetHeight = window.innerHeight;
618
- scrollTop = document.documentElement.scrollTop;
655
+ scrollHeight = Math.max(
656
+ correctItemSize(document.documentElement, horizontalDirection ? "width" : "height"),
657
+ horizontalDirection ? document.documentElement.scrollWidth : document.documentElement.scrollHeight
658
+ );
659
+ offsetHeight = horizontalDirection ? window.innerWidth : window.innerHeight;
660
+ scrollTop = horizontalDirection ? document.documentElement.scrollLeft : document.documentElement.scrollTop;
619
661
  } else {
620
- scrollHeight = scrollerElement2.scrollHeight;
621
- offsetHeight = correctItemSize(scrollerElement2, "height");
622
- scrollTop = scrollerElement2.scrollTop;
662
+ scrollHeight = scrollerElement2[horizontalDirection ? "scrollWidth" : "scrollHeight"];
663
+ offsetHeight = correctItemSize(scrollerElement2, horizontalDirection ? "width" : "height");
664
+ scrollTop = scrollerElement2[horizontalDirection ? "scrollLeft" : "scrollTop"];
623
665
  }
624
666
  const maxScrollTop = scrollHeight - offsetHeight;
625
667
  location.top = Math.ceil(Math.max(Math.min(maxScrollTop, location.top), 0));
@@ -643,9 +685,15 @@ function useScrollTop(scrollContainerStateCallback, smoothScrollTargetReached, s
643
685
  } else {
644
686
  scrollTopTarget.current = null;
645
687
  }
688
+ if (horizontalDirection) {
689
+ location = { left: location.top, behavior: location.behavior };
690
+ }
646
691
  scrollerElement2.scrollTo(location);
647
692
  }
648
693
  function scrollByCallback(location) {
694
+ if (horizontalDirection) {
695
+ location = { left: location.top, behavior: location.behavior };
696
+ }
649
697
  scrollerRef.current.scrollBy(location);
650
698
  }
651
699
  return { scrollerRef, scrollByCallback, scrollToCallback };
@@ -666,6 +714,7 @@ const domIOSystem = system(
666
714
  const scrollTo = stream();
667
715
  const scrollBy = stream();
668
716
  const scrollingInProgress = statefulStream(false);
717
+ const horizontalDirection = statefulStream(false);
669
718
  connect(
670
719
  pipe(
671
720
  scrollContainerState,
@@ -682,6 +731,7 @@ const domIOSystem = system(
682
731
  );
683
732
  connect(scrollTop, statefulScrollTop);
684
733
  return {
734
+ // input
685
735
  scrollContainerState,
686
736
  scrollTop,
687
737
  viewportHeight,
@@ -691,8 +741,11 @@ const domIOSystem = system(
691
741
  footerHeight,
692
742
  scrollHeight,
693
743
  smoothScrollTargetReached,
744
+ horizontalDirection,
745
+ // signals
694
746
  scrollTo,
695
747
  scrollBy,
748
+ // state
696
749
  statefulScrollTop,
697
750
  deviation,
698
751
  scrollingInProgress
@@ -746,10 +799,10 @@ function findMaxKeyValue(node, value, field = "k") {
746
799
  if (empty(node)) {
747
800
  return [-Infinity, void 0];
748
801
  }
749
- if (node[field] === value) {
802
+ if (Number(node[field]) === value) {
750
803
  return [node.k, node.v];
751
804
  }
752
- if (node[field] < value) {
805
+ if (Number(node[field]) < value) {
753
806
  const r = findMaxKeyValue(node.r, value, field);
754
807
  if (r[0] === -Infinity) {
755
808
  return [node.k, node.v];
@@ -1114,6 +1167,13 @@ function originalIndexFromItemIndex(itemIndex, sizes) {
1114
1167
  function hasGroups(sizes) {
1115
1168
  return !empty(sizes.groupOffsetTree);
1116
1169
  }
1170
+ function sizeTreeToRanges(sizeTree) {
1171
+ return walk(sizeTree).map(({ k: startIndex, v: size }, index, sizeArray) => {
1172
+ const nextSize = sizeArray[index + 1];
1173
+ const endIndex = nextSize ? nextSize.k - 1 : Infinity;
1174
+ return { startIndex, endIndex, size };
1175
+ });
1176
+ }
1117
1177
  const SIZE_MAP = {
1118
1178
  offsetHeight: "height",
1119
1179
  offsetWidth: "width"
@@ -1171,8 +1231,8 @@ const sizeSystem = system(
1171
1231
  pipe(
1172
1232
  totalCount,
1173
1233
  withLatestFrom(sizes),
1174
- filter(([totalCount2, { lastIndex, groupIndices: groupIndices2 }]) => {
1175
- return totalCount2 < lastIndex && groupIndices2.length === 0;
1234
+ filter(([totalCount2, { lastIndex }]) => {
1235
+ return totalCount2 < lastIndex;
1176
1236
  }),
1177
1237
  map(([totalCount2, { lastIndex, lastSize }]) => {
1178
1238
  return [
@@ -1239,8 +1299,9 @@ const sizeSystem = system(
1239
1299
  } else if (offset < 0) {
1240
1300
  const prevGroupIndicesValue = getValue(prevGroupIndices);
1241
1301
  if (prevGroupIndicesValue.length > 0) {
1242
- publish(shiftWith, offset - affectedGroupCount(-offset, prevGroupIndicesValue));
1302
+ offset -= affectedGroupCount(-offset, prevGroupIndicesValue);
1243
1303
  }
1304
+ publish(shiftWith, offset);
1244
1305
  }
1245
1306
  }
1246
1307
  );
@@ -1268,7 +1329,7 @@ const sizeSystem = system(
1268
1329
  let groupIndex = 0;
1269
1330
  while (prependedGroupItemsCount < unshiftWith2) {
1270
1331
  const theGroupIndex = sizes2.groupIndices[groupIndex];
1271
- const groupItemCount = sizes2.groupIndices[groupIndex + 1] - theGroupIndex - 1;
1332
+ const groupItemCount = sizes2.groupIndices.length === groupIndex + 1 ? Infinity : sizes2.groupIndices[groupIndex + 1] - theGroupIndex - 1;
1272
1333
  initialRanges.push({
1273
1334
  startIndex: theGroupIndex,
1274
1335
  endIndex: theGroupIndex,
@@ -1348,6 +1409,9 @@ const sizeSystem = system(
1348
1409
  map(([shiftWith2, sizes2, gap2]) => {
1349
1410
  const groupedMode = sizes2.groupIndices.length > 0;
1350
1411
  if (groupedMode) {
1412
+ if (empty(sizes2.sizeTree)) {
1413
+ return sizes2;
1414
+ }
1351
1415
  let newSizeTree = newTree();
1352
1416
  const prevGroupIndicesValue = getValue(prevGroupIndices);
1353
1417
  let removedItemsCount = 0;
@@ -1389,6 +1453,7 @@ const sizeSystem = system(
1389
1453
  sizes
1390
1454
  );
1391
1455
  return {
1456
+ // input
1392
1457
  data,
1393
1458
  totalCount,
1394
1459
  sizeRanges,
@@ -1401,6 +1466,7 @@ const sizeSystem = system(
1401
1466
  beforeUnshiftWith,
1402
1467
  firstItemIndex,
1403
1468
  gap,
1469
+ // output
1404
1470
  sizes,
1405
1471
  listRefresh,
1406
1472
  statefulTotalCount,
@@ -1441,6 +1507,7 @@ const scrollToIndexSystem = system(
1441
1507
  { log }
1442
1508
  ]) => {
1443
1509
  const scrollToIndex = stream();
1510
+ const scrollTargetReached = stream();
1444
1511
  const topListHeight = statefulStream(0);
1445
1512
  let unsubscribeNextListRefresh = null;
1446
1513
  let cleartTimeoutRef = null;
@@ -1496,6 +1563,7 @@ const scrollToIndexSystem = system(
1496
1563
  log2("retrying to scroll to", { location }, LogLevel.DEBUG);
1497
1564
  publish(scrollToIndex, location);
1498
1565
  } else {
1566
+ publish(scrollTargetReached, true);
1499
1567
  log2("list did not change, scroll successful", {}, LogLevel.DEBUG);
1500
1568
  }
1501
1569
  };
@@ -1524,6 +1592,7 @@ const scrollToIndexSystem = system(
1524
1592
  );
1525
1593
  return {
1526
1594
  scrollToIndex,
1595
+ scrollTargetReached,
1527
1596
  topListHeight
1528
1597
  };
1529
1598
  },
@@ -1703,6 +1772,7 @@ const stateFlagsSystem = system(([{ scrollContainerState, scrollTop, viewportHei
1703
1772
  pipe(
1704
1773
  isScrolling,
1705
1774
  filter((value) => !value),
1775
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
1706
1776
  mapTo(0)
1707
1777
  ),
1708
1778
  scrollVelocity
@@ -1750,15 +1820,23 @@ const propsReadySystem = system(
1750
1820
  tup(loggerSystem),
1751
1821
  { singleton: true }
1752
1822
  );
1823
+ function skipFrames(frameCount, callback) {
1824
+ if (frameCount == 0) {
1825
+ callback();
1826
+ } else {
1827
+ requestAnimationFrame(() => skipFrames(frameCount - 1, callback));
1828
+ }
1829
+ }
1753
1830
  function getInitialTopMostItemIndexNumber(location, totalCount) {
1754
1831
  const lastIndex = totalCount - 1;
1755
1832
  const index = typeof location === "number" ? location : location.index === "LAST" ? lastIndex : location.index;
1756
1833
  return index;
1757
1834
  }
1758
1835
  const initialTopMostItemIndexSystem = system(
1759
- ([{ sizes, listRefresh, defaultItemSize }, { scrollTop }, { scrollToIndex }, { didMount }]) => {
1836
+ ([{ sizes, listRefresh, defaultItemSize }, { scrollTop }, { scrollToIndex, scrollTargetReached }, { didMount }]) => {
1760
1837
  const scrolledToInitialItem = statefulStream(true);
1761
1838
  const initialTopMostItemIndex = statefulStream(0);
1839
+ const initialItemFinalLocationReached = statefulStream(true);
1762
1840
  connect(
1763
1841
  pipe(
1764
1842
  didMount,
@@ -1768,17 +1846,29 @@ const initialTopMostItemIndexSystem = system(
1768
1846
  ),
1769
1847
  scrolledToInitialItem
1770
1848
  );
1849
+ connect(
1850
+ pipe(
1851
+ didMount,
1852
+ withLatestFrom(initialTopMostItemIndex),
1853
+ filter(([_, location]) => !!location),
1854
+ mapTo(false)
1855
+ ),
1856
+ initialItemFinalLocationReached
1857
+ );
1771
1858
  subscribe(
1772
1859
  pipe(
1773
1860
  combineLatest(listRefresh, didMount),
1774
- withLatestFrom(scrolledToInitialItem, sizes, defaultItemSize),
1775
- filter(([[, didMount2], scrolledToInitialItem2, { sizeTree }, defaultItemSize2]) => {
1776
- return didMount2 && (!empty(sizeTree) || defaultItemSize2 !== void 0) && !scrolledToInitialItem2;
1861
+ withLatestFrom(scrolledToInitialItem, sizes, defaultItemSize, initialItemFinalLocationReached),
1862
+ filter(([[, didMount2], scrolledToInitialItem2, { sizeTree }, defaultItemSize2, scrollScheduled]) => {
1863
+ return didMount2 && (!empty(sizeTree) || isDefined(defaultItemSize2)) && !scrolledToInitialItem2 && !scrollScheduled;
1777
1864
  }),
1778
1865
  withLatestFrom(initialTopMostItemIndex)
1779
1866
  ),
1780
1867
  ([, initialTopMostItemIndex2]) => {
1781
- setTimeout(() => {
1868
+ handleNext(scrollTargetReached, () => {
1869
+ publish(initialItemFinalLocationReached, true);
1870
+ });
1871
+ skipFrames(3, () => {
1782
1872
  handleNext(scrollTop, () => {
1783
1873
  publish(scrolledToInitialItem, true);
1784
1874
  });
@@ -1788,7 +1878,8 @@ const initialTopMostItemIndexSystem = system(
1788
1878
  );
1789
1879
  return {
1790
1880
  scrolledToInitialItem,
1791
- initialTopMostItemIndex
1881
+ initialTopMostItemIndex,
1882
+ initialItemFinalLocationReached
1792
1883
  };
1793
1884
  },
1794
1885
  tup(sizeSystem, domIOSystem, scrollToIndexSystem, propsReadySystem),
@@ -1876,7 +1967,9 @@ const followOutputSystem = system(
1876
1967
  withLatestFrom(followOutput, totalCount)
1877
1968
  ),
1878
1969
  ([, followOutput2]) => {
1879
- trapNextSizeIncrease(followOutput2 !== false);
1970
+ if (getValue(scrolledToInitialItem)) {
1971
+ trapNextSizeIncrease(followOutput2 !== false);
1972
+ }
1880
1973
  }
1881
1974
  );
1882
1975
  subscribe(autoscrollToBottom, () => {
@@ -2019,10 +2112,12 @@ const sizeRangeSystem = system(
2019
2112
  [0, 0]
2020
2113
  );
2021
2114
  return {
2115
+ // input
2022
2116
  listBoundary,
2023
2117
  overscan,
2024
2118
  topListHeight,
2025
2119
  increaseViewportBy,
2120
+ // output
2026
2121
  visibleRange
2027
2122
  };
2028
2123
  },
@@ -2116,6 +2211,26 @@ function buildListState(items, topItems, totalCount, gap, sizes, firstItemIndex)
2116
2211
  firstItemIndex
2117
2212
  };
2118
2213
  }
2214
+ function buildListStateFromItemCount(itemCount, initialTopMostItemIndex, sizes, firstItemIndex, gap, data) {
2215
+ let includedGroupsCount = 0;
2216
+ if (sizes.groupIndices.length > 0) {
2217
+ for (const index of sizes.groupIndices) {
2218
+ if (index - includedGroupsCount >= itemCount) {
2219
+ break;
2220
+ }
2221
+ includedGroupsCount++;
2222
+ }
2223
+ }
2224
+ const adjustedCount = itemCount + includedGroupsCount;
2225
+ const initialTopMostItemIndexNumber = getInitialTopMostItemIndexNumber(initialTopMostItemIndex, adjustedCount);
2226
+ const items = Array.from({ length: adjustedCount }).map((_, index) => ({
2227
+ index: index + initialTopMostItemIndexNumber,
2228
+ size: 0,
2229
+ offset: 0,
2230
+ data: data[index + initialTopMostItemIndexNumber]
2231
+ }));
2232
+ return buildListState(items, [], adjustedCount, gap, sizes, firstItemIndex);
2233
+ }
2119
2234
  const listStateSystem = system(
2120
2235
  ([
2121
2236
  { sizes, totalCount, data, firstItemIndex, gap },
@@ -2128,6 +2243,7 @@ const listStateSystem = system(
2128
2243
  { recalcInProgress }
2129
2244
  ]) => {
2130
2245
  const topItemsIndexes = statefulStream([]);
2246
+ const initialItemCount = statefulStream(0);
2131
2247
  const itemsRendered = stream();
2132
2248
  connect(groupedListSystem2.topItemsIndexes, topItemsIndexes);
2133
2249
  const listState = statefulStreamFromEmitter(
@@ -2165,11 +2281,22 @@ const listStateSystem = system(
2165
2281
  ]) => {
2166
2282
  const sizesValue = sizes2;
2167
2283
  const { sizeTree, offsetTree } = sizesValue;
2168
- if (totalCount2 === 0 || startOffset === 0 && endOffset === 0) {
2284
+ const initialItemCountValue = getValue(initialItemCount);
2285
+ if (totalCount2 === 0) {
2169
2286
  return { ...EMPTY_LIST_STATE, totalCount: totalCount2 };
2170
2287
  }
2288
+ if (startOffset === 0 && endOffset === 0) {
2289
+ if (initialItemCountValue === 0) {
2290
+ return { ...EMPTY_LIST_STATE, totalCount: totalCount2 };
2291
+ } else {
2292
+ return buildListStateFromItemCount(initialItemCountValue, initialTopMostItemIndex2, sizes2, firstItemIndex2, gap2, data2 || []);
2293
+ }
2294
+ }
2171
2295
  if (empty(sizeTree)) {
2172
- return buildListState(
2296
+ if (initialItemCountValue > 0) {
2297
+ return null;
2298
+ }
2299
+ const state = buildListState(
2173
2300
  probeItemSet(getInitialTopMostItemIndexNumber(initialTopMostItemIndex2, totalCount2), sizesValue, data2),
2174
2301
  [],
2175
2302
  totalCount2,
@@ -2177,6 +2304,7 @@ const listStateSystem = system(
2177
2304
  sizesValue,
2178
2305
  firstItemIndex2
2179
2306
  );
2307
+ return state;
2180
2308
  }
2181
2309
  const topItems = [];
2182
2310
  if (topItemsIndexes2.length > 0) {
@@ -2230,6 +2358,7 @@ const listStateSystem = system(
2230
2358
  return buildListState(items, topItems, totalCount2, gap2, sizesValue, firstItemIndex2);
2231
2359
  }
2232
2360
  ),
2361
+ //@ts-expect-error filter needs to be fixed
2233
2362
  filter((value) => value !== null),
2234
2363
  distinctUntilChanged()
2235
2364
  ),
@@ -2238,7 +2367,7 @@ const listStateSystem = system(
2238
2367
  connect(
2239
2368
  pipe(
2240
2369
  data,
2241
- filter((data2) => data2 !== void 0),
2370
+ filter(isDefined),
2242
2371
  map((data2) => data2 == null ? void 0 : data2.length)
2243
2372
  ),
2244
2373
  totalCount
@@ -2308,7 +2437,7 @@ const listStateSystem = system(
2308
2437
  distinctUntilChanged(rangeComparator)
2309
2438
  )
2310
2439
  );
2311
- return { listState, topItemsIndexes, endReached, startReached, rangeChanged, itemsRendered, ...stateFlags };
2440
+ return { listState, topItemsIndexes, endReached, startReached, rangeChanged, itemsRendered, initialItemCount, ...stateFlags };
2312
2441
  },
2313
2442
  tup(
2314
2443
  sizeSystem,
@@ -2323,34 +2452,22 @@ const listStateSystem = system(
2323
2452
  { singleton: true }
2324
2453
  );
2325
2454
  const initialItemCountSystem = system(
2326
- ([{ sizes, firstItemIndex, data, gap }, { listState }, { didMount }]) => {
2327
- const initialItemCount = statefulStream(0);
2455
+ ([{ sizes, firstItemIndex, data, gap }, { initialTopMostItemIndex }, { initialItemCount, listState }, { didMount }]) => {
2328
2456
  connect(
2329
2457
  pipe(
2330
2458
  didMount,
2331
2459
  withLatestFrom(initialItemCount),
2332
2460
  filter(([, count]) => count !== 0),
2333
- withLatestFrom(sizes, firstItemIndex, gap, data),
2334
- map(([[, count], sizes2, firstItemIndex2, gap2, data2 = []]) => {
2335
- let includedGroupsCount = 0;
2336
- if (sizes2.groupIndices.length > 0) {
2337
- for (const index of sizes2.groupIndices) {
2338
- if (index - includedGroupsCount >= count) {
2339
- break;
2340
- }
2341
- includedGroupsCount++;
2342
- }
2343
- }
2344
- const adjustedCount = count + includedGroupsCount;
2345
- const items = Array.from({ length: adjustedCount }).map((_, index) => ({ index, size: 0, offset: 0, data: data2[index] }));
2346
- return buildListState(items, [], adjustedCount, gap2, sizes2, firstItemIndex2);
2461
+ withLatestFrom(initialTopMostItemIndex, sizes, firstItemIndex, gap, data),
2462
+ map(([[, count], initialTopMostItemIndexValue, sizes2, firstItemIndex2, gap2, data2 = []]) => {
2463
+ return buildListStateFromItemCount(count, initialTopMostItemIndexValue, sizes2, firstItemIndex2, gap2, data2);
2347
2464
  })
2348
2465
  ),
2349
2466
  listState
2350
2467
  );
2351
- return { initialItemCount };
2468
+ return {};
2352
2469
  },
2353
- tup(sizeSystem, listStateSystem, propsReadySystem),
2470
+ tup(sizeSystem, initialTopMostItemIndexSystem, listStateSystem, propsReadySystem),
2354
2471
  { singleton: true }
2355
2472
  );
2356
2473
  const scrollSeekSystem = system(
@@ -2528,7 +2645,7 @@ const upwardScrollFixSystem = system(
2528
2645
  while (recognizedOffsetItems < offset) {
2529
2646
  recognizedOffsetItems++;
2530
2647
  amount += defaultGroupSize;
2531
- let groupItemCount = groupIndices[groupIndex + 1] - groupIndices[groupIndex] - 1;
2648
+ let groupItemCount = groupIndices.length === groupIndex + 1 ? Infinity : groupIndices[groupIndex + 1] - groupIndices[groupIndex] - 1;
2532
2649
  if (recognizedOffsetItems + groupItemCount > offset) {
2533
2650
  amount -= defaultGroupSize;
2534
2651
  groupItemCount = offset - recognizedOffsetItems + 1;
@@ -2557,7 +2674,7 @@ const upwardScrollFixSystem = system(
2557
2674
  tup(domIOSystem, stateFlagsSystem, listStateSystem, sizeSystem, loggerSystem, recalcSystem)
2558
2675
  );
2559
2676
  const initialScrollTopSystem = system(
2560
- ([{ totalListHeight }, { didMount }, { scrollTo }]) => {
2677
+ ([{ didMount }, { scrollTo }, { listState }]) => {
2561
2678
  const initialScrollTop = statefulStream(0);
2562
2679
  subscribe(
2563
2680
  pipe(
@@ -2569,11 +2686,12 @@ const initialScrollTopSystem = system(
2569
2686
  (location) => {
2570
2687
  handleNext(
2571
2688
  pipe(
2572
- totalListHeight,
2573
- filter((val) => val !== 0)
2689
+ listState,
2690
+ skip(1),
2691
+ filter((state) => state.items.length > 1)
2574
2692
  ),
2575
2693
  () => {
2576
- setTimeout(() => {
2694
+ requestAnimationFrame(() => {
2577
2695
  publish(scrollTo, location);
2578
2696
  });
2579
2697
  }
@@ -2584,7 +2702,7 @@ const initialScrollTopSystem = system(
2584
2702
  initialScrollTop
2585
2703
  };
2586
2704
  },
2587
- tup(totalListHeightSystem, propsReadySystem, domIOSystem),
2705
+ tup(propsReadySystem, domIOSystem, listStateSystem),
2588
2706
  { singleton: true }
2589
2707
  );
2590
2708
  const alignToBottomSystem = system(
@@ -2597,6 +2715,7 @@ const alignToBottomSystem = system(
2597
2715
  map(([, viewportHeight2, totalListHeight2]) => {
2598
2716
  return Math.max(0, viewportHeight2 - totalListHeight2);
2599
2717
  }),
2718
+ throttleTime(0),
2600
2719
  distinctUntilChanged()
2601
2720
  ),
2602
2721
  0
@@ -2639,10 +2758,13 @@ const windowScrollerSystem = system(([{ scrollTo, scrollContainerState }]) => {
2639
2758
  windowScrollTo
2640
2759
  );
2641
2760
  return {
2761
+ // config
2642
2762
  useWindowScroll,
2643
2763
  customScrollParent,
2764
+ // input
2644
2765
  windowScrollContainerState,
2645
2766
  windowViewportRect,
2767
+ // signals
2646
2768
  windowScrollTo
2647
2769
  };
2648
2770
  }, tup(domIOSystem));
@@ -2654,10 +2776,10 @@ const defaultCalculateViewLocation = ({
2654
2776
  locationParams: { behavior, align, ...rest }
2655
2777
  }) => {
2656
2778
  if (itemTop2 < viewportTop) {
2657
- return { ...rest, behavior, align: align ?? "start" };
2779
+ return { ...rest, behavior, align: align != null ? align : "start" };
2658
2780
  }
2659
2781
  if (itemBottom > viewportBottom) {
2660
- return { ...rest, behavior, align: align ?? "end" };
2782
+ return { ...rest, behavior, align: align != null ? align : "end" };
2661
2783
  }
2662
2784
  return null;
2663
2785
  };
@@ -2692,6 +2814,8 @@ const scrollIntoViewSystem = system(
2692
2814
  pipe(
2693
2815
  scrollingInProgress,
2694
2816
  filter((value) => value === false),
2817
+ // skips the initial publish of false, and the cleanup call.
2818
+ // but if scrollingInProgress is true, we skip the initial publish.
2695
2819
  skip(getValue(scrollingInProgress) ? 1 : 2)
2696
2820
  ),
2697
2821
  done
@@ -2712,6 +2836,53 @@ const scrollIntoViewSystem = system(
2712
2836
  tup(sizeSystem, domIOSystem, scrollToIndexSystem, listStateSystem, loggerSystem),
2713
2837
  { singleton: true }
2714
2838
  );
2839
+ const stateLoadSystem = system(
2840
+ ([
2841
+ { sizes, sizeRanges },
2842
+ { scrollTop },
2843
+ { initialTopMostItemIndex },
2844
+ { didMount },
2845
+ { useWindowScroll, windowScrollContainerState, windowViewportRect }
2846
+ ]) => {
2847
+ const getState = stream();
2848
+ const restoreStateFrom = statefulStream(void 0);
2849
+ const statefulWindowScrollContainerState = statefulStream(null);
2850
+ const statefulWindowViewportRect = statefulStream(null);
2851
+ connect(windowScrollContainerState, statefulWindowScrollContainerState);
2852
+ connect(windowViewportRect, statefulWindowViewportRect);
2853
+ subscribe(
2854
+ pipe(getState, withLatestFrom(sizes, scrollTop, useWindowScroll, statefulWindowScrollContainerState, statefulWindowViewportRect)),
2855
+ ([callback, sizes2, scrollTop2, useWindowScroll2, windowScrollContainerState2, windowViewportRect2]) => {
2856
+ const ranges = sizeTreeToRanges(sizes2.sizeTree);
2857
+ if (useWindowScroll2 && windowScrollContainerState2 !== null && windowViewportRect2 !== null) {
2858
+ scrollTop2 = windowScrollContainerState2.scrollTop - windowViewportRect2.offsetTop;
2859
+ }
2860
+ callback({ ranges, scrollTop: scrollTop2 });
2861
+ }
2862
+ );
2863
+ connect(pipe(restoreStateFrom, filter(isDefined), map(locationFromSnapshot)), initialTopMostItemIndex);
2864
+ connect(
2865
+ pipe(
2866
+ didMount,
2867
+ withLatestFrom(restoreStateFrom),
2868
+ filter(([, state]) => state !== void 0),
2869
+ distinctUntilChanged(),
2870
+ map(([, snapshot]) => {
2871
+ return snapshot.ranges;
2872
+ })
2873
+ ),
2874
+ sizeRanges
2875
+ );
2876
+ return {
2877
+ getState,
2878
+ restoreStateFrom
2879
+ };
2880
+ },
2881
+ tup(sizeSystem, domIOSystem, initialTopMostItemIndexSystem, propsReadySystem, windowScrollerSystem)
2882
+ );
2883
+ function locationFromSnapshot(snapshot) {
2884
+ return { offset: snapshot.scrollTop, index: 0, align: "start" };
2885
+ }
2715
2886
  const featureGroup1System = system(
2716
2887
  ([
2717
2888
  sizeRange,
@@ -2722,7 +2893,8 @@ const featureGroup1System = system(
2722
2893
  initialScrollTopSystem2,
2723
2894
  alignToBottom,
2724
2895
  windowScroller,
2725
- scrollIntoView
2896
+ scrollIntoView,
2897
+ logger
2726
2898
  ]) => {
2727
2899
  return {
2728
2900
  ...sizeRange,
@@ -2733,7 +2905,8 @@ const featureGroup1System = system(
2733
2905
  ...initialScrollTopSystem2,
2734
2906
  ...alignToBottom,
2735
2907
  ...windowScroller,
2736
- ...scrollIntoView
2908
+ ...scrollIntoView,
2909
+ ...logger
2737
2910
  };
2738
2911
  },
2739
2912
  tup(
@@ -2745,7 +2918,8 @@ const featureGroup1System = system(
2745
2918
  initialScrollTopSystem,
2746
2919
  alignToBottomSystem,
2747
2920
  windowScrollerSystem,
2748
- scrollIntoViewSystem
2921
+ scrollIntoViewSystem,
2922
+ loggerSystem
2749
2923
  )
2750
2924
  );
2751
2925
  const listSystem = system(
@@ -2764,16 +2938,16 @@ const listSystem = system(
2764
2938
  gap,
2765
2939
  sizes
2766
2940
  },
2767
- { initialTopMostItemIndex, scrolledToInitialItem },
2941
+ { initialTopMostItemIndex, scrolledToInitialItem, initialItemFinalLocationReached },
2768
2942
  domIO,
2943
+ stateLoad,
2769
2944
  followOutput,
2770
2945
  { listState, topItemsIndexes, ...flags },
2771
2946
  { scrollToIndex },
2772
2947
  _,
2773
2948
  { topItemCount },
2774
2949
  { groupCounts },
2775
- featureGroup1,
2776
- log
2950
+ featureGroup1
2777
2951
  ]) => {
2778
2952
  connect(flags.rangeChanged, featureGroup1.scrollSeekRangeChanged);
2779
2953
  connect(
@@ -2784,12 +2958,14 @@ const listSystem = system(
2784
2958
  domIO.viewportHeight
2785
2959
  );
2786
2960
  return {
2961
+ // input
2787
2962
  totalCount,
2788
2963
  data,
2789
2964
  firstItemIndex,
2790
2965
  sizeRanges,
2791
2966
  initialTopMostItemIndex,
2792
2967
  scrolledToInitialItem,
2968
+ initialItemFinalLocationReached,
2793
2969
  topItemsIndexes,
2794
2970
  topItemCount,
2795
2971
  groupCounts,
@@ -2797,31 +2973,34 @@ const listSystem = system(
2797
2973
  defaultItemHeight: defaultItemSize,
2798
2974
  gap,
2799
2975
  ...followOutput,
2976
+ // output
2800
2977
  statefulTotalCount,
2801
2978
  listState,
2802
2979
  scrollToIndex,
2803
2980
  trackItemSizes,
2804
2981
  itemSize,
2805
2982
  groupIndices,
2983
+ // exported from stateFlagsSystem
2806
2984
  ...flags,
2985
+ // the bag of IO from featureGroup1System
2807
2986
  ...featureGroup1,
2808
2987
  ...domIO,
2809
- ...log,
2810
- sizes
2988
+ sizes,
2989
+ ...stateLoad
2811
2990
  };
2812
2991
  },
2813
2992
  tup(
2814
2993
  sizeSystem,
2815
2994
  initialTopMostItemIndexSystem,
2816
2995
  domIOSystem,
2996
+ stateLoadSystem,
2817
2997
  followOutputSystem,
2818
2998
  listStateSystem,
2819
2999
  scrollToIndexSystem,
2820
3000
  upwardScrollFixSystem,
2821
3001
  topItemCountSystem,
2822
3002
  groupedListSystem,
2823
- featureGroup1System,
2824
- loggerSystem
3003
+ featureGroup1System
2825
3004
  )
2826
3005
  );
2827
3006
  const WEBKIT_STICKY = "-webkit-sticky";
@@ -2869,7 +3048,9 @@ function useWindowViewportRectRef(callback, customScrollParent) {
2869
3048
  React.useEffect(() => {
2870
3049
  if (customScrollParent) {
2871
3050
  customScrollParent.addEventListener("scroll", scrollAndResizeEventHandler);
2872
- const observer = new ResizeObserver(scrollAndResizeEventHandler);
3051
+ const observer = new ResizeObserver(() => {
3052
+ requestAnimationFrame(scrollAndResizeEventHandler);
3053
+ });
2873
3054
  observer.observe(customScrollParent);
2874
3055
  return () => {
2875
3056
  customScrollParent.removeEventListener("scroll", scrollAndResizeEventHandler);
@@ -2933,7 +3114,8 @@ const combinedSystem$2 = /* @__PURE__ */ system(([listSystem2, propsSystem]) =>
2933
3114
  }, tup(listSystem, listComponentPropsSystem));
2934
3115
  const DefaultScrollSeekPlaceholder$1 = ({ height }) => /* @__PURE__ */ React.createElement("div", { style: { height } });
2935
3116
  const GROUP_STYLE = { position: positionStickyCssValue(), zIndex: 1, overflowAnchor: "none" };
2936
- const ITEM_STYLE = { overflowAnchor: "none" };
3117
+ const ITEM_STYLE$1 = { overflowAnchor: "none" };
3118
+ const HORIZONTAL_ITEM_STYLE = { ...ITEM_STYLE$1, display: "inline-block", height: "100%" };
2937
3119
  const Items$1 = /* @__PURE__ */ React.memo(function VirtuosoItems({ showTopList = false }) {
2938
3120
  const listState = useEmitterValue$2("listState");
2939
3121
  const sizeRanges = usePublisher$2("sizeRanges");
@@ -2949,6 +3131,7 @@ const Items$1 = /* @__PURE__ */ React.memo(function VirtuosoItems({ showTopList
2949
3131
  const itemSize = useEmitterValue$2("itemSize");
2950
3132
  const log = useEmitterValue$2("log");
2951
3133
  const listGap = usePublisher$2("gap");
3134
+ const horizontalDirection = useEmitterValue$2("horizontalDirection");
2952
3135
  const { callbackRef } = useChangedListContentsSizes(
2953
3136
  sizeRanges,
2954
3137
  itemSize,
@@ -2956,7 +3139,8 @@ const Items$1 = /* @__PURE__ */ React.memo(function VirtuosoItems({ showTopList
2956
3139
  showTopList ? noop : scrollContainerStateCallback,
2957
3140
  log,
2958
3141
  listGap,
2959
- customScrollParent
3142
+ customScrollParent,
3143
+ horizontalDirection
2960
3144
  );
2961
3145
  const [deviation, setDeviation] = React.useState(0);
2962
3146
  useEmitter$2("deviation", (value) => {
@@ -2972,12 +3156,23 @@ const Items$1 = /* @__PURE__ */ React.memo(function VirtuosoItems({ showTopList
2972
3156
  const computeItemKey = useEmitterValue$2("computeItemKey");
2973
3157
  const isSeeking = useEmitterValue$2("isSeeking");
2974
3158
  const hasGroups2 = useEmitterValue$2("groupIndices").length > 0;
2975
- const paddingTopAddition = useEmitterValue$2("paddingTopAddition");
3159
+ const alignToBottom = useEmitterValue$2("alignToBottom");
3160
+ const initialItemFinalLocationReached = useEmitterValue$2("initialItemFinalLocationReached");
2976
3161
  const containerStyle = showTopList ? {} : {
2977
3162
  boxSizing: "border-box",
2978
- paddingTop: listState.offsetTop + paddingTopAddition,
2979
- paddingBottom: listState.offsetBottom,
2980
- marginTop: deviation
3163
+ ...horizontalDirection ? {
3164
+ whiteSpace: "nowrap",
3165
+ display: "inline-block",
3166
+ height: "100%",
3167
+ paddingLeft: listState.offsetTop,
3168
+ paddingRight: listState.offsetBottom,
3169
+ marginLeft: deviation !== 0 ? deviation : alignToBottom ? "auto" : 0
3170
+ } : {
3171
+ marginTop: deviation !== 0 ? deviation : alignToBottom ? "auto" : 0,
3172
+ paddingTop: listState.offsetTop,
3173
+ paddingBottom: listState.offsetBottom
3174
+ },
3175
+ ...initialItemFinalLocationReached ? {} : { visibility: "hidden" }
2981
3176
  };
2982
3177
  if (!showTopList && listState.totalCount === 0 && EmptyPlaceholder) {
2983
3178
  return React.createElement(EmptyPlaceholder, contextPropIfNotDomElement(EmptyPlaceholder, context));
@@ -2988,7 +3183,7 @@ const Items$1 = /* @__PURE__ */ React.memo(function VirtuosoItems({ showTopList
2988
3183
  ...contextPropIfNotDomElement(ListComponent, context),
2989
3184
  ref: callbackRef,
2990
3185
  style: containerStyle,
2991
- "data-test-id": showTopList ? "virtuoso-top-item-list" : "virtuoso-item-list"
3186
+ "data-testid": showTopList ? "virtuoso-top-item-list" : "virtuoso-item-list"
2992
3187
  },
2993
3188
  (showTopList ? listState.topItems : listState.items).map((item) => {
2994
3189
  const index = item.originalIndex;
@@ -3021,13 +3216,13 @@ const Items$1 = /* @__PURE__ */ React.memo(function VirtuosoItems({ showTopList
3021
3216
  ItemComponent,
3022
3217
  {
3023
3218
  ...contextPropIfNotDomElement(ItemComponent, context),
3219
+ ...itemPropIfNotDomElement(ItemComponent, item.data),
3024
3220
  key,
3025
3221
  "data-index": index,
3026
3222
  "data-known-size": item.size,
3027
3223
  "data-item-index": item.index,
3028
3224
  "data-item-group-index": item.groupIndex,
3029
- item: item.data,
3030
- style: ITEM_STYLE
3225
+ style: horizontalDirection ? HORIZONTAL_ITEM_STYLE : ITEM_STYLE$1
3031
3226
  },
3032
3227
  hasGroups2 ? itemContent(item.index, item.groupIndex, item.data, context) : itemContent(item.index, item.data, context)
3033
3228
  );
@@ -3042,12 +3237,18 @@ const scrollerStyle = {
3042
3237
  position: "relative",
3043
3238
  WebkitOverflowScrolling: "touch"
3044
3239
  };
3045
- const viewportStyle = {
3240
+ const horizontalScrollerStyle = {
3241
+ outline: "none",
3242
+ overflowX: "auto",
3243
+ position: "relative"
3244
+ };
3245
+ const viewportStyle = (alignToBottom) => ({
3046
3246
  width: "100%",
3047
3247
  height: "100%",
3048
3248
  position: "absolute",
3049
- top: 0
3050
- };
3249
+ top: 0,
3250
+ ...alignToBottom ? { display: "flex", flexDirection: "column" } : {}
3251
+ });
3051
3252
  const topItemListStyle = {
3052
3253
  width: "100%",
3053
3254
  position: positionStickyCssValue(),
@@ -3060,6 +3261,9 @@ function contextPropIfNotDomElement(element, context) {
3060
3261
  }
3061
3262
  return { context };
3062
3263
  }
3264
+ function itemPropIfNotDomElement(element, item) {
3265
+ return { item: typeof element === "string" ? void 0 : item };
3266
+ }
3063
3267
  const Header$1 = /* @__PURE__ */ React.memo(function VirtuosoHeader() {
3064
3268
  const Header2 = useEmitterValue$2("HeaderComponent");
3065
3269
  const headerHeight = usePublisher$2("headerHeight");
@@ -3083,20 +3287,24 @@ function buildScroller({ usePublisher: usePublisher2, useEmitter: useEmitter2, u
3083
3287
  const smoothScrollTargetReached = usePublisher2("smoothScrollTargetReached");
3084
3288
  const scrollerRefCallback = useEmitterValue2("scrollerRef");
3085
3289
  const context = useEmitterValue2("context");
3290
+ const horizontalDirection = useEmitterValue2("horizontalDirection") || false;
3086
3291
  const { scrollerRef, scrollByCallback, scrollToCallback } = useScrollTop(
3087
3292
  scrollContainerStateCallback,
3088
3293
  smoothScrollTargetReached,
3089
3294
  ScrollerComponent,
3090
- scrollerRefCallback
3295
+ scrollerRefCallback,
3296
+ void 0,
3297
+ horizontalDirection
3091
3298
  );
3092
3299
  useEmitter2("scrollTo", scrollToCallback);
3093
3300
  useEmitter2("scrollBy", scrollByCallback);
3301
+ const defaultStyle = horizontalDirection ? horizontalScrollerStyle : scrollerStyle;
3094
3302
  return React.createElement(
3095
3303
  ScrollerComponent,
3096
3304
  {
3097
3305
  ref: scrollerRef,
3098
- style: { ...scrollerStyle, ...style },
3099
- "data-test-id": "virtuoso-scroller",
3306
+ style: { ...defaultStyle, ...style },
3307
+ "data-testid": "virtuoso-scroller",
3100
3308
  "data-virtuoso-scroller": true,
3101
3309
  tabIndex: 0,
3102
3310
  ...props,
@@ -3148,14 +3356,16 @@ const Viewport$2 = ({ children }) => {
3148
3356
  const ctx = React.useContext(VirtuosoMockContext);
3149
3357
  const viewportHeight = usePublisher$2("viewportHeight");
3150
3358
  const fixedItemHeight = usePublisher$2("fixedItemHeight");
3151
- const viewportRef = useSize(compose(viewportHeight, (el) => correctItemSize(el, "height")));
3359
+ const alignToBottom = useEmitterValue$2("alignToBottom");
3360
+ const horizontalDirection = useEmitterValue$2("horizontalDirection");
3361
+ const viewportRef = useSize(compose(viewportHeight, (el) => correctItemSize(el, horizontalDirection ? "width" : "height")));
3152
3362
  React.useEffect(() => {
3153
3363
  if (ctx) {
3154
3364
  viewportHeight(ctx.viewportHeight);
3155
3365
  fixedItemHeight(ctx.itemHeight);
3156
3366
  }
3157
3367
  }, [ctx, viewportHeight, fixedItemHeight]);
3158
- return /* @__PURE__ */ React.createElement("div", { style: viewportStyle, ref: viewportRef, "data-viewport-type": "element" }, children);
3368
+ return /* @__PURE__ */ React.createElement("div", { style: viewportStyle(alignToBottom), ref: viewportRef, "data-viewport-type": "element" }, children);
3159
3369
  };
3160
3370
  const WindowViewport$2 = ({ children }) => {
3161
3371
  const ctx = React.useContext(VirtuosoMockContext);
@@ -3163,20 +3373,21 @@ const WindowViewport$2 = ({ children }) => {
3163
3373
  const fixedItemHeight = usePublisher$2("fixedItemHeight");
3164
3374
  const customScrollParent = useEmitterValue$2("customScrollParent");
3165
3375
  const viewportRef = useWindowViewportRectRef(windowViewportRect, customScrollParent);
3376
+ const alignToBottom = useEmitterValue$2("alignToBottom");
3166
3377
  React.useEffect(() => {
3167
3378
  if (ctx) {
3168
3379
  fixedItemHeight(ctx.itemHeight);
3169
3380
  windowViewportRect({ offsetTop: 0, visibleHeight: ctx.viewportHeight, visibleWidth: 100 });
3170
3381
  }
3171
3382
  }, [ctx, windowViewportRect, fixedItemHeight]);
3172
- return /* @__PURE__ */ React.createElement("div", { ref: viewportRef, style: viewportStyle, "data-viewport-type": "window" }, children);
3383
+ return /* @__PURE__ */ React.createElement("div", { ref: viewportRef, style: viewportStyle(alignToBottom), "data-viewport-type": "window" }, children);
3173
3384
  };
3174
3385
  const TopItemListContainer = ({ children }) => {
3175
- const TopItemList = useEmitterValue$2("TopItemListComponent");
3386
+ const TopItemList = useEmitterValue$2("TopItemListComponent") || "div";
3176
3387
  const headerHeight = useEmitterValue$2("headerHeight");
3177
3388
  const style = { ...topItemListStyle, marginTop: `${headerHeight}px` };
3178
3389
  const context = useEmitterValue$2("context");
3179
- return React.createElement(TopItemList || "div", { style, context }, children);
3390
+ return React.createElement(TopItemList, { style, ...contextPropIfNotDomElement(TopItemList, context) }, children);
3180
3391
  };
3181
3392
  const ListRoot = /* @__PURE__ */ React.memo(function VirtuosoRoot(props) {
3182
3393
  const useWindowScroll = useEmitterValue$2("useWindowScroll");
@@ -3196,6 +3407,7 @@ const {
3196
3407
  {
3197
3408
  required: {},
3198
3409
  optional: {
3410
+ restoreStateFrom: "restoreStateFrom",
3199
3411
  context: "context",
3200
3412
  followOutput: "followOutput",
3201
3413
  itemContent: "itemContent",
@@ -3223,14 +3435,16 @@ const {
3223
3435
  useWindowScroll: "useWindowScroll",
3224
3436
  customScrollParent: "customScrollParent",
3225
3437
  scrollerRef: "scrollerRef",
3226
- logLevel: "logLevel"
3438
+ logLevel: "logLevel",
3439
+ horizontalDirection: "horizontalDirection"
3227
3440
  },
3228
3441
  methods: {
3229
3442
  scrollToIndex: "scrollToIndex",
3230
3443
  scrollIntoView: "scrollIntoView",
3231
3444
  scrollTo: "scrollTo",
3232
3445
  scrollBy: "scrollBy",
3233
- autoscrollToBottom: "autoscrollToBottom"
3446
+ autoscrollToBottom: "autoscrollToBottom",
3447
+ getState: "getState"
3234
3448
  },
3235
3449
  events: {
3236
3450
  isScrolling: "isScrolling",
@@ -3276,9 +3490,10 @@ function buildProbeGridState(items) {
3276
3490
  };
3277
3491
  }
3278
3492
  function buildItems(startIndex, endIndex, data) {
3279
- return Array.from({ length: endIndex - startIndex + 1 }).map(
3280
- (_, i) => ({ index: i + startIndex, data: data == null ? void 0 : data[i + startIndex] })
3281
- );
3493
+ return Array.from({ length: endIndex - startIndex + 1 }).map((_, i) => {
3494
+ const dataItem = data === null ? null : data[i + startIndex];
3495
+ return { index: i + startIndex, data: dataItem };
3496
+ });
3282
3497
  }
3283
3498
  function gapComparator(prev, next) {
3284
3499
  return prev && prev.column === next.column && prev.row === next.row;
@@ -3293,7 +3508,7 @@ const gridSystem = /* @__PURE__ */ system(
3293
3508
  stateFlags,
3294
3509
  scrollSeek,
3295
3510
  { propsReady, didMount },
3296
- { windowViewportRect, windowScrollTo, useWindowScroll, customScrollParent, windowScrollContainerState },
3511
+ { windowViewportRect, useWindowScroll, customScrollParent, windowScrollContainerState, windowScrollTo },
3297
3512
  log
3298
3513
  ]) => {
3299
3514
  const totalCount = statefulStream(0);
@@ -3304,25 +3519,96 @@ const gridSystem = /* @__PURE__ */ system(
3304
3519
  const scrollToIndex = stream();
3305
3520
  const scrollHeight = stream();
3306
3521
  const deviation = statefulStream(0);
3307
- const data = statefulStream(void 0);
3522
+ const data = statefulStream(null);
3308
3523
  const gap = statefulStream({ row: 0, column: 0 });
3309
- connect(
3524
+ const stateChanged = stream();
3525
+ const restoreStateFrom = stream();
3526
+ const stateRestoreInProgress = statefulStream(false);
3527
+ const initialTopMostItemIndex = statefulStream(0);
3528
+ const scrolledToInitialItem = statefulStream(true);
3529
+ const scrollScheduled = statefulStream(false);
3530
+ const horizontalDirection = statefulStream(false);
3531
+ subscribe(
3310
3532
  pipe(
3311
- combineLatest(didMount, initialItemCount, data),
3312
- filter(([, count]) => count !== 0),
3313
- map(([, count, data2]) => {
3314
- return {
3315
- items: buildItems(0, count - 1, data2),
3316
- top: 0,
3317
- bottom: 0,
3318
- offsetBottom: 0,
3319
- offsetTop: 0,
3320
- itemHeight: 0,
3321
- itemWidth: 0
3322
- };
3533
+ didMount,
3534
+ withLatestFrom(initialTopMostItemIndex),
3535
+ filter(([_, location]) => !!location)
3536
+ ),
3537
+ () => {
3538
+ publish(scrolledToInitialItem, false);
3539
+ publish(initialItemCount, 0);
3540
+ }
3541
+ );
3542
+ subscribe(
3543
+ pipe(
3544
+ combineLatest(didMount, scrolledToInitialItem, itemDimensions, viewportDimensions, initialTopMostItemIndex, scrollScheduled),
3545
+ filter(([didMount2, scrolledToInitialItem2, itemDimensions2, viewportDimensions2, , scrollScheduled2]) => {
3546
+ return didMount2 && !scrolledToInitialItem2 && itemDimensions2.height !== 0 && viewportDimensions2.height !== 0 && !scrollScheduled2;
3323
3547
  })
3324
3548
  ),
3325
- gridState
3549
+ ([, , , , initialTopMostItemIndex2]) => {
3550
+ publish(scrollScheduled, true);
3551
+ skipFrames(1, () => {
3552
+ publish(scrollToIndex, initialTopMostItemIndex2);
3553
+ });
3554
+ handleNext(pipe(scrollTop), () => {
3555
+ publish(listBoundary, [0, 0]);
3556
+ publish(scrolledToInitialItem, true);
3557
+ });
3558
+ }
3559
+ );
3560
+ connect(
3561
+ pipe(
3562
+ restoreStateFrom,
3563
+ filter((value) => value !== void 0 && value !== null && value.scrollTop > 0),
3564
+ mapTo(0)
3565
+ ),
3566
+ initialItemCount
3567
+ );
3568
+ subscribe(
3569
+ pipe(
3570
+ didMount,
3571
+ withLatestFrom(restoreStateFrom),
3572
+ filter(([, snapshot]) => snapshot !== void 0 && snapshot !== null)
3573
+ ),
3574
+ ([, snapshot]) => {
3575
+ if (!snapshot) {
3576
+ return;
3577
+ }
3578
+ publish(viewportDimensions, snapshot.viewport), publish(itemDimensions, snapshot == null ? void 0 : snapshot.item);
3579
+ publish(gap, snapshot.gap);
3580
+ if (snapshot.scrollTop > 0) {
3581
+ publish(stateRestoreInProgress, true);
3582
+ handleNext(pipe(scrollTop, skip(1)), (_value) => {
3583
+ publish(stateRestoreInProgress, false);
3584
+ });
3585
+ publish(scrollTo, { top: snapshot.scrollTop });
3586
+ }
3587
+ }
3588
+ );
3589
+ connect(
3590
+ pipe(
3591
+ viewportDimensions,
3592
+ map(({ height }) => height)
3593
+ ),
3594
+ viewportHeight
3595
+ );
3596
+ connect(
3597
+ pipe(
3598
+ combineLatest(
3599
+ duc(viewportDimensions, dimensionComparator),
3600
+ duc(itemDimensions, dimensionComparator),
3601
+ duc(gap, (prev, next) => prev && prev.column === next.column && prev.row === next.row),
3602
+ duc(scrollTop)
3603
+ ),
3604
+ map(([viewport, item, gap2, scrollTop2]) => ({
3605
+ viewport,
3606
+ item,
3607
+ gap: gap2,
3608
+ scrollTop: scrollTop2
3609
+ }))
3610
+ ),
3611
+ stateChanged
3326
3612
  );
3327
3613
  connect(
3328
3614
  pipe(
@@ -3332,65 +3618,104 @@ const gridSystem = /* @__PURE__ */ system(
3332
3618
  duc(gap, gapComparator),
3333
3619
  duc(itemDimensions, dimensionComparator),
3334
3620
  duc(viewportDimensions, dimensionComparator),
3335
- data
3621
+ duc(data),
3622
+ duc(initialItemCount),
3623
+ duc(stateRestoreInProgress),
3624
+ duc(scrolledToInitialItem),
3625
+ duc(initialTopMostItemIndex)
3336
3626
  ),
3337
- map(([totalCount2, [startOffset, endOffset], gap2, item, viewport, data2]) => {
3338
- const { row: rowGap, column: columnGap } = gap2;
3339
- const { height: itemHeight, width: itemWidth } = item;
3340
- const { width: viewportWidth } = viewport;
3341
- if (totalCount2 === 0 || viewportWidth === 0) {
3342
- return INITIAL_GRID_STATE;
3343
- }
3344
- if (itemWidth === 0) {
3345
- return buildProbeGridState(buildItems(0, 0, data2));
3627
+ filter(([, , , , , , , stateRestoreInProgress2]) => {
3628
+ return !stateRestoreInProgress2;
3629
+ }),
3630
+ map(
3631
+ ([
3632
+ totalCount2,
3633
+ [startOffset, endOffset],
3634
+ gap2,
3635
+ item,
3636
+ viewport,
3637
+ data2,
3638
+ initialItemCount2,
3639
+ ,
3640
+ scrolledToInitialItem2,
3641
+ initialTopMostItemIndex2
3642
+ ]) => {
3643
+ const { row: rowGap, column: columnGap } = gap2;
3644
+ const { height: itemHeight, width: itemWidth } = item;
3645
+ const { width: viewportWidth } = viewport;
3646
+ if (initialItemCount2 === 0 && (totalCount2 === 0 || viewportWidth === 0)) {
3647
+ return INITIAL_GRID_STATE;
3648
+ }
3649
+ if (itemWidth === 0) {
3650
+ const startIndex2 = getInitialTopMostItemIndexNumber(initialTopMostItemIndex2, totalCount2);
3651
+ const endIndex2 = startIndex2 === 0 ? Math.max(initialItemCount2 - 1, 0) : startIndex2;
3652
+ return buildProbeGridState(buildItems(startIndex2, endIndex2, data2));
3653
+ }
3654
+ const perRow = itemsPerRow(viewportWidth, itemWidth, columnGap);
3655
+ let startIndex;
3656
+ let endIndex;
3657
+ if (!scrolledToInitialItem2) {
3658
+ startIndex = 0;
3659
+ endIndex = -1;
3660
+ } else if (startOffset === 0 && endOffset === 0 && initialItemCount2 > 0) {
3661
+ startIndex = 0;
3662
+ endIndex = initialItemCount2 - 1;
3663
+ } else {
3664
+ startIndex = perRow * floor((startOffset + rowGap) / (itemHeight + rowGap));
3665
+ endIndex = perRow * ceil((endOffset + rowGap) / (itemHeight + rowGap)) - 1;
3666
+ endIndex = min(totalCount2 - 1, max(endIndex, perRow - 1));
3667
+ startIndex = min(endIndex, max(0, startIndex));
3668
+ }
3669
+ const items = buildItems(startIndex, endIndex, data2);
3670
+ const { top, bottom } = gridLayout(viewport, gap2, item, items);
3671
+ const rowCount = ceil(totalCount2 / perRow);
3672
+ const totalHeight = rowCount * itemHeight + (rowCount - 1) * rowGap;
3673
+ const offsetBottom = totalHeight - bottom;
3674
+ return { items, offsetTop: top, offsetBottom, top, bottom, itemHeight, itemWidth };
3346
3675
  }
3347
- const perRow = itemsPerRow(viewportWidth, itemWidth, columnGap);
3348
- let startIndex = perRow * floor((startOffset + rowGap) / (itemHeight + rowGap));
3349
- let endIndex = perRow * ceil((endOffset + rowGap) / (itemHeight + rowGap)) - 1;
3350
- endIndex = min(totalCount2 - 1, max(endIndex, perRow - 1));
3351
- startIndex = min(endIndex, max(0, startIndex));
3352
- const items = buildItems(startIndex, endIndex, data2);
3353
- const { top, bottom } = gridLayout(viewport, gap2, item, items);
3354
- const rowCount = ceil(totalCount2 / perRow);
3355
- const totalHeight = rowCount * itemHeight + (rowCount - 1) * rowGap;
3356
- const offsetBottom = totalHeight - bottom;
3357
- return { items, offsetTop: top, offsetBottom, top, bottom, itemHeight, itemWidth };
3358
- })
3676
+ )
3359
3677
  ),
3360
3678
  gridState
3361
3679
  );
3362
3680
  connect(
3363
3681
  pipe(
3364
3682
  data,
3365
- filter((data2) => data2 !== void 0),
3683
+ filter((data2) => data2 !== null),
3366
3684
  map((data2) => data2.length)
3367
3685
  ),
3368
3686
  totalCount
3369
3687
  );
3370
- connect(
3371
- pipe(
3372
- viewportDimensions,
3373
- map(({ height }) => height)
3374
- ),
3375
- viewportHeight
3376
- );
3377
3688
  connect(
3378
3689
  pipe(
3379
3690
  combineLatest(viewportDimensions, itemDimensions, gridState, gap),
3380
- map(([viewportDimensions2, item, { items }, gap2]) => {
3381
- const { top, bottom } = gridLayout(viewportDimensions2, gap2, item, items);
3691
+ filter(([viewportDimensions2, itemDimensions2, { items }]) => {
3692
+ return items.length > 0 && itemDimensions2.height !== 0 && viewportDimensions2.height !== 0;
3693
+ }),
3694
+ map(([viewportDimensions2, itemDimensions2, { items }, gap2]) => {
3695
+ const { top, bottom } = gridLayout(viewportDimensions2, gap2, itemDimensions2, items);
3382
3696
  return [top, bottom];
3383
3697
  }),
3384
3698
  distinctUntilChanged(tupleComparator)
3385
3699
  ),
3386
3700
  listBoundary
3387
3701
  );
3702
+ const hasScrolled = statefulStream(false);
3703
+ connect(
3704
+ pipe(
3705
+ scrollTop,
3706
+ withLatestFrom(hasScrolled),
3707
+ map(([scrollTop2, hasScrolled2]) => {
3708
+ return hasScrolled2 || scrollTop2 !== 0;
3709
+ })
3710
+ ),
3711
+ hasScrolled
3712
+ );
3388
3713
  const endReached = streamFromEmitter(
3389
3714
  pipe(
3390
3715
  duc(gridState),
3391
3716
  filter(({ items }) => items.length > 0),
3392
- withLatestFrom(totalCount),
3393
- filter(([{ items }, totalCount2]) => items[items.length - 1].index === totalCount2 - 1),
3717
+ withLatestFrom(totalCount, hasScrolled),
3718
+ filter(([{ items }, totalCount2, hasScrolled2]) => hasScrolled2 && items[items.length - 1].index === totalCount2 - 1),
3394
3719
  map(([, totalCount2]) => totalCount2 - 1),
3395
3720
  distinctUntilChanged()
3396
3721
  )
@@ -3401,6 +3726,7 @@ const gridSystem = /* @__PURE__ */ system(
3401
3726
  filter(({ items }) => {
3402
3727
  return items.length > 0 && items[0].index === 0;
3403
3728
  }),
3729
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
3404
3730
  mapTo(0),
3405
3731
  distinctUntilChanged()
3406
3732
  )
@@ -3408,14 +3734,16 @@ const gridSystem = /* @__PURE__ */ system(
3408
3734
  const rangeChanged = streamFromEmitter(
3409
3735
  pipe(
3410
3736
  duc(gridState),
3411
- filter(({ items }) => items.length > 0),
3412
- map(({ items }) => {
3737
+ withLatestFrom(stateRestoreInProgress),
3738
+ filter(([{ items }, stateRestoreInProgress2]) => items.length > 0 && !stateRestoreInProgress2),
3739
+ map(([{ items }]) => {
3413
3740
  return {
3414
3741
  startIndex: items[0].index,
3415
3742
  endIndex: items[items.length - 1].index
3416
3743
  };
3417
3744
  }),
3418
- distinctUntilChanged(rangeComparator)
3745
+ distinctUntilChanged(rangeComparator),
3746
+ throttleTime(0)
3419
3747
  )
3420
3748
  );
3421
3749
  connect(rangeChanged, scrollSeek.scrollSeekRangeChanged);
@@ -3423,7 +3751,7 @@ const gridSystem = /* @__PURE__ */ system(
3423
3751
  pipe(
3424
3752
  scrollToIndex,
3425
3753
  withLatestFrom(viewportDimensions, itemDimensions, totalCount, gap),
3426
- map(([location, viewport, item, totalCount2, gap2]) => {
3754
+ map(([location, viewportDimensions2, itemDimensions2, totalCount2, gap2]) => {
3427
3755
  const normalLocation = normalizeIndexLocation(location);
3428
3756
  const { align, behavior, offset } = normalLocation;
3429
3757
  let index = normalLocation.index;
@@ -3431,11 +3759,11 @@ const gridSystem = /* @__PURE__ */ system(
3431
3759
  index = totalCount2 - 1;
3432
3760
  }
3433
3761
  index = max(0, index, min(totalCount2 - 1, index));
3434
- let top = itemTop(viewport, gap2, item, index);
3762
+ let top = itemTop(viewportDimensions2, gap2, itemDimensions2, index);
3435
3763
  if (align === "end") {
3436
- top = round(top - viewport.height + item.height);
3764
+ top = round(top - viewportDimensions2.height + itemDimensions2.height);
3437
3765
  } else if (align === "center") {
3438
- top = round(top - viewport.height / 2 + item.height / 2);
3766
+ top = round(top - viewportDimensions2.height / 2 + itemDimensions2.height / 2);
3439
3767
  }
3440
3768
  if (offset) {
3441
3769
  top += offset;
@@ -3462,6 +3790,7 @@ const gridSystem = /* @__PURE__ */ system(
3462
3790
  viewportDimensions
3463
3791
  );
3464
3792
  return {
3793
+ // input
3465
3794
  data,
3466
3795
  totalCount,
3467
3796
  viewportDimensions,
@@ -3484,14 +3813,20 @@ const gridSystem = /* @__PURE__ */ system(
3484
3813
  headerHeight,
3485
3814
  initialItemCount,
3486
3815
  gap,
3816
+ restoreStateFrom,
3487
3817
  ...scrollSeek,
3818
+ initialTopMostItemIndex,
3819
+ horizontalDirection,
3820
+ // output
3488
3821
  gridState,
3489
3822
  totalListHeight,
3490
3823
  ...stateFlags,
3491
3824
  startReached,
3492
3825
  endReached,
3493
3826
  rangeChanged,
3827
+ stateChanged,
3494
3828
  propsReady,
3829
+ stateRestoreInProgress,
3495
3830
  ...log
3496
3831
  };
3497
3832
  },
@@ -3513,7 +3848,7 @@ function itemTop(viewport, gap, item, index) {
3513
3848
  return top > 0 ? top + gap.row : top;
3514
3849
  }
3515
3850
  function itemsPerRow(viewportWidth, itemWidth, gap) {
3516
- return max(1, floor((viewportWidth + gap) / (itemWidth + gap)));
3851
+ return max(1, floor((viewportWidth + gap) / (floor(itemWidth) + gap)));
3517
3852
  }
3518
3853
  const gridComponentPropsSystem = /* @__PURE__ */ system(() => {
3519
3854
  const itemContent = statefulStream((index) => `Item ${index}`);
@@ -3569,18 +3904,23 @@ const GridItems = /* @__PURE__ */ React.memo(function GridItems2() {
3569
3904
  const itemDimensions = usePublisher$1("itemDimensions");
3570
3905
  const gridGap = usePublisher$1("gap");
3571
3906
  const log = useEmitterValue$1("log");
3907
+ const stateRestoreInProgress = useEmitterValue$1("stateRestoreInProgress");
3572
3908
  const listRef = useSize((el) => {
3573
3909
  const scrollHeight = el.parentElement.parentElement.scrollHeight;
3574
3910
  scrollHeightCallback(scrollHeight);
3575
3911
  const firstItem = el.firstChild;
3576
3912
  if (firstItem) {
3577
- itemDimensions(firstItem.getBoundingClientRect());
3913
+ const { width, height } = firstItem.getBoundingClientRect();
3914
+ itemDimensions({ width, height });
3578
3915
  }
3579
3916
  gridGap({
3580
3917
  row: resolveGapValue("row-gap", getComputedStyle(el).rowGap, log),
3581
3918
  column: resolveGapValue("column-gap", getComputedStyle(el).columnGap, log)
3582
3919
  });
3583
3920
  });
3921
+ if (stateRestoreInProgress) {
3922
+ return null;
3923
+ }
3584
3924
  return React.createElement(
3585
3925
  ListComponent,
3586
3926
  {
@@ -3588,7 +3928,7 @@ const GridItems = /* @__PURE__ */ React.memo(function GridItems2() {
3588
3928
  className: listClassName,
3589
3929
  ...contextPropIfNotDomElement(ListComponent, context),
3590
3930
  style: { paddingTop: gridState.offsetTop, paddingBottom: gridState.offsetBottom },
3591
- "data-test-id": "virtuoso-item-list"
3931
+ "data-testid": "virtuoso-item-list"
3592
3932
  },
3593
3933
  gridState.items.map((item) => {
3594
3934
  const key = computeItemKey(item.index, item.data, context);
@@ -3635,7 +3975,7 @@ const Viewport$1 = ({ children }) => {
3635
3975
  itemDimensions({ height: ctx.itemHeight, width: ctx.itemWidth });
3636
3976
  }
3637
3977
  }, [ctx, viewportDimensions, itemDimensions]);
3638
- return /* @__PURE__ */ React.createElement("div", { style: viewportStyle, ref: viewportRef }, children);
3978
+ return /* @__PURE__ */ React.createElement("div", { style: viewportStyle(false), ref: viewportRef }, children);
3639
3979
  };
3640
3980
  const WindowViewport$1 = ({ children }) => {
3641
3981
  const ctx = React.useContext(VirtuosoGridMockContext);
@@ -3649,7 +3989,7 @@ const WindowViewport$1 = ({ children }) => {
3649
3989
  windowViewportRect({ offsetTop: 0, visibleHeight: ctx.viewportHeight, visibleWidth: ctx.viewportWidth });
3650
3990
  }
3651
3991
  }, [ctx, windowViewportRect, itemDimensions]);
3652
- return /* @__PURE__ */ React.createElement("div", { ref: viewportRef, style: viewportStyle }, children);
3992
+ return /* @__PURE__ */ React.createElement("div", { ref: viewportRef, style: viewportStyle(false) }, children);
3653
3993
  };
3654
3994
  const GridRoot = /* @__PURE__ */ React.memo(function GridRoot2({ ...props }) {
3655
3995
  const useWindowScroll = useEmitterValue$1("useWindowScroll");
@@ -3681,7 +4021,10 @@ const {
3681
4021
  itemClassName: "itemClassName",
3682
4022
  useWindowScroll: "useWindowScroll",
3683
4023
  customScrollParent: "customScrollParent",
3684
- scrollerRef: "scrollerRef"
4024
+ scrollerRef: "scrollerRef",
4025
+ logLevel: "logLevel",
4026
+ restoreStateFrom: "restoreStateFrom",
4027
+ initialTopMostItemIndex: "initialTopMostItemIndex"
3685
4028
  },
3686
4029
  methods: {
3687
4030
  scrollTo: "scrollTo",
@@ -3694,7 +4037,8 @@ const {
3694
4037
  startReached: "startReached",
3695
4038
  rangeChanged: "rangeChanged",
3696
4039
  atBottomStateChange: "atBottomStateChange",
3697
- atTopStateChange: "atTopStateChange"
4040
+ atTopStateChange: "atTopStateChange",
4041
+ stateChanged: "stateChanged"
3698
4042
  }
3699
4043
  },
3700
4044
  GridRoot
@@ -3708,7 +4052,7 @@ function resolveGapValue(property, value, log) {
3708
4052
  if (value === "normal") {
3709
4053
  return 0;
3710
4054
  }
3711
- return parseInt(value ?? "0", 10);
4055
+ return parseInt(value != null ? value : "0", 10);
3712
4056
  }
3713
4057
  const VirtuosoGrid = Grid;
3714
4058
  const tableComponentPropsSystem = /* @__PURE__ */ system(() => {
@@ -3753,6 +4097,7 @@ const combinedSystem = /* @__PURE__ */ system(([listSystem2, propsSystem]) => {
3753
4097
  }, tup(listSystem, tableComponentPropsSystem));
3754
4098
  const DefaultScrollSeekPlaceholder = ({ height }) => /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("td", { style: { height } }));
3755
4099
  const DefaultFillerRow = ({ height }) => /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("td", { style: { height, padding: 0, border: 0 } }));
4100
+ const ITEM_STYLE = { overflowAnchor: "none" };
3756
4101
  const Items = /* @__PURE__ */ React.memo(function VirtuosoItems2() {
3757
4102
  const listState = useEmitterValue("listState");
3758
4103
  const sizeRanges = usePublisher("sizeRanges");
@@ -3815,19 +4160,19 @@ const Items = /* @__PURE__ */ React.memo(function VirtuosoItems2() {
3815
4160
  TableRowComponent,
3816
4161
  {
3817
4162
  ...contextPropIfNotDomElement(TableRowComponent, context),
4163
+ ...itemPropIfNotDomElement(TableRowComponent, item.data),
3818
4164
  key,
3819
4165
  "data-index": index,
3820
4166
  "data-known-size": item.size,
3821
4167
  "data-item-index": item.index,
3822
- item: item.data,
3823
- style: { overflowAnchor: "none" }
4168
+ style: ITEM_STYLE
3824
4169
  },
3825
4170
  itemContent(item.index, item.data, context)
3826
4171
  );
3827
4172
  });
3828
4173
  return React.createElement(
3829
4174
  TableBodyComponent,
3830
- { ref: callbackRef, "data-test-id": "virtuoso-item-list", ...contextPropIfNotDomElement(TableBodyComponent, context) },
4175
+ { ref: callbackRef, "data-testid": "virtuoso-item-list", ...contextPropIfNotDomElement(TableBodyComponent, context) },
3831
4176
  [paddingTopEl, ...items, paddingBottomEl]
3832
4177
  );
3833
4178
  });
@@ -3842,7 +4187,7 @@ const Viewport = ({ children }) => {
3842
4187
  fixedItemHeight(ctx.itemHeight);
3843
4188
  }
3844
4189
  }, [ctx, viewportHeight, fixedItemHeight]);
3845
- return /* @__PURE__ */ React.createElement("div", { style: viewportStyle, ref: viewportRef, "data-viewport-type": "element" }, children);
4190
+ return /* @__PURE__ */ React.createElement("div", { style: viewportStyle(false), ref: viewportRef, "data-viewport-type": "element" }, children);
3846
4191
  };
3847
4192
  const WindowViewport = ({ children }) => {
3848
4193
  const ctx = React.useContext(VirtuosoMockContext);
@@ -3856,7 +4201,7 @@ const WindowViewport = ({ children }) => {
3856
4201
  windowViewportRect({ offsetTop: 0, visibleHeight: ctx.viewportHeight, visibleWidth: 100 });
3857
4202
  }
3858
4203
  }, [ctx, windowViewportRect, fixedItemHeight]);
3859
- return /* @__PURE__ */ React.createElement("div", { ref: viewportRef, style: viewportStyle, "data-viewport-type": "window" }, children);
4204
+ return /* @__PURE__ */ React.createElement("div", { ref: viewportRef, style: viewportStyle(false), "data-viewport-type": "window" }, children);
3860
4205
  };
3861
4206
  const TableRoot = /* @__PURE__ */ React.memo(function TableVirtuosoRoot(props) {
3862
4207
  const useWindowScroll = useEmitterValue("useWindowScroll");
@@ -3877,7 +4222,7 @@ const TableRoot = /* @__PURE__ */ React.memo(function TableVirtuosoRoot(props) {
3877
4222
  TheTHead,
3878
4223
  {
3879
4224
  key: "TableHead",
3880
- style: { zIndex: 1, position: "sticky", top: 0 },
4225
+ style: { zIndex: 2, position: "sticky", top: 0 },
3881
4226
  ref: theadRef,
3882
4227
  ...contextPropIfNotDomElement(TheTHead, context)
3883
4228
  },
@@ -3893,11 +4238,11 @@ const TableRoot = /* @__PURE__ */ React.memo(function TableVirtuosoRoot(props) {
3893
4238
  },
3894
4239
  fixedFooterContent()
3895
4240
  ) : null;
3896
- return /* @__PURE__ */ React.createElement(TheScroller, { ...props }, /* @__PURE__ */ React.createElement(TheViewport, null, React.createElement(TheTable, { style: { borderSpacing: 0 }, ...contextPropIfNotDomElement(TheTable, context) }, [
3897
- theHead,
3898
- /* @__PURE__ */ React.createElement(Items, { key: "TableBody" }),
3899
- theFoot
3900
- ])));
4241
+ return /* @__PURE__ */ React.createElement(TheScroller, { ...props }, /* @__PURE__ */ React.createElement(TheViewport, null, React.createElement(
4242
+ TheTable,
4243
+ { style: { borderSpacing: 0, overflowAnchor: "none" }, ...contextPropIfNotDomElement(TheTable, context) },
4244
+ [theHead, /* @__PURE__ */ React.createElement(Items, { key: "TableBody" }), theFoot]
4245
+ )));
3901
4246
  });
3902
4247
  const {
3903
4248
  Component: Table,
@@ -3909,6 +4254,7 @@ const {
3909
4254
  {
3910
4255
  required: {},
3911
4256
  optional: {
4257
+ restoreStateFrom: "restoreStateFrom",
3912
4258
  context: "context",
3913
4259
  followOutput: "followOutput",
3914
4260
  firstItemIndex: "firstItemIndex",
@@ -3942,7 +4288,8 @@ const {
3942
4288
  scrollToIndex: "scrollToIndex",
3943
4289
  scrollIntoView: "scrollIntoView",
3944
4290
  scrollTo: "scrollTo",
3945
- scrollBy: "scrollBy"
4291
+ scrollBy: "scrollBy",
4292
+ getState: "getState"
3946
4293
  },
3947
4294
  events: {
3948
4295
  isScrolling: "isScrolling",