virtua 0.50.6 → 0.51.0

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.
@@ -34,7 +34,6 @@ var once = (fn) => {
34
34
  //#endregion
35
35
  //#region src/core/environment.ts
36
36
  var isBrowser = typeof window !== "undefined";
37
- var getDocumentElement = (doc) => doc.documentElement;
38
37
  var getCurrentDocument = (node) => node.ownerDocument;
39
38
  var getCurrentWindow = (doc) => doc.defaultView;
40
39
  var isIOSWebKit = /*#__PURE__*/ once(() => {
@@ -43,9 +42,6 @@ var isIOSWebKit = /*#__PURE__*/ once(() => {
43
42
  }
44
43
  return navigator.platform === "MacIntel" && navigator.maxTouchPoints > 0;
45
44
  });
46
- var isSmoothScrollSupported = /*#__PURE__*/ once(() => {
47
- return "scrollBehavior" in getDocumentElement(document).style;
48
- });
49
45
 
50
46
  //#endregion
51
47
  //#region src/core/store.ts
@@ -90,12 +86,8 @@ var createVirtualStore = ({ $getRange: getRange, $findIndex: findIndex, $getItem
90
86
  const subscribers = new Set();
91
87
  const getRelativeScrollOffset = () => scrollOffset - startSpacerSize;
92
88
  const getVisibleOffset = () => getRelativeScrollOffset() + pendingJump + jump;
93
- const getItemOffset = (index, fromEnd) => {
94
- const offset = getOffset(index) - pendingJump;
95
- if (fromEnd) {
96
- return getTotalSize() - offset - getItemSize(index);
97
- }
98
- return offset;
89
+ const getItemOffset = (index) => {
90
+ return getOffset(index) - pendingJump;
99
91
  };
100
92
  const applyJump = (j) => {
101
93
  if (j) {
@@ -518,7 +510,6 @@ var createScrollScheduler = (store, initialized, scroll) => {
518
510
  let stopped;
519
511
  let timerId;
520
512
  let unsubscribe;
521
- const isSmooth = smooth && isSmoothScrollSupported();
522
513
  const stop = cancelScroll = () => {
523
514
  stopped = true;
524
515
  cancelTimeout(timerId);
@@ -532,7 +523,7 @@ var createScrollScheduler = (store, initialized, scroll) => {
532
523
  cancelTimeout(timerId);
533
524
  timerId = timeout(stop, 150);
534
525
  }
535
- if (isSmooth) {
526
+ if (smooth) {
536
527
  for (let [i, end] = store.$getRange(0); i <= end; i++) {
537
528
  if (store.$isUnmeasuredItem(i)) {
538
529
  return;
@@ -541,7 +532,7 @@ var createScrollScheduler = (store, initialized, scroll) => {
541
532
  stop();
542
533
  }
543
534
  store.$update(7);
544
- scroll(getTargetOffset(), isSmooth);
535
+ scroll(getTargetOffset(), smooth);
545
536
  };
546
537
  const start = () => {
547
538
  if (stopped) {
@@ -560,7 +551,7 @@ var createScrollScheduler = (store, initialized, scroll) => {
560
551
  });
561
552
  onMeasured();
562
553
  };
563
- if (isSmooth) {
554
+ if (smooth) {
564
555
  store.$update(8, getTargetOffset());
565
556
  microtask(start);
566
557
  } else {
@@ -574,19 +565,15 @@ var createContainerDriver = (store, isHorizontal) => {
574
565
  let viewportElement;
575
566
  let scrollObserver;
576
567
  let initialized = createPromise();
577
- let isNegative = false;
568
+ let isRtl = false;
578
569
  const scrollOffsetKey = isHorizontal ? "scrollLeft" : "scrollTop";
570
+ const scrollToKey = isHorizontal ? "left" : "top";
579
571
  const overflowKey = isHorizontal ? "overflowX" : "overflowY";
580
572
  const [scheduleScroll, cancelScroll] = createScrollScheduler(store, () => initialized[0], (offset, smooth) => {
581
- offset = normalizeScrollOffset(offset, isNegative);
582
- if (smooth) {
583
- viewportElement.scrollTo({
584
- [isHorizontal ? "left" : "top"]: offset,
585
- behavior: "smooth"
586
- });
587
- } else {
588
- viewportElement[scrollOffsetKey] = offset;
589
- }
573
+ viewportElement.scrollTo({
574
+ [scrollToKey]: normalizeScrollOffset(offset, isRtl),
575
+ behavior: smooth ? "smooth" : "instant"
576
+ });
590
577
  });
591
578
  const sizeKey = isHorizontal ? "width" : "height";
592
579
  const mountedIndexes = new WeakMap();
@@ -611,9 +598,9 @@ var createContainerDriver = (store, isHorizontal) => {
611
598
  $observe(containerElement, viewport = containerElement.parentElement) {
612
599
  resizeObserver._observe(viewportElement = viewport);
613
600
  if (isHorizontal) {
614
- isNegative = getComputedStyle(viewport).direction === "rtl";
601
+ isRtl = getComputedStyle(viewport).direction === "rtl";
615
602
  }
616
- scrollObserver = createScrollObserver(store, viewport, isHorizontal, () => normalizeScrollOffset(viewport[scrollOffsetKey], isNegative), (jump, shift, isMomentumScrolling) => {
603
+ scrollObserver = createScrollObserver(store, viewport, isHorizontal, () => normalizeScrollOffset(viewport[scrollOffsetKey], isRtl), (jump, shift, isMomentumScrolling) => {
617
604
  if (isMomentumScrolling) {
618
605
  const style = viewport.style;
619
606
  const prev = style[overflowKey];
@@ -622,7 +609,18 @@ var createContainerDriver = (store, isHorizontal) => {
622
609
  style[overflowKey] = prev;
623
610
  });
624
611
  }
625
- viewport[scrollOffsetKey] = normalizeScrollOffset(store.$getScrollOffset() + jump, isNegative);
612
+ const target = store.$getScrollOffset() + jump;
613
+ if (target <= 0 || target >= store.$getStartSpacerSize() + store.$getTotalSize() - store.$getViewportSize()) {
614
+ viewport.scrollTo({
615
+ [scrollToKey]: normalizeScrollOffset(target, isRtl),
616
+ behavior: "instant"
617
+ });
618
+ } else {
619
+ viewport.scrollBy({
620
+ [scrollToKey]: normalizeScrollOffset(jump, isRtl),
621
+ behavior: "instant"
622
+ });
623
+ }
626
624
  if (shift) {
627
625
  cancelScroll();
628
626
  }
@@ -643,39 +641,38 @@ var createContainerDriver = (store, isHorizontal) => {
643
641
  resizeObserver._unobserve(el);
644
642
  };
645
643
  },
646
- $isNegative: () => isNegative,
647
644
  $scroll: scheduleScroll,
648
645
  $effect() {
649
646
  scrollObserver && scrollObserver._fixScrollJump();
650
647
  },
651
- $getBaseOffset: store.$getStartSpacerSize,
652
- $getScrollbarSize: () => 0
648
+ $getBaseOffset: store.$getStartSpacerSize
653
649
  };
654
650
  };
655
651
  var createWindowDriver = (store, isHorizontal) => {
656
- let containerElement;
652
+ let viewportElement;
657
653
  let scrollObserver;
658
654
  let cleanupOnWindowResize;
655
+ let getBaseOffset;
656
+ let onViewportResize;
659
657
  let initialized = createPromise();
660
- let isNegative = false;
658
+ let isRtl = false;
659
+ const scrollOffsetKey = isHorizontal ? "scrollLeft" : "scrollTop";
661
660
  const scrollToKey = isHorizontal ? "left" : "top";
662
- const [scheduleScroll] = createScrollScheduler(store, () => initialized[0], (offset, smooth) => {
663
- offset = normalizeScrollOffset(offset, isNegative);
664
- const window = getCurrentWindow(getCurrentDocument(containerElement));
665
- if (smooth) {
666
- window.scroll({
667
- [scrollToKey]: offset,
668
- behavior: "smooth"
669
- });
670
- } else {
671
- window.scroll({ [scrollToKey]: offset });
672
- }
661
+ const [scheduleScroll, cancelScroll] = createScrollScheduler(store, () => initialized[0], (offset, smooth) => {
662
+ viewportElement.scrollTo({
663
+ [scrollToKey]: normalizeScrollOffset(offset, isRtl),
664
+ behavior: smooth ? "smooth" : "instant"
665
+ });
673
666
  });
674
667
  const sizeKey = isHorizontal ? "width" : "height";
675
668
  const mountedIndexes = new WeakMap();
676
669
  const resizeObserver = createResizeObserver((entries) => {
677
670
  const resizes = [];
678
671
  for (const { target, contentRect } of entries) {
672
+ if (target === viewportElement) {
673
+ onViewportResize && onViewportResize();
674
+ continue;
675
+ }
679
676
  if (!target.offsetParent) continue;
680
677
  const index = mountedIndexes.get(target);
681
678
  if (index != null) {
@@ -686,46 +683,58 @@ var createWindowDriver = (store, isHorizontal) => {
686
683
  store.$update(3, resizes);
687
684
  }
688
685
  });
689
- const calcOffsetToViewport = (node, viewport, window, isHorizontal, offset = 0) => {
686
+ const calcOffsetToViewport = (node, viewport, until, isHorizontal, offset = 0) => {
690
687
  const offsetKey = isHorizontal ? "offsetLeft" : "offsetTop";
691
- const offsetSum = offset + (isHorizontal && isNegative ? window.innerWidth - node[offsetKey] - node.offsetWidth : node[offsetKey]);
688
+ const offsetSum = offset + (isRtl ? viewport.clientWidth - node[offsetKey] - node.offsetWidth : node[offsetKey]);
692
689
  const parent = node.offsetParent;
693
- if (node === viewport || !parent) {
690
+ if (node === until || !parent) {
694
691
  return offsetSum;
695
692
  }
696
- return calcOffsetToViewport(parent, viewport, window, isHorizontal, offsetSum);
693
+ return calcOffsetToViewport(parent, viewport, until, isHorizontal, offsetSum);
697
694
  };
698
695
  return {
699
696
  $observe(container) {
700
- containerElement = container;
701
- const scrollOffsetKey = isHorizontal ? "scrollX" : "scrollY";
702
697
  const document = getCurrentDocument(container);
703
698
  const window = getCurrentWindow(document);
704
- const onWindowResize = () => {
705
- store.$update(4, window[isHorizontal ? "innerWidth" : "innerHeight"]);
699
+ const viewport = viewportElement = document.scrollingElement;
700
+ const baseOffset = getBaseOffset = () => {
701
+ return calcOffsetToViewport(container, viewport, document.body, isHorizontal);
702
+ };
703
+ const onWindowResize = onViewportResize = () => {
704
+ store.$update(4, viewport[isHorizontal ? "clientWidth" : "clientHeight"]);
706
705
  };
707
706
  window.addEventListener("resize", onWindowResize);
708
- microtask(onWindowResize);
707
+ resizeObserver._observe(viewport);
709
708
  cleanupOnWindowResize = () => {
710
709
  window.removeEventListener("resize", onWindowResize);
711
710
  };
712
711
  if (isHorizontal) {
713
- isNegative = getComputedStyle(getDocumentElement(document)).direction === "rtl";
712
+ isRtl = getComputedStyle(viewport).direction === "rtl";
714
713
  }
715
- scrollObserver = createScrollObserver(store, window, isHorizontal, () => normalizeScrollOffset(window[scrollOffsetKey], isNegative), (jump, shift) => {
716
- if (shift) {
717
- window.scroll({ [scrollToKey]: normalizeScrollOffset(store.$getScrollOffset() + jump, isNegative) });
714
+ scrollObserver = createScrollObserver(store, window, isHorizontal, () => normalizeScrollOffset(viewport[scrollOffsetKey], isRtl), (jump, shift) => {
715
+ const target = store.$getScrollOffset() + jump;
716
+ if (target <= 0 || target >= store.$getStartSpacerSize() + store.$getTotalSize() - store.$getViewportSize()) {
717
+ viewport.scrollTo({
718
+ [scrollToKey]: normalizeScrollOffset(target, isRtl),
719
+ behavior: "instant"
720
+ });
718
721
  } else {
719
- window.scrollBy({ [scrollToKey]: normalizeScrollOffset(jump, isNegative) });
722
+ viewport.scrollBy({
723
+ [scrollToKey]: normalizeScrollOffset(jump, isRtl),
724
+ behavior: "instant"
725
+ });
720
726
  }
721
- }, () => calcOffsetToViewport(container, document.body, window, isHorizontal));
727
+ if (shift) {
728
+ cancelScroll();
729
+ }
730
+ }, baseOffset);
722
731
  initialized[1](true);
723
732
  },
724
733
  $dispose() {
725
734
  cleanupOnWindowResize && cleanupOnWindowResize();
726
735
  resizeObserver._dispose();
727
736
  scrollObserver && scrollObserver._dispose();
728
- containerElement = undefined;
737
+ viewportElement = undefined;
729
738
  initialized[1](false);
730
739
  initialized = createPromise();
731
740
  },
@@ -737,18 +746,12 @@ var createWindowDriver = (store, isHorizontal) => {
737
746
  resizeObserver._unobserve(el);
738
747
  };
739
748
  },
740
- $isNegative: () => isNegative,
741
749
  $scroll: scheduleScroll,
742
750
  $effect() {
743
751
  scrollObserver && scrollObserver._fixScrollJump();
744
752
  },
745
753
  $getBaseOffset() {
746
- const document = getCurrentDocument(containerElement);
747
- return calcOffsetToViewport(containerElement, document.body, getCurrentWindow(document), isHorizontal);
748
- },
749
- $getScrollbarSize() {
750
- const html = getDocumentElement(getCurrentDocument(containerElement));
751
- return store.$getViewportSize() - (isHorizontal ? html.clientWidth : html.clientHeight);
754
+ return getBaseOffset();
752
755
  }
753
756
  };
754
757
  };
@@ -757,20 +760,18 @@ var createContainerGridDriver = (rowStore, colStore) => {
757
760
  let rowScrollObserver;
758
761
  let colScrollObserver;
759
762
  let initialized = createPromise();
760
- let isNegative = false;
763
+ let isRtl = false;
761
764
  const [scheduleScrollX, cancelScrollX] = createScrollScheduler(colStore, () => initialized[0], (offset, smooth) => {
762
- const opts = { left: normalizeScrollOffset(offset, isNegative) };
763
- if (smooth) {
764
- opts.behavior = "smooth";
765
- }
766
- viewportElement.scrollTo(opts);
765
+ viewportElement.scrollTo({
766
+ left: normalizeScrollOffset(offset, isRtl),
767
+ behavior: smooth ? "smooth" : "instant"
768
+ });
767
769
  });
768
770
  const [scheduleScrollY, cancelScrollY] = createScrollScheduler(rowStore, () => initialized[0], (offset, smooth) => {
769
- const opts = { top: offset };
770
- if (smooth) {
771
- opts.behavior = "smooth";
772
- }
773
- viewportElement.scrollTo(opts);
771
+ viewportElement.scrollTo({
772
+ top: offset,
773
+ behavior: smooth ? "smooth" : "instant"
774
+ });
774
775
  });
775
776
  const mountedIndexes = new WeakMap();
776
777
  const maybeCachedRowIndexes = new Set();
@@ -852,8 +853,8 @@ var createContainerGridDriver = (rowStore, colStore) => {
852
853
  const viewport = viewportElement;
853
854
  const scrollOffsetKey = isHorizontal ? "scrollLeft" : "scrollTop";
854
855
  const overflowKey = isHorizontal ? "overflowX" : "overflowY";
855
- const negative = isHorizontal && isNegative;
856
- return createScrollObserver(store, viewport, isHorizontal, () => normalizeScrollOffset(viewport[scrollOffsetKey], negative), (jump, shift, isMomentumScrolling) => {
856
+ const rtl = isHorizontal && isRtl;
857
+ return createScrollObserver(store, viewport, isHorizontal, () => normalizeScrollOffset(viewport[scrollOffsetKey], rtl), (jump, shift, isMomentumScrolling) => {
857
858
  if (isMomentumScrolling) {
858
859
  const style = viewport.style;
859
860
  const prev = style[overflowKey];
@@ -862,7 +863,18 @@ var createContainerGridDriver = (rowStore, colStore) => {
862
863
  style[overflowKey] = prev;
863
864
  });
864
865
  }
865
- viewport[scrollOffsetKey] = normalizeScrollOffset(store.$getScrollOffset() + jump, negative);
866
+ const target = store.$getScrollOffset() + jump;
867
+ if (target <= 0 || target >= store.$getStartSpacerSize() + store.$getTotalSize() - store.$getViewportSize()) {
868
+ viewport.scrollTo({
869
+ [isHorizontal ? "left" : "top"]: normalizeScrollOffset(target, rtl),
870
+ behavior: "instant"
871
+ });
872
+ } else {
873
+ viewport.scrollBy({
874
+ [isHorizontal ? "left" : "top"]: normalizeScrollOffset(jump, rtl),
875
+ behavior: "instant"
876
+ });
877
+ }
866
878
  if (shift) {
867
879
  cancelScroll();
868
880
  }
@@ -871,7 +883,7 @@ var createContainerGridDriver = (rowStore, colStore) => {
871
883
  return {
872
884
  $observe(containerElement, viewport = containerElement.parentElement) {
873
885
  resizeObserver._observe(viewportElement = viewport);
874
- isNegative = getComputedStyle(viewport).direction === "rtl";
886
+ isRtl = getComputedStyle(viewport).direction === "rtl";
875
887
  rowScrollObserver = observeAxisScroll(rowStore, false, cancelScrollY);
876
888
  colScrollObserver = observeAxisScroll(colStore, true, cancelScrollX);
877
889
  initialized[1](true);
@@ -909,7 +921,6 @@ var createContainerGridDriver = (rowStore, colStore) => {
909
921
  }
910
922
  colStore.$update(3, cols);
911
923
  },
912
- $isNegative: () => isNegative,
913
924
  $scrollX: scheduleScrollX,
914
925
  $scrollY: scheduleScrollY,
915
926
  $effect() {
@@ -941,7 +952,7 @@ var scrollToIndex = (driver, store, index, { align, smooth, offset = 0 } = {}) =
941
952
  }
942
953
  }
943
954
  driver.$scroll(() => {
944
- return offset + driver.$getBaseOffset() + store.$getItemOffset(index) + (align === "end" ? store.$getItemSize(index) - (store.$getViewportSize() - driver.$getScrollbarSize()) : align === "center" ? (store.$getItemSize(index) - (store.$getViewportSize() - driver.$getScrollbarSize())) / 2 : 0);
955
+ return offset + driver.$getBaseOffset() + store.$getItemOffset(index) + (align === "end" ? store.$getItemSize(index) - store.$getViewportSize() : align === "center" ? (store.$getItemSize(index) - store.$getViewportSize()) / 2 : 0);
945
956
  }, smooth);
946
957
  };
947
958
  var gridScrollTo = (driver, row, col) => {
@@ -991,7 +1002,7 @@ var ListItem = (props) => {
991
1002
  position: hide && isSSR ? undefined : "absolute",
992
1003
  [isHorizontal ? "height" : "width"]: "100%",
993
1004
  [isHorizontal ? "top" : "left"]: "0px",
994
- [isHorizontal ? "left" : "top"]: props._offset + "px",
1005
+ [isHorizontal ? "inset-inline-start" : "top"]: props._offset + "px",
995
1006
  visibility: !hide || isSSR ? undefined : "hidden"
996
1007
  };
997
1008
  if (isHorizontal) {
@@ -1040,7 +1051,6 @@ var Virtualizer = (props) => {
1040
1051
  });
1041
1052
  const isScrolling = createMemo(() => stateVersion() && store.$isScrolling());
1042
1053
  const totalSize = createMemo(() => stateVersion() && store.$getTotalSize());
1043
- const isNegative = createMemo(() => stateVersion() && driver.$isNegative());
1044
1054
  onMount(() => {
1045
1055
  setIsSSR(false);
1046
1056
  if (props.ref) {
@@ -1114,7 +1124,7 @@ var Virtualizer = (props) => {
1114
1124
  const renderItem = (data, index) => {
1115
1125
  const offset = createMemo(() => {
1116
1126
  stateVersion();
1117
- return store.$getItemOffset(index(), isNegative());
1127
+ return store.$getItemOffset(index());
1118
1128
  });
1119
1129
  const hide = createMemo(() => {
1120
1130
  stateVersion();
@@ -1205,7 +1215,6 @@ var WindowVirtualizer = (props) => {
1205
1215
  });
1206
1216
  const isScrolling = createMemo(() => stateVersion() && store.$isScrolling());
1207
1217
  const totalSize = createMemo(() => stateVersion() && store.$getTotalSize());
1208
- const isNegative = createMemo(() => stateVersion() && driver.$isNegative());
1209
1218
  onMount(() => {
1210
1219
  setIsSSR(false);
1211
1220
  if (props.ref) {
@@ -1264,7 +1273,7 @@ var WindowVirtualizer = (props) => {
1264
1273
  const itemIndex = createMemo(() => range()[0] + index());
1265
1274
  const offset = createMemo(() => {
1266
1275
  stateVersion();
1267
- return store.$getItemOffset(itemIndex(), isNegative());
1276
+ return store.$getItemOffset(itemIndex());
1268
1277
  });
1269
1278
  const hide = createMemo(() => {
1270
1279
  stateVersion();