virtua 0.43.6 → 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 +76 -66
  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
@@ -333,8 +333,12 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
333
333
  };
334
334
  const applyJump = (j) => {
335
335
  if (j) {
336
+ if (
336
337
  // In iOS WebKit browsers, updating scroll position will stop scrolling so it have to be deferred during scrolling.
337
- 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)) {
338
342
  pendingJump += j;
339
343
  }
340
344
  else {
@@ -373,13 +377,6 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
373
377
  $findStartIndex: () => findIndex(cache, getVisibleOffset()),
374
378
  $findEndIndex: () => findIndex(cache, getVisibleOffset() + viewportSize),
375
379
  $isUnmeasuredItem: (index) => cache._sizes[index] === UNCACHED,
376
- _hasUnmeasuredItemsInFrozenRange: () => {
377
- if (!_frozenRange)
378
- return false;
379
- return cache._sizes
380
- .slice(max(0, _frozenRange[0] - 1), min(cache._length - 1, _frozenRange[1] + 1) + 1)
381
- .includes(UNCACHED);
382
- },
383
380
  $getItemOffset: getItemOffset,
384
381
  $getItemSize: getItemSize$1,
385
382
  $getItemsLength: () => cache._length,
@@ -391,13 +388,7 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
391
388
  _flushJump: () => {
392
389
  _flushedJump = jump;
393
390
  jump = 0;
394
- return [
395
- _flushedJump,
396
- // Use absolute position not to exceed scrollable bounds
397
- _scrollMode === SCROLL_BY_SHIFT ||
398
- // https://github.com/inokawa/virtua/discussions/475
399
- getRelativeScrollOffset() + viewportSize >= getTotalSize(),
400
- ];
391
+ return [_flushedJump, _scrollMode === SCROLL_BY_SHIFT];
401
392
  },
402
393
  $subscribe: (target, cb) => {
403
394
  const sub = [target, cb];
@@ -476,10 +467,10 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
476
467
  if (
477
468
  // Keep distance from end during shifting
478
469
  _scrollMode === SCROLL_BY_SHIFT ||
479
- (_frozenRange
470
+ (_frozenRange && _scrollMode === SCROLL_BY_MANUAL_SCROLL
480
471
  ? // https://github.com/inokawa/virtua/issues/380
481
- // https://github.com/inokawa/virtua/issues/590
482
- !isSSR && index < _frozenRange[0]
472
+ // https://github.com/inokawa/virtua/issues/758
473
+ index < _frozenRange[0]
483
474
  : // Otherwise we should maintain visible position
484
475
  getItemOffset(index) +
485
476
  // https://github.com/inokawa/virtua/issues/385
@@ -740,33 +731,44 @@ const createScroller = (store, isHorizontal) => {
740
731
  ];
741
732
  };
742
733
  if (smooth && isSmoothScrollSupported()) {
743
- while (true) {
744
- store.$update(ACTION_BEFORE_MANUAL_SMOOTH_SCROLL, getTargetOffset());
745
- if (!store._hasUnmeasuredItemsInFrozenRange()) {
746
- break;
747
- }
748
- const [promise, unsubscribe] = waitForMeasurement();
749
- try {
750
- if (!(await promise)) {
751
- // canceled
752
- 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();
753
757
  }
754
758
  }
755
- finally {
756
- unsubscribe();
757
- }
758
- }
759
- viewportElement.scrollTo({
760
- [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
761
- behavior: "smooth",
759
+ store.$update(ACTION_MANUAL_SCROLL);
760
+ viewportElement.scrollTo({
761
+ [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
762
+ behavior: "smooth",
763
+ });
762
764
  });
763
765
  }
764
766
  else {
765
767
  while (true) {
766
768
  const [promise, unsubscribe] = waitForMeasurement();
767
769
  try {
768
- viewportElement[scrollOffsetKey] = normalizeOffset(getTargetOffset(), isHorizontal);
769
770
  store.$update(ACTION_MANUAL_SCROLL);
771
+ viewportElement[scrollOffsetKey] = normalizeOffset(getTargetOffset(), isHorizontal);
770
772
  if (!(await promise)) {
771
773
  // canceled or finished
772
774
  return;
@@ -794,14 +796,13 @@ const createScroller = (store, isHorizontal) => {
794
796
  style[overflowKey] = prev;
795
797
  });
796
798
  }
799
+ // Use absolute position not to exceed scrollable bounds
800
+ // https://github.com/inokawa/virtua/discussions/475
801
+ viewport[scrollOffsetKey] = store.$getScrollOffset() + jump;
797
802
  if (shift) {
798
- viewport[scrollOffsetKey] = store.$getScrollOffset() + jump;
799
803
  // https://github.com/inokawa/virtua/issues/357
800
804
  cancelScroll && cancelScroll();
801
805
  }
802
- else {
803
- viewport[scrollOffsetKey] += jump;
804
- }
805
806
  });
806
807
  initialized[1](true);
807
808
  },
@@ -905,34 +906,46 @@ const createWindowScroller = (store, isHorizontal) => {
905
906
  };
906
907
  const window = getCurrentWindow(getCurrentDocument(containerElement));
907
908
  if (smooth && isSmoothScrollSupported()) {
908
- while (true) {
909
- store.$update(ACTION_BEFORE_MANUAL_SMOOTH_SCROLL, getTargetOffset());
910
- if (!store._hasUnmeasuredItemsInFrozenRange()) {
911
- break;
912
- }
913
- const [promise, unsubscribe] = waitForMeasurement();
914
- try {
915
- if (!(await promise)) {
916
- 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();
917
932
  }
918
933
  }
919
- finally {
920
- unsubscribe();
921
- }
922
- }
923
- window.scroll({
924
- [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
925
- behavior: "smooth",
934
+ store.$update(ACTION_MANUAL_SCROLL);
935
+ window.scroll({
936
+ [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
937
+ behavior: "smooth",
938
+ });
926
939
  });
927
940
  }
928
941
  else {
929
942
  while (true) {
930
943
  const [promise, unsubscribe] = waitForMeasurement();
931
944
  try {
945
+ store.$update(ACTION_MANUAL_SCROLL);
932
946
  window.scroll({
933
947
  [isHorizontal ? "left" : "top"]: normalizeOffset(getTargetOffset(), isHorizontal),
934
948
  });
935
- store.$update(ACTION_MANUAL_SCROLL);
936
949
  if (!(await promise)) {
937
950
  return;
938
951
  }
@@ -950,16 +963,13 @@ const createWindowScroller = (store, isHorizontal) => {
950
963
  const document = getCurrentDocument(container);
951
964
  const window = getCurrentWindow(document);
952
965
  const documentBody = document.body;
953
- 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
954
969
  // TODO support case two window scrollers exist in the same view
955
- if (shift) {
956
- window.scroll({
957
- [isHorizontal ? "left" : "top"]: store.$getScrollOffset() + jump,
958
- });
959
- }
960
- else {
961
- window.scrollBy(isHorizontal ? jump : 0, isHorizontal ? 0 : jump);
962
- }
970
+ window.scroll({
971
+ [isHorizontal ? "left" : "top"]: store.$getScrollOffset() + jump,
972
+ });
963
973
  }, () => calcOffsetToViewport(container, documentBody, window, isHorizontal));
964
974
  initialized[1](true);
965
975
  },