virtua 0.43.5 → 0.44.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.
Files changed (57) hide show
  1. package/lib/core/index.cjs +2 -0
  2. package/lib/core/index.cjs.map +1 -0
  3. package/lib/core/index.d.ts +6 -6
  4. package/lib/core/index.js +1 -1
  5. package/lib/core/index.js.map +1 -1
  6. package/lib/index.cjs +3 -0
  7. package/lib/index.cjs.map +1 -0
  8. package/lib/index.d.ts +2 -2
  9. package/lib/index.js +1 -1
  10. package/lib/index.js.map +1 -1
  11. package/lib/react/VGrid.d.ts +1 -1
  12. package/lib/react/VList.d.ts +2 -2
  13. package/lib/react/Virtualizer.d.ts +2 -2
  14. package/lib/react/WindowVirtualizer.d.ts +2 -2
  15. package/lib/react/index.d.ts +9 -9
  16. package/lib/solid/VList.d.ts +2 -2
  17. package/lib/solid/Virtualizer.d.ts +1 -1
  18. package/lib/solid/WindowVirtualizer.d.ts +1 -1
  19. package/lib/solid/index.cjs +2 -0
  20. package/lib/solid/index.cjs.map +1 -0
  21. package/lib/solid/index.d.ts +7 -7
  22. package/lib/solid/index.js +1 -1
  23. package/lib/solid/index.js.map +1 -1
  24. package/lib/solid/index.jsx +90 -80
  25. package/lib/solid/index.jsx.map +1 -1
  26. package/lib/svelte/ListItem.svelte +2 -2
  27. package/lib/svelte/VList.svelte +2 -2
  28. package/lib/svelte/VList.type.d.ts +2 -2
  29. package/lib/svelte/VList.type.js +2 -1
  30. package/lib/svelte/Virtualizer.svelte +3 -3
  31. package/lib/svelte/Virtualizer.type.d.ts +1 -1
  32. package/lib/svelte/Virtualizer.type.js +2 -1
  33. package/lib/svelte/WindowVirtualizer.svelte +3 -3
  34. package/lib/svelte/WindowVirtualizer.type.d.ts +1 -1
  35. package/lib/svelte/WindowVirtualizer.type.js +2 -1
  36. package/lib/svelte/index.d.ts +3 -3
  37. package/lib/svelte/index.js +12 -3
  38. package/lib/svelte/types.js +2 -1
  39. package/lib/svelte/utils.d.ts +1 -1
  40. package/lib/svelte/utils.js +9 -3
  41. package/lib/vue/VList.d.ts +2 -2
  42. package/lib/vue/Virtualizer.d.ts +2 -2
  43. package/lib/vue/WindowVirtualizer.d.ts +1 -1
  44. package/lib/vue/index.cjs +2 -0
  45. package/lib/vue/index.cjs.map +1 -0
  46. package/lib/vue/index.d.ts +3 -3
  47. package/lib/vue/index.js +1 -1
  48. package/lib/vue/index.js.map +1 -1
  49. package/package.json +8 -8
  50. package/lib/core/index.mjs +0 -2
  51. package/lib/core/index.mjs.map +0 -1
  52. package/lib/index.mjs +0 -3
  53. package/lib/index.mjs.map +0 -1
  54. package/lib/solid/index.mjs +0 -2
  55. package/lib/solid/index.mjs.map +0 -1
  56. package/lib/vue/index.mjs +0 -2
  57. package/lib/vue/index.mjs.map +0 -1
@@ -28,12 +28,10 @@ const microtask = typeof queueMicrotask === "function"
28
28
  */
29
29
  const createPromise = () => {
30
30
  let resolve;
31
- let reject;
32
- const promise = new Promise((res, rej) => {
31
+ const promise = new Promise((res) => {
33
32
  resolve = res;
34
- reject = rej;
35
33
  });
36
- return [promise, resolve, reject];
34
+ return [promise, resolve];
37
35
  };
38
36
  /**
39
37
  * @internal
@@ -335,8 +333,12 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
335
333
  };
336
334
  const applyJump = (j) => {
337
335
  if (j) {
336
+ if (
338
337
  // In iOS WebKit browsers, updating scroll position will stop scrolling so it have to be deferred during scrolling.
339
- if (isIOSWebKit() && _scrollDirection !== SCROLL_IDLE) {
338
+ (isIOSWebKit() && _scrollDirection !== SCROLL_IDLE) ||
339
+ // Before imperative smooth scrolling, we measure all items which may be visible during scrolling.
340
+ // However, especially in Firefox, there are rare cases where items resize while scrolling, which can stop smooth scrolling.
341
+ (_frozenRange && _scrollMode === SCROLL_BY_MANUAL_SCROLL)) {
340
342
  pendingJump += j;
341
343
  }
342
344
  else {
@@ -375,13 +377,6 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
375
377
  $findStartIndex: () => findIndex(cache, getVisibleOffset()),
376
378
  $findEndIndex: () => findIndex(cache, getVisibleOffset() + viewportSize),
377
379
  $isUnmeasuredItem: (index) => cache._sizes[index] === UNCACHED,
378
- _hasUnmeasuredItemsInFrozenRange: () => {
379
- if (!_frozenRange)
380
- return false;
381
- return cache._sizes
382
- .slice(max(0, _frozenRange[0] - 1), min(cache._length - 1, _frozenRange[1] + 1) + 1)
383
- .includes(UNCACHED);
384
- },
385
380
  $getItemOffset: getItemOffset,
386
381
  $getItemSize: getItemSize$1,
387
382
  $getItemsLength: () => cache._length,
@@ -393,13 +388,7 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
393
388
  _flushJump: () => {
394
389
  _flushedJump = jump;
395
390
  jump = 0;
396
- return [
397
- _flushedJump,
398
- // Use absolute position not to exceed scrollable bounds
399
- _scrollMode === SCROLL_BY_SHIFT ||
400
- // https://github.com/inokawa/virtua/discussions/475
401
- getRelativeScrollOffset() + viewportSize >= getTotalSize(),
402
- ];
391
+ return [_flushedJump, _scrollMode === SCROLL_BY_SHIFT];
403
392
  },
404
393
  $subscribe: (target, cb) => {
405
394
  const sub = [target, cb];
@@ -478,10 +467,10 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
478
467
  if (
479
468
  // Keep distance from end during shifting
480
469
  _scrollMode === SCROLL_BY_SHIFT ||
481
- (_frozenRange
470
+ (_frozenRange && _scrollMode === SCROLL_BY_MANUAL_SCROLL
482
471
  ? // https://github.com/inokawa/virtua/issues/380
483
- // https://github.com/inokawa/virtua/issues/590
484
- !isSSR && index < _frozenRange[0]
472
+ // https://github.com/inokawa/virtua/issues/758
473
+ index < _frozenRange[0]
485
474
  : // Otherwise we should maintain visible position
486
475
  getItemOffset(index) +
487
476
  // https://github.com/inokawa/virtua/issues/385
@@ -704,7 +693,7 @@ const createScroller = (store, isHorizontal) => {
704
693
  let viewportElement;
705
694
  let scrollObserver;
706
695
  let cancelScroll;
707
- const [initialized, resolveInitialized] = createPromise();
696
+ let initialized = createPromise();
708
697
  const scrollOffsetKey = isHorizontal ? "scrollLeft" : "scrollTop";
709
698
  const overflowKey = isHorizontal ? "overflowX" : "overflowY";
710
699
  // The given offset will be clamped by browser
@@ -713,8 +702,7 @@ const createScroller = (store, isHorizontal) => {
713
702
  // Wait for element assign. The element may be undefined if scrollRef prop is used and scroll is scheduled on mount.
714
703
  // https://github.com/inokawa/virtua/pull/733
715
704
  // https://github.com/inokawa/virtua/pull/750
716
- const ok = await initialized;
717
- if (!ok) {
705
+ if (!(await initialized[0])) {
718
706
  return;
719
707
  }
720
708
  if (cancelScroll) {
@@ -743,33 +731,44 @@ const createScroller = (store, isHorizontal) => {
743
731
  ];
744
732
  };
745
733
  if (smooth && isSmoothScrollSupported()) {
746
- while (true) {
747
- store.$update(ACTION_BEFORE_MANUAL_SMOOTH_SCROLL, getTargetOffset());
748
- if (!store._hasUnmeasuredItemsInFrozenRange()) {
749
- break;
750
- }
751
- const [promise, unsubscribe] = waitForMeasurement();
752
- try {
753
- if (!(await promise)) {
754
- // canceled
755
- return;
734
+ store.$update(ACTION_BEFORE_MANUAL_SMOOTH_SCROLL, getTargetOffset());
735
+ // https://github.com/inokawa/virtua/issues/590
736
+ microtask(async () => {
737
+ while (true) {
738
+ let measuring = false;
739
+ for (let [i, end] = store.$getRange(); i <= end; i++) {
740
+ if (store.$isUnmeasuredItem(i)) {
741
+ measuring = true;
742
+ break;
743
+ }
744
+ }
745
+ if (!measuring) {
746
+ break;
747
+ }
748
+ const [promise, unsubscribe] = waitForMeasurement();
749
+ try {
750
+ if (!(await promise)) {
751
+ // canceled
752
+ return;
753
+ }
754
+ }
755
+ finally {
756
+ unsubscribe();
756
757
  }
757
758
  }
758
- finally {
759
- unsubscribe();
760
- }
761
- }
762
- viewportElement.scrollTo({
763
- [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
764
- behavior: "smooth",
759
+ store.$update(ACTION_MANUAL_SCROLL);
760
+ viewportElement.scrollTo({
761
+ [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
762
+ behavior: "smooth",
763
+ });
765
764
  });
766
765
  }
767
766
  else {
768
767
  while (true) {
769
768
  const [promise, unsubscribe] = waitForMeasurement();
770
769
  try {
771
- viewportElement[scrollOffsetKey] = normalizeOffset(getTargetOffset(), isHorizontal);
772
770
  store.$update(ACTION_MANUAL_SCROLL);
771
+ viewportElement[scrollOffsetKey] = normalizeOffset(getTargetOffset(), isHorizontal);
773
772
  if (!(await promise)) {
774
773
  // canceled or finished
775
774
  return;
@@ -797,20 +796,21 @@ const createScroller = (store, isHorizontal) => {
797
796
  style[overflowKey] = prev;
798
797
  });
799
798
  }
799
+ // Use absolute position not to exceed scrollable bounds
800
+ // https://github.com/inokawa/virtua/discussions/475
801
+ viewport[scrollOffsetKey] = store.$getScrollOffset() + jump;
800
802
  if (shift) {
801
- viewport[scrollOffsetKey] = store.$getScrollOffset() + jump;
802
803
  // https://github.com/inokawa/virtua/issues/357
803
804
  cancelScroll && cancelScroll();
804
805
  }
805
- else {
806
- viewport[scrollOffsetKey] += jump;
807
- }
808
806
  });
809
- resolveInitialized(true);
807
+ initialized[1](true);
810
808
  },
811
809
  $dispose() {
812
810
  scrollObserver && scrollObserver._dispose();
813
- resolveInitialized(false);
811
+ initialized[1](false);
812
+ // https://github.com/inokawa/virtua/pull/765
813
+ initialized = createPromise();
814
814
  },
815
815
  $scrollTo(offset) {
816
816
  scheduleImperativeScroll(() => offset);
@@ -859,7 +859,7 @@ const createWindowScroller = (store, isHorizontal) => {
859
859
  let containerElement;
860
860
  let scrollObserver;
861
861
  let cancelScroll;
862
- const [initialized, resolveInitialized] = createPromise();
862
+ let initialized = createPromise();
863
863
  const calcOffsetToViewport = (node, viewport, window, isHorizontal, offset = 0) => {
864
864
  // TODO calc offset only when it changes (maybe impossible)
865
865
  const offsetKey = isHorizontal ? "offsetLeft" : "offsetTop";
@@ -877,8 +877,7 @@ const createWindowScroller = (store, isHorizontal) => {
877
877
  // Wait for element assign. The element may be undefined if scrollRef prop is used and scroll is scheduled on mount.
878
878
  // https://github.com/inokawa/virtua/pull/733
879
879
  // https://github.com/inokawa/virtua/pull/750
880
- const ok = await initialized;
881
- if (!ok) {
880
+ if (!(await initialized[0])) {
882
881
  return;
883
882
  }
884
883
  if (cancelScroll) {
@@ -907,34 +906,46 @@ const createWindowScroller = (store, isHorizontal) => {
907
906
  };
908
907
  const window = getCurrentWindow(getCurrentDocument(containerElement));
909
908
  if (smooth && isSmoothScrollSupported()) {
910
- while (true) {
911
- store.$update(ACTION_BEFORE_MANUAL_SMOOTH_SCROLL, getTargetOffset());
912
- if (!store._hasUnmeasuredItemsInFrozenRange()) {
913
- break;
914
- }
915
- const [promise, unsubscribe] = waitForMeasurement();
916
- try {
917
- if (!(await promise)) {
918
- return;
909
+ store.$update(ACTION_BEFORE_MANUAL_SMOOTH_SCROLL, getTargetOffset());
910
+ // https://github.com/inokawa/virtua/issues/590
911
+ microtask(async () => {
912
+ while (true) {
913
+ let measuring = false;
914
+ for (let [i, end] = store.$getRange(); i <= end; i++) {
915
+ if (store.$isUnmeasuredItem(i)) {
916
+ measuring = true;
917
+ break;
918
+ }
919
+ }
920
+ if (!measuring) {
921
+ break;
922
+ }
923
+ const [promise, unsubscribe] = waitForMeasurement();
924
+ try {
925
+ if (!(await promise)) {
926
+ // canceled
927
+ return;
928
+ }
929
+ }
930
+ finally {
931
+ unsubscribe();
919
932
  }
920
933
  }
921
- finally {
922
- unsubscribe();
923
- }
924
- }
925
- window.scroll({
926
- [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
927
- behavior: "smooth",
934
+ store.$update(ACTION_MANUAL_SCROLL);
935
+ window.scroll({
936
+ [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
937
+ behavior: "smooth",
938
+ });
928
939
  });
929
940
  }
930
941
  else {
931
942
  while (true) {
932
943
  const [promise, unsubscribe] = waitForMeasurement();
933
944
  try {
945
+ store.$update(ACTION_MANUAL_SCROLL);
934
946
  window.scroll({
935
947
  [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
936
948
  });
937
- store.$update(ACTION_MANUAL_SCROLL);
938
949
  if (!(await promise)) {
939
950
  return;
940
951
  }
@@ -952,23 +963,22 @@ const createWindowScroller = (store, isHorizontal) => {
952
963
  const document = getCurrentDocument(container);
953
964
  const window = getCurrentWindow(document);
954
965
  const documentBody = document.body;
955
- scrollObserver = createScrollObserver(store, window, isHorizontal, () => normalizeOffset(window[scrollOffsetKey], isHorizontal), (jump, shift) => {
966
+ scrollObserver = createScrollObserver(store, window, isHorizontal, () => normalizeOffset(window[scrollOffsetKey], isHorizontal), (jump) => {
967
+ // Use absolute position not to exceed scrollable bounds
968
+ // https://github.com/inokawa/virtua/discussions/475
956
969
  // TODO support case two window scrollers exist in the same view
957
- if (shift) {
958
- window.scroll({
959
- [isHorizontal ? "left" : "top"]: store.$getScrollOffset() + jump,
960
- });
961
- }
962
- else {
963
- window.scrollBy(isHorizontal ? jump : 0, isHorizontal ? 0 : jump);
964
- }
970
+ window.scroll({
971
+ [isHorizontal ? "left" : "top"]: store.$getScrollOffset() + jump,
972
+ });
965
973
  }, () => calcOffsetToViewport(container, documentBody, window, isHorizontal));
966
- resolveInitialized(true);
974
+ initialized[1](true);
967
975
  },
968
976
  $dispose() {
969
977
  scrollObserver && scrollObserver._dispose();
970
978
  containerElement = undefined;
971
- resolveInitialized(false);
979
+ initialized[1](false);
980
+ // https://github.com/inokawa/virtua/pull/765
981
+ initialized = createPromise();
972
982
  },
973
983
  $fixScrollJump: () => {
974
984
  scrollObserver && scrollObserver._fixScrollJump();