ng-virtual-list 20.10.7 → 20.10.9

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.
@@ -142,7 +142,7 @@ const TRACK_BY_PROPERTY_NAME = 'id';
142
142
  const DEFAULT_DIRECTION = Directions.VERTICAL;
143
143
  const DEFAULT_COLLECTION_MODE = CollectionModes.NORMAL;
144
144
  const DISPLAY_OBJECTS_LENGTH_MESUREMENT_ERROR = 1;
145
- const MAX_SCROLL_TO_ITERATIONS = 7;
145
+ const MAX_SCROLL_TO_ITERATIONS = 5;
146
146
  const DEFAULT_SNAPPING_METHOD = SnappingMethods.NORMAL;
147
147
  const DEFAULT_SELECT_METHOD = MethodsForSelecting.NONE;
148
148
  const DEFAULT_SCREEN_READER_MESSAGE = 'Showing items $1 to $2';
@@ -637,7 +637,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
637
637
  args: ['maxClickDistance']
638
638
  }], onClick: [{ type: i0.Output, args: ["onClick"] }] } });
639
639
 
640
- const ZEROS_POSITION = -1000, NAVIGATE_TO_ATTEMT = 5, ATTR_AREA_SELECTED = 'area-selected', POSITION = 'position', POSITION_ZERO = '0', ID$1 = 'item-id', KEY_SPACE = ' ', KEY_ARR_LEFT = 'ArrowLeft', KEY_ARR_UP = 'ArrowUp', KEY_ARR_RIGHT = 'ArrowRight', KEY_ARR_DOWN = 'ArrowDown', EVENT_FOCUS_IN = 'focusin', EVENT_FOCUS_OUT = 'focusout', EVENT_KEY_DOWN = 'keydown', CLASS_NAME_SNAPPED = 'snapped', CLASS_NAME_SNAPPED_OUT = 'snapped-out', CLASS_NAME_FOCUS = 'focus';
640
+ const TRANSLATE_3D_HIDDEN = 'translate3d(-1000px,-1000px,0)', NAVIGATE_TO_ATTEMT = 5, ATTR_AREA_SELECTED = 'area-selected', POSITION = 'position', POSITION_ZERO = '0', ID$1 = 'item-id', KEY_SPACE = ' ', KEY_ARR_LEFT = 'ArrowLeft', KEY_ARR_UP = 'ArrowUp', KEY_ARR_RIGHT = 'ArrowRight', KEY_ARR_DOWN = 'ArrowDown', EVENT_FOCUS_IN = 'focusin', EVENT_FOCUS_OUT = 'focusout', EVENT_KEY_DOWN = 'keydown', CLASS_NAME_SNAPPED = 'snapped', CLASS_NAME_SNAPPED_OUT = 'snapped-out', CLASS_NAME_FOCUS = 'focus';
641
641
  /**
642
642
  * Virtual list component.
643
643
  * Maximum performance for extremely large lists.
@@ -986,7 +986,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
986
986
  hide() {
987
987
  const el = this._elementRef.nativeElement, styles = el.style;
988
988
  styles.position = POSITION_ABSOLUTE;
989
- styles.transform = `${TRANSLATE_3D}(${this._data?.config?.isVertical ? 0 : ZEROS_POSITION},${this._data?.config?.isVertical ? 0 : ZEROS_POSITION},0)`;
989
+ styles.transform = TRANSLATE_3D_HIDDEN;
990
990
  styles.zIndex = HIDDEN_ZINDEX;
991
991
  if (this.regular) {
992
992
  if (styles.display === DISPLAY_NONE) {
@@ -1605,8 +1605,6 @@ const bufferInterpolation = (currentBufferValue, array, value, extra) => {
1605
1605
  var TrackBoxEvents;
1606
1606
  (function (TrackBoxEvents) {
1607
1607
  TrackBoxEvents["CHANGE"] = "change";
1608
- TrackBoxEvents["PREPARE"] = "prepare";
1609
- TrackBoxEvents["RESET"] = "reset";
1610
1608
  })(TrackBoxEvents || (TrackBoxEvents = {}));
1611
1609
  var ItemDisplayMethods;
1612
1610
  (function (ItemDisplayMethods) {
@@ -1744,10 +1742,6 @@ class TrackBox extends CacheMap {
1744
1742
  _resetBufferSizeTimeout = DEFAULT_RESET_BUFFER_SIZE_TIMEOUT;
1745
1743
  _resetBufferSizeTimer;
1746
1744
  _isReseted = true;
1747
- _prepared = false;
1748
- _preparedToStart = false;
1749
- _preparedToStartIterations = 2;
1750
- get prepared() { return this._prepared; }
1751
1745
  lifeCircle() {
1752
1746
  this.fireChangeIfNeed();
1753
1747
  this.lifeCircleDo();
@@ -1763,12 +1757,7 @@ class TrackBox extends CacheMap {
1763
1757
  }
1764
1758
  const reseted = ((!this._previousCollection || this._previousCollection.length === 0) &&
1765
1759
  (!!currentCollection && currentCollection.length > 0));
1766
- if (this._isReseted !== reseted && reseted && this._prepared) {
1767
- this._prepared = false;
1768
- this.dispatch(TrackBoxEvents.PREPARE, false);
1769
- }
1770
1760
  this._isReseted = reseted;
1771
- this.dispatch(TrackBoxEvents.RESET, reseted);
1772
1761
  this.updateCache(this._previousCollection, currentCollection, itemSize);
1773
1762
  this._previousCollection = [...(currentCollection || [])];
1774
1763
  }
@@ -1897,7 +1886,7 @@ class TrackBox extends CacheMap {
1897
1886
  updateCollection(items, itemConfigMap, options) {
1898
1887
  const opt = { itemConfigMap, ...options }, dynamicSize = opt.dynamicSize, crudDetected = this._crudDetected, deletedItemsMap = this._deletedItemsMap;
1899
1888
  if (dynamicSize) {
1900
- this.cacheElements();
1889
+ this.cacheElements(opt.isVertical, opt.itemSize);
1901
1890
  }
1902
1891
  this._defaultBufferSize = opt.bufferSize;
1903
1892
  this._maxBufferSize = opt.maxBufferSize;
@@ -1920,16 +1909,6 @@ class TrackBox extends CacheMap {
1920
1909
  }
1921
1910
  this._delta += metrics.delta;
1922
1911
  this.updateAdaptiveBufferParams(metrics, items.length);
1923
- if (!opt.dynamicSize || (this._preparedToStart && !this._prepared && this._previousTotalSize === metrics.totalSize)) {
1924
- this._prepared = true;
1925
- this.dispatch(TrackBoxEvents.PREPARE, true);
1926
- }
1927
- if (this._preparedToStartIterations > 0 && this._previousTotalSize !== metrics.totalSize) {
1928
- this._preparedToStartIterations--;
1929
- }
1930
- if (this._preparedToStartIterations === 0) {
1931
- this._preparedToStart = true;
1932
- }
1933
1912
  this._previousTotalSize = metrics.totalSize;
1934
1913
  this._deletedItemsMap = {};
1935
1914
  if (!dynamicSize) {
@@ -2222,6 +2201,20 @@ class TrackBox extends CacheMap {
2222
2201
  };
2223
2202
  return metrics;
2224
2203
  }
2204
+ resetCache(collection, trackBy, isVertical, itemSize, bounds) {
2205
+ const map = this._map;
2206
+ for (let i = 0, l = collection.length; i < l; i++) {
2207
+ const collectionItem = collection[i], id = collectionItem[trackBy];
2208
+ if (map.has(id)) {
2209
+ const cache = map.get(id), bSize = isVertical ? bounds.height : bounds.width;
2210
+ map.set(id, {
2211
+ ...cache,
2212
+ width: isVertical ? cache.width : (cache.width <= itemSize || cache.width === bSize) ? itemSize : cache.width,
2213
+ height: isVertical ? (cache.height <= itemSize || cache.height === bSize) ? itemSize : cache.height : cache.height
2214
+ });
2215
+ }
2216
+ }
2217
+ }
2225
2218
  clearDeltaDirection() {
2226
2219
  this.clearScrollDirectionCache();
2227
2220
  }
@@ -2492,7 +2485,7 @@ class TrackBox extends CacheMap {
2492
2485
  _debouncedIsScrollStartOff = debounce(() => {
2493
2486
  this._isScrollStart = false;
2494
2487
  });
2495
- cacheElements() {
2488
+ cacheElements(isVertical, itemSize) {
2496
2489
  if (!this._displayComponents) {
2497
2490
  return;
2498
2491
  }
@@ -2502,11 +2495,13 @@ class TrackBox extends CacheMap {
2502
2495
  continue;
2503
2496
  }
2504
2497
  const bounds = component.instance.getBounds();
2505
- if (bounds.width && bounds.height) {
2506
- this.set(itemId, { ...this.get(itemId), ...bounds });
2507
- if (this._isLazy && (this._isScrollStart)) {
2508
- this._debouncedIsScrollStartOff.execute();
2509
- }
2498
+ this.set(itemId, {
2499
+ ...this.get(itemId), ...bounds,
2500
+ width: bounds.width || (isVertical ? 0 : itemSize),
2501
+ height: bounds.height || (isVertical ? itemSize : 0),
2502
+ });
2503
+ if (this._isLazy && (this._isScrollStart)) {
2504
+ this._debouncedIsScrollStartOff.execute();
2510
2505
  }
2511
2506
  }
2512
2507
  }
@@ -2999,7 +2994,7 @@ const easeLinear = (t) => {
2999
2994
  return t + t;
3000
2995
  };
3001
2996
 
3002
- const DEFAULT_ANIMATION_DURATION = 500, ANIMATOR_MIN_TIMESTAMP = 20, MIN_ANIMATED_VALUE = 10;
2997
+ const DEFAULT_ANIMATION_DURATION = 500, ANIMATOR_MIN_TIMESTAMP = 1000 / 30, MIN_ANIMATED_VALUE = 10;
3003
2998
  class Animator {
3004
2999
  _animationId = 0;
3005
3000
  animate(params) {
@@ -3068,7 +3063,7 @@ const calculateDirection = (buffer) => {
3068
3063
  }
3069
3064
  return 1;
3070
3065
  };
3071
- const TOP$1 = 'top', LEFT$1 = 'left', INSTANT$1 = 'instant', AUTO$1 = 'auto', SMOOTH = 'smooth', DURATION = 2000, FRICTION_FORCE = .035, MAX_DURATION = 4000, ANIMATION_DURATION = 50, MASS = .005, MAX_DIST = 12500, MAX_VELOCITY_TIMESTAMP = 100, SPEED_SCALE = 5, OVERSCROLL_START_ITERATION = 2;
3066
+ const TOP$1 = 'top', LEFT$1 = 'left', INSTANT$1 = 'instant', AUTO$1 = 'auto', SMOOTH = 'smooth', DURATION = 2000, FRICTION_FORCE = .035, MAX_DURATION = 4000, ANIMATION_DURATION = 50, MASS = .005, MAX_DIST = 12500, MAX_VELOCITY_TIMESTAMP = 100, SPEED_SCALE = 15, OVERSCROLL_START_ITERATION = 2;
3072
3067
  const SCROLL_EVENT$1 = new Event(SCROLLER_SCROLL), WHEEL_EVENT$1 = new Event(SCROLLER_WHEEL), SCROLLBAR_SCROLL_EVENT$1 = new Event(SCROLLER_SCROLLBAR_SCROLL);
3073
3068
  /**
3074
3069
  * NgScrollView
@@ -3241,7 +3236,7 @@ class NgScrollView {
3241
3236
  if (this.scrollBehavior() === BEHAVIOR_INSTANT) {
3242
3237
  return;
3243
3238
  }
3244
- this.moveWithAcceleration(isVertical, position, 0, v0, a0);
3239
+ this.moveWithAcceleration(isVertical, position, 0, v0, a0, timestamp);
3245
3240
  }));
3246
3241
  }));
3247
3242
  }));
@@ -3279,7 +3274,7 @@ class NgScrollView {
3279
3274
  if (this.scrollBehavior() === BEHAVIOR_INSTANT) {
3280
3275
  return;
3281
3276
  }
3282
- this.moveWithAcceleration(isVertical, position, this._velocity, v0, a0);
3277
+ this.moveWithAcceleration(isVertical, position, this._velocity, v0, a0, timestamp);
3283
3278
  }));
3284
3279
  }));
3285
3280
  }));
@@ -3288,9 +3283,6 @@ class NgScrollView {
3288
3283
  calculatePosition(isVertical, e, inversion, startClientPos, startTime, prevClientPosition, offsets, velocities) {
3289
3284
  const currentPos = isVertical ? e.touches?.[e.touches?.length - 1]?.clientY || e.clientY : e.touches?.[e.touches?.length - 1]?.clientX || e.clientX, scrollSize = isVertical ? this.scrollHeight : this.scrollWidth, delta = (inversion ? -1 : 1) * (startClientPos - currentPos), dp = this._startPosition + delta, position = Math.round(dp < 0 ? 0 : dp > scrollSize ? scrollSize : dp), endTime = Date.now(), timestamp = endTime - startTime, scrollDelta = prevClientPosition === 0 ? 0 : prevClientPosition - currentPos, { v0 } = this.calculateVelocity(offsets, scrollDelta, timestamp);
3290
3285
  this.calculateAcceleration(velocities, v0, timestamp);
3291
- prevClientPosition = currentPos;
3292
- this.move(isVertical, position, true, true, true);
3293
- startTime = endTime;
3294
3286
  return { position, currentPos, endTime, scrollDelta };
3295
3287
  }
3296
3288
  cancelOverscroll() {
@@ -3361,8 +3353,8 @@ class NgScrollView {
3361
3353
  continue;
3362
3354
  }
3363
3355
  if (v00) {
3364
- const a0 = timestamp < MAX_VELOCITY_TIMESTAMP ? (v00[1] !== 0 ? (lastVSign * Math.abs(Math.abs(v01[0]) - Math.abs(v00[0]))) / Math.abs(v00[1]) : 0) : 0;
3365
- aSum += a0;
3356
+ const a0 = timestamp < MAX_VELOCITY_TIMESTAMP ? (v00[1] !== 0 ? (lastVSign * Math.abs(Math.abs(v01[0]) - Math.abs(v00[0]))) / Math.abs(v00[1]) : 0) : 0.1;
3357
+ aSum = (aSum * MASS) + a0;
3366
3358
  prevV0 = v01;
3367
3359
  }
3368
3360
  prevV0 = v01;
@@ -3377,8 +3369,8 @@ class NgScrollView {
3377
3369
  move(isVertical, position, blending = false, userAction = false, fireUpdate = true) {
3378
3370
  this.scroll({ [isVertical ? TOP$1 : LEFT$1]: position, behavior: INSTANT$1, blending, userAction, fireUpdate });
3379
3371
  }
3380
- moveWithAcceleration(isVertical, position, v0, v, a0) {
3381
- if (a0 !== 0) {
3372
+ moveWithAcceleration(isVertical, position, v0, v, a0, timestamp) {
3373
+ if (a0 !== 0 && timestamp < MAX_VELOCITY_TIMESTAMP) {
3382
3374
  const dvSign = Math.sign(v), duration = DURATION, maxDuration = MAX_DURATION, maxDistance = dvSign * MAX_DIST, s = (dvSign * Math.abs((a0 * Math.pow(duration, 2)) * .5) / 1000) / MASS, distance = Math.abs(s) < MAX_DIST ? s : maxDistance, positionWithVelocity = position + (this._inversion ? -1 : 1) * distance, vmax = Math.max(Math.abs(v0), Math.abs(v)), ad = Math.abs(vmax !== 0 ? Math.sqrt(vmax) : 0) * 10 / MASS, aDuration = ad < maxDuration ? ad : maxDuration, startPosition = isVertical ? this.y : this.x;
3383
3375
  this.animate(startPosition, Math.round(positionWithVelocity), aDuration, easeOutQuad, true);
3384
3376
  }
@@ -3937,7 +3929,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
3937
3929
  args: ['scrollBar', { read: NgScrollBarComponent }]
3938
3930
  }], scrollbarEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarEnabled", required: false }] }], scrollbarInteractive: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarInteractive", required: false }] }], focusedElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusedElement", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], classes: [{ type: i0.Input, args: [{ isSignal: true, alias: "classes", required: false }] }], startOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "startOffset", required: false }] }], endOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "endOffset", required: false }] }], scrollbarTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarTheme", required: false }] }], scrollbarMinSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollbarMinSize", required: false }] }] } });
3939
3931
 
3940
- const MIN_SCROLL_TO_START_PIXELS = 10, RANGE_DISPLAY_ITEMS_END_OFFSET = 20, MIN_PREPARE_ITERATIONS = 15, EMPTY_SCROLL_STATE_VERSION = '-1', ROLE_LIST = 'list', ROLE_LIST_BOX = 'listbox', ITEM_ID = 'item-id', ITEM_CONTAINER = 'ngvl-item__container', READY_TO_START = 'ready-to-start', WAIT_FOR_PREPARATION = 'wait-for-preparation';
3932
+ const MIN_SCROLL_TO_START_PIXELS = 10, RANGE_DISPLAY_ITEMS_END_OFFSET = 20, MIN_PREPARE_ITERATIONS = 10, PREPARATION_REUPDATE_LENGTH = 15, RESET_CACHE_FRAME_NUMBER = 3, EMPTY_SCROLL_STATE_VERSION = '-1', ROLE_LIST = 'list', ROLE_LIST_BOX = 'listbox', ITEM_ID = 'item-id', ITEM_CONTAINER = 'ngvl-item__container', READY_TO_START = 'ready-to-start', WAIT_FOR_PREPARATION = 'wait-for-preparation';
3941
3933
  const validateScrollIteration = (value) => {
3942
3934
  return Number.isNaN(value) || (value < 0) ? 0 : value > MAX_SCROLL_TO_ITERATIONS ? MAX_SCROLL_TO_ITERATIONS : value;
3943
3935
  }, validateId = (id) => {
@@ -4465,6 +4457,7 @@ class NgVirtualListComponent {
4465
4457
  * to adjust the sizes of the items in the unallocated area.
4466
4458
  */
4467
4459
  itemSize = input(DEFAULT_ITEM_SIZE, ...(ngDevMode ? [{ debugName: "itemSize", ...this._itemSizeOptions }] : [{ ...this._itemSizeOptions }]));
4460
+ actualItemSize = signal(this.itemSize(), ...(ngDevMode ? [{ debugName: "actualItemSize" }] : []));
4468
4461
  _dynamicSizeOptions = {
4469
4462
  transform: (v) => {
4470
4463
  const valid = validateBoolean(v);
@@ -4701,7 +4694,8 @@ class NgVirtualListComponent {
4701
4694
  }
4702
4695
  const scroller = this._scrollerComponent();
4703
4696
  if (!!scroller) {
4704
- scroller.refresh(true, true);
4697
+ const updatebale = this._readyToShow;
4698
+ scroller.refresh(updatebale, updatebale);
4705
4699
  }
4706
4700
  };
4707
4701
  _onListResizeHandler = () => {
@@ -4714,6 +4708,9 @@ class NgVirtualListComponent {
4714
4708
  }
4715
4709
  };
4716
4710
  itemToFocus = (element, position, align = FocusAlignments.CENTER, behavior = BEHAVIOR_AUTO) => {
4711
+ if (!this._readyToShow) {
4712
+ return;
4713
+ }
4717
4714
  const scroller = this._scrollerComponent();
4718
4715
  if (scroller) {
4719
4716
  const { width, height } = this._bounds(), { width: elementWidth, height: elementHeight } = element.getBoundingClientRect(), isVertical = this._isVertical, viewportSize = isVertical ? height : width, elementSize = isVertical ? elementHeight : elementWidth;
@@ -4781,8 +4778,6 @@ class NgVirtualListComponent {
4781
4778
  this._cacheVersion.set(v);
4782
4779
  };
4783
4780
  _cacheVersion = signal(-1, ...(ngDevMode ? [{ debugName: "_cacheVersion" }] : []));
4784
- _$prepared = new BehaviorSubject$1(false);
4785
- $prepared = this._$prepared.asObservable();
4786
4781
  _$update = new Subject();
4787
4782
  $update = this._$update.asObservable();
4788
4783
  _$isResetedReachStart = new BehaviorSubject$1(true);
@@ -4797,29 +4792,15 @@ class NgVirtualListComponent {
4797
4792
  $fireUpdateNextFrame = this._$fireUpdateNextFrame.asObservable();
4798
4793
  _$snapScrollToEndCanceller = new BehaviorSubject$1(false);
4799
4794
  $snapScrollToEndCanceller = this._$snapScrollToEndCanceller.asObservable();
4800
- _onTrackBoxResetHandler = (v) => {
4801
- if (v && this._scrollerComponent()?.scrollable) {
4802
- this._$isResetedReachStart.next(true);
4803
- const scroller = this._scroller()?.nativeElement;
4804
- if (scroller) {
4805
- const params = {
4806
- [this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: 0,
4807
- behavior: BEHAVIOR_INSTANT,
4808
- blending: false,
4809
- fireUpdate: false,
4810
- userAction: false,
4811
- duration: this.animationParams().scrollToItem,
4812
- };
4813
- scroller.scrollTo(params);
4814
- }
4815
- }
4816
- };
4817
- _onPreparedHandler = (v) => {
4818
- this._$prepared.next(v);
4819
- };
4820
4795
  _destroyRef = inject(DestroyRef);
4821
4796
  _updateId;
4822
4797
  _scrollStateUpdateIndex = 0;
4798
+ _readyToShow = false;
4799
+ _isUserScrolling = false;
4800
+ _prevScrollStateVersion = EMPTY_SCROLL_STATE_VERSION;
4801
+ _updateIterations = 0;
4802
+ _$viewInit = new BehaviorSubject$1(false);
4803
+ $viewInit = this._$viewInit.asObservable();
4823
4804
  getScrollStateVersion(totalSize, scrollSize, cacheVersion) {
4824
4805
  if (totalSize < scrollSize) {
4825
4806
  this._scrollStateUpdateIndex = this._scrollStateUpdateIndex === Number.MAX_SAFE_INTEGER ? 0 : this._scrollStateUpdateIndex + 1;
@@ -4831,8 +4812,6 @@ class NgVirtualListComponent {
4831
4812
  NgVirtualListComponent.__nextId = NgVirtualListComponent.__nextId + 1 === Number.MAX_SAFE_INTEGER
4832
4813
  ? 0 : NgVirtualListComponent.__nextId + 1;
4833
4814
  this._id = NgVirtualListComponent.__nextId;
4834
- this._trackBox.addEventListener(TrackBoxEvents.RESET, this._onTrackBoxResetHandler);
4835
- this._trackBox.addEventListener(TrackBoxEvents.PREPARE, this._onPreparedHandler);
4836
4815
  this._service.initialize(this._trackBox);
4837
4816
  this._service.itemToFocus = this.itemToFocus;
4838
4817
  this._trackBox.displayComponents = this._displayComponents;
@@ -4865,34 +4844,133 @@ class NgVirtualListComponent {
4865
4844
  const dist = this.clickDistance();
4866
4845
  this._service.clickDistance = dist;
4867
4846
  });
4868
- let prepared = false, readyToStart = false, isUserScrolling = false;
4869
- let prevScrollStateVersion = EMPTY_SCROLL_STATE_VERSION, updateIterations = 0;
4870
- const $updateComplete = this.$update.pipe(takeUntilDestroyed(), debounceTime(0), switchMap$1((v) => {
4871
- if (((prevScrollStateVersion === EMPTY_SCROLL_STATE_VERSION) || (prevScrollStateVersion !== v)) &&
4872
- (updateIterations < MIN_PREPARE_ITERATIONS)) {
4847
+ const update = (params, emitable = true) => {
4848
+ const { snapScrollToBottom, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion, } = params;
4849
+ const scroller = this._scrollerComponent();
4850
+ if (scroller) {
4851
+ let actualScrollSize = !this._readyToShow && snapScrollToBottom ? (isVertical ? scroller.scrollHeight ?? 0 : scroller.scrollWidth ?? 0) :
4852
+ (isVertical ? scroller.scrollTop ?? 0 : scroller.scrollLeft ?? 0), totalSize = 0, displayItems;
4853
+ const { width, height, x, y } = bounds, viewportSize = (isVertical ? height : width);
4854
+ let scrollLength = Math.round(this._totalSize()) ?? 0, actualScrollLength = Math.round(scrollLength === 0 ? 0 : scrollLength > viewportSize ? scrollLength - viewportSize : scrollLength), roundedMaxPosition = Math.round(actualScrollLength), scrollPosition = Math.round(actualScrollSize);
4855
+ const opts = {
4856
+ bounds: { width, height, x, y }, dynamicSize, isVertical, itemSize,
4857
+ bufferSize, maxBufferSize, scrollSize: actualScrollSize, snap, enabledBufferOptimization,
4858
+ };
4859
+ if (snapScrollToBottom && !this._readyToShow) {
4860
+ const { displayItems: calculatedDisplayItems, totalSize: calculatedTotalSize1 } = this._trackBox.updateCollection(items, itemConfigMap, { ...opts, scrollSize: actualScrollSize });
4861
+ displayItems = calculatedDisplayItems;
4862
+ totalSize = calculatedTotalSize1;
4863
+ scrollLength = Math.round(totalSize) ?? 0;
4864
+ actualScrollLength = Math.round(scrollLength === 0 ? 0 : scrollLength > viewportSize ? scrollLength - viewportSize : scrollLength);
4865
+ roundedMaxPosition = Math.round(actualScrollLength);
4866
+ scrollPosition = Math.round(actualScrollSize);
4867
+ }
4868
+ else {
4869
+ const { displayItems: calculatedDisplayItems, totalSize: calculatedTotalSize } = this._trackBox.updateCollection(items, itemConfigMap, opts);
4870
+ displayItems = calculatedDisplayItems;
4871
+ totalSize = calculatedTotalSize;
4872
+ }
4873
+ scroller.totalSize = totalSize;
4874
+ this._totalSize.set(totalSize);
4875
+ this._service.collection = displayItems;
4876
+ this.resetBoundsSize(isVertical, totalSize);
4877
+ this.createDisplayComponentsIfNeed(displayItems);
4878
+ this.tracking();
4879
+ if (emitable && this._readyToShow && actualScrollLength > 0) {
4880
+ const isScrollStart = this._isUserScrolling && scrollPosition < MIN_SCROLL_TO_START_PIXELS;
4881
+ this._isScrollStart.set(isScrollStart);
4882
+ if (isScrollStart) {
4883
+ this._isScrollFinished.set(false);
4884
+ }
4885
+ else {
4886
+ this._isScrollFinished.set(scrollPosition >= roundedMaxPosition);
4887
+ }
4888
+ }
4889
+ actualScrollSize = !this._readyToShow && snapScrollToBottom ? (isVertical ? scroller.scrollHeight ?? 0 : scroller.scrollWidth ?? 0) :
4890
+ (isVertical ? scroller.scrollTop ?? 0 : scroller.scrollLeft ?? 0);
4891
+ const delta = this._trackBox.delta, roundedActualScrollSize = Math.round(actualScrollSize), scrollPositionAfterUpdate = actualScrollSize + delta, roundedScrollPositionAfterUpdate = Math.round(scrollPositionAfterUpdate), roundedMaxPositionAfterUpdate = Math.round(totalSize - viewportSize);
4892
+ if (this._isSnappingMethodAdvanced) {
4893
+ this.updateRegularRenderer();
4894
+ }
4895
+ scroller.delta = delta;
4896
+ this._trackBox.clearDelta();
4897
+ if ((snapScrollToBottom && this._trackBox.isSnappedToEnd) ||
4898
+ (snapScrollToBottom && actualScrollSize > 0 &&
4899
+ ((roundedScrollPositionAfterUpdate >= scrollPosition) &&
4900
+ (scrollPosition >= roundedMaxPosition) &&
4901
+ (roundedMaxPositionAfterUpdate >= roundedMaxPosition)))) {
4902
+ if (!this._trackBox.isSnappedToEnd) {
4903
+ this._isScrollFinished.set(true);
4904
+ }
4905
+ this._trackBox.isScrollEnd = true;
4906
+ if (emitable && this._readyToShow) {
4907
+ this.emitScrollEvent(true, false);
4908
+ }
4909
+ if (!this._readyToShow || roundedMaxPositionAfterUpdate > 0) {
4910
+ const params = {
4911
+ [isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: roundedMaxPositionAfterUpdate,
4912
+ fireUpdate: false, behavior: BEHAVIOR_INSTANT,
4913
+ blending: false, duration: this.animationParams().scrollToItem,
4914
+ };
4915
+ scroller?.scrollTo?.(params);
4916
+ if (emitable && !this._readyToShow) {
4917
+ this._$update.next(this.getScrollStateVersion(totalSize, this._isVertical ? scroller.scrollTop : scroller.scrollLeft, cacheVersion));
4918
+ }
4919
+ return;
4920
+ }
4921
+ }
4922
+ else if (roundedActualScrollSize !== roundedScrollPositionAfterUpdate && scrollPositionAfterUpdate > 0) {
4923
+ if (!snapScrollToBottom && scrollPositionAfterUpdate >= roundedMaxPosition) {
4924
+ if (!this._trackBox.isSnappedToEnd) {
4925
+ this._isScrollFinished.set(true);
4926
+ }
4927
+ }
4928
+ if (this._scrollSize() !== scrollPositionAfterUpdate) {
4929
+ const params = {
4930
+ [isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollPositionAfterUpdate, blending: true,
4931
+ fireUpdate: false, behavior: BEHAVIOR_INSTANT, duration: this.animationParams().scrollToItem,
4932
+ };
4933
+ scroller.scrollTo(params);
4934
+ if (emitable && !this._readyToShow) {
4935
+ this._$update.next(this.getScrollStateVersion(totalSize, this._isVertical ? scroller.scrollTop : scroller.scrollLeft, cacheVersion));
4936
+ }
4937
+ return;
4938
+ }
4939
+ }
4940
+ if (emitable && !this._readyToShow) {
4941
+ this._$update.next(this.getScrollStateVersion(totalSize, this._isVertical ? scroller.scrollTop : scroller.scrollLeft, cacheVersion));
4942
+ }
4943
+ }
4944
+ };
4945
+ const $updateComplete = this.$update.pipe(takeUntilDestroyed(), switchMap$1((v) => {
4946
+ if (((this._prevScrollStateVersion === EMPTY_SCROLL_STATE_VERSION) || (this._prevScrollStateVersion !== v)) &&
4947
+ (this._updateIterations < MIN_PREPARE_ITERATIONS)) {
4873
4948
  if (v !== EMPTY_SCROLL_STATE_VERSION) {
4874
- prevScrollStateVersion = v;
4949
+ this._prevScrollStateVersion = v;
4875
4950
  }
4876
4951
  this._trackBox.isScrollEnd = true;
4877
- this.updateToEnd();
4952
+ this._$fireUpdateNextFrame.next();
4878
4953
  return of(false);
4879
4954
  }
4880
- if (prevScrollStateVersion === v) {
4955
+ if (this._prevScrollStateVersion === v) {
4881
4956
  this._trackBox.isScrollEnd = true;
4882
- if (updateIterations < MIN_PREPARE_ITERATIONS) {
4883
- updateIterations++;
4884
- this.updateToEnd();
4957
+ if (this._updateIterations === RESET_CACHE_FRAME_NUMBER) {
4958
+ this.refreshActualItemSize(true);
4959
+ }
4960
+ if (this._updateIterations < PREPARATION_REUPDATE_LENGTH) {
4961
+ this._updateIterations++;
4885
4962
  this._$fireUpdateNextFrame.next();
4886
4963
  return of(false);
4887
4964
  }
4888
4965
  }
4889
- prevScrollStateVersion = v;
4966
+ this._prevScrollStateVersion = v;
4890
4967
  return of(true);
4891
- }), debounceTime(0), filter$1(v => !!v), distinctUntilChanged()), $items = toObservable(this.items).pipe(takeUntilDestroyed(), map(i => !i ? [] : i)), $dynamicSize = toObservable(this.dynamicSize);
4892
- const $snapScrollToBottom = toObservable(this.snapScrollToBottom), $waitForPreparation = toObservable(this.waitForPreparation);
4893
- combineLatest([$dynamicSize, $snapScrollToBottom, $waitForPreparation]).pipe(takeUntilDestroyed(), switchMap$1(([dynamicSize, snapScrollToBottom, waitForPreparation]) => {
4968
+ }), filter$1(v => !!v), distinctUntilChanged()), $items = toObservable(this.items), $dynamicSize = toObservable(this.dynamicSize);
4969
+ const $viewInit = this.$viewInit, $snapScrollToBottom = toObservable(this.snapScrollToBottom), $waitForPreparation = toObservable(this.waitForPreparation);
4970
+ combineLatest([$dynamicSize, $snapScrollToBottom, $waitForPreparation]).pipe(takeUntilDestroyed(this._destroyRef), distinctUntilChanged(), switchMap$1(([dynamicSize, snapScrollToBottom, waitForPreparation]) => {
4894
4971
  if (!dynamicSize || !snapScrollToBottom || !waitForPreparation) {
4895
- prepared = readyToStart = true;
4972
+ this._readyToShow = true;
4973
+ this.refreshActualItemSize(true);
4896
4974
  const scrollerComponent = this._scrollerComponent();
4897
4975
  if (scrollerComponent) {
4898
4976
  scrollerComponent.prepared = true;
@@ -4903,60 +4981,76 @@ class NgVirtualListComponent {
4903
4981
  return of(false);
4904
4982
  }
4905
4983
  if (!!dynamicSize && !!snapScrollToBottom && !!waitForPreparation) {
4906
- return this.$prepared.pipe(takeUntilDestroyed(this._destroyRef), distinctUntilChanged(), switchMap$1(v => {
4984
+ this._$show.next(false);
4985
+ this.cacheClean();
4986
+ this._readyToShow = this._isUserScrolling = false;
4987
+ const scrollerComponent = this._scrollerComponent();
4988
+ if (scrollerComponent) {
4989
+ scrollerComponent.prepared = false;
4990
+ scrollerComponent.stopScrolling();
4991
+ }
4992
+ this.classes.set({ prepared: false, [READY_TO_START]: false, [WAIT_FOR_PREPARATION]: false });
4993
+ return $items.pipe(takeUntilDestroyed(this._destroyRef), map(i => (i ?? []).length > 0), distinctUntilChanged(), switchMap$1(v => {
4907
4994
  if (!v) {
4908
- this._$show.next(false);
4909
- readyToStart = isUserScrolling = prepared = false;
4910
4995
  this.cacheClean();
4996
+ this._readyToShow = this._isUserScrolling = false;
4997
+ this.refreshActualItemSize(false);
4998
+ this._trackBox.isScrollEnd = true;
4999
+ this._updateIterations = 0;
5000
+ this._prevScrollStateVersion = EMPTY_SCROLL_STATE_VERSION;
4911
5001
  const scrollerComponent = this._scrollerComponent();
4912
5002
  if (scrollerComponent) {
4913
5003
  scrollerComponent.prepared = false;
4914
5004
  scrollerComponent.stopScrolling();
4915
5005
  }
4916
- this.classes.set({ prepared: v, [READY_TO_START]: false, [WAIT_FOR_PREPARATION]: false });
4917
- this._service.update(true);
5006
+ this.classes.set({ prepared: false, [READY_TO_START]: false, [WAIT_FOR_PREPARATION]: false });
5007
+ this._$show.next(false);
4918
5008
  return of(false);
4919
5009
  }
4920
- return of(true).pipe(takeUntilDestroyed(this._destroyRef), switchMap$1(v => {
5010
+ return of(true).pipe(takeUntilDestroyed(this._destroyRef), switchMap$1(() => {
4921
5011
  const waitForPreparation = this.waitForPreparation();
4922
5012
  if (waitForPreparation) {
4923
- prevScrollStateVersion = EMPTY_SCROLL_STATE_VERSION;
4924
- updateIterations = 0;
5013
+ this.refreshActualItemSize(false);
4925
5014
  return $updateComplete.pipe(takeUntilDestroyed(this._destroyRef), take(1), tap(() => {
4926
- prepared = readyToStart = true;
5015
+ this._readyToShow = true;
4927
5016
  const waitForPreparation = this.waitForPreparation(), scrollerComponent = this._scrollerComponent();
4928
5017
  if (scrollerComponent) {
4929
5018
  scrollerComponent.prepared = true;
4930
5019
  scrollerComponent.stopScrolling();
4931
5020
  }
4932
5021
  this.classes.set({ prepared: true, [READY_TO_START]: true, [WAIT_FOR_PREPARATION]: waitForPreparation });
4933
- this._service.update(true);
4934
5022
  this._$show.next(true);
5023
+ }), tap(() => {
5024
+ this.refreshActualItemSize(true);
5025
+ this._scrollerComponent()?.refresh(true, true);
4935
5026
  }));
4936
5027
  }
4937
- prepared = readyToStart = true;
5028
+ this._readyToShow = true;
4938
5029
  const scrollerComponent = this._scrollerComponent();
4939
5030
  if (scrollerComponent) {
4940
5031
  scrollerComponent.prepared = true;
4941
5032
  scrollerComponent.stopScrolling();
4942
5033
  }
4943
5034
  this.classes.set({ prepared: true, [READY_TO_START]: true, [WAIT_FOR_PREPARATION]: waitForPreparation });
4944
- this._service.update(true);
4945
5035
  this._$show.next(true);
4946
5036
  return of(false);
4947
5037
  }));
4948
5038
  }));
4949
5039
  }
4950
- prepared = readyToStart = true;
4951
- const scrollerComponent = this._scrollerComponent();
4952
- if (scrollerComponent) {
4953
- scrollerComponent.prepared = true;
4954
- scrollerComponent.stopScrolling();
5040
+ else {
5041
+ this._readyToShow = true;
5042
+ this.refreshActualItemSize(true);
5043
+ const scrollerComponent = this._scrollerComponent();
5044
+ if (scrollerComponent) {
5045
+ scrollerComponent.prepared = true;
5046
+ scrollerComponent.stopScrolling();
5047
+ }
5048
+ this.classes.set({ prepared: true, [READY_TO_START]: true, [WAIT_FOR_PREPARATION]: false });
5049
+ this._service.update(true);
5050
+ this._$show.next(true);
5051
+ this._scrollerComponent()?.refresh(true, true);
5052
+ return of(false);
4955
5053
  }
4956
- this.classes.set({ prepared: true, [READY_TO_START]: true, [WAIT_FOR_PREPARATION]: false });
4957
- this._service.update(true);
4958
- this._$show.next(true);
4959
- return of(false);
4960
5054
  })).subscribe();
4961
5055
  this._service.$focusedId.pipe(takeUntilDestroyed(), tap(v => {
4962
5056
  this.focusedElement.set(v ?? undefined);
@@ -4992,7 +5086,7 @@ class NgVirtualListComponent {
4992
5086
  isResetedReachStart = v;
4993
5087
  })).subscribe();
4994
5088
  $isScrollStart.pipe(takeUntilDestroyed(), distinctUntilChanged(), debounceTime(0), tap(v => {
4995
- if (readyToStart && v && !isResetedReachStart && this._scrollerComponent()?.scrollable) {
5089
+ if (this._readyToShow && v && !isResetedReachStart && this._scrollerComponent()?.scrollable) {
4996
5090
  this._trackBox.isScrollStart = true;
4997
5091
  this.onScrollReachStart.emit();
4998
5092
  }
@@ -5000,7 +5094,7 @@ class NgVirtualListComponent {
5000
5094
  })).subscribe();
5001
5095
  $isScrollFinished.pipe(takeUntilDestroyed(), distinctUntilChanged(), debounceTime(0), tap(v => {
5002
5096
  this._trackBox.isScrollEnd = v;
5003
- if (readyToStart && v && this._scrollerComponent()?.scrollable) {
5097
+ if (this._readyToShow && v && this._scrollerComponent()?.scrollable) {
5004
5098
  this.onScrollReachEnd.emit();
5005
5099
  }
5006
5100
  })).subscribe();
@@ -5013,17 +5107,31 @@ class NgVirtualListComponent {
5013
5107
  $trackBy.pipe(takeUntilDestroyed(), tap(v => {
5014
5108
  this._trackBox.trackingPropertyName = v;
5015
5109
  })).subscribe();
5016
- const $bounds = toObservable(this._bounds).pipe(filter$1(b => !!b)), $listBounds = toObservable(this._listBounds).pipe(filter$1(b => !!b)), $scrollSize = toObservable(this._scrollSize), $itemSize = toObservable(this.itemSize).pipe(map(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $bufferSize = toObservable(this.bufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $maxBufferSize = toObservable(this.maxBufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $itemConfigMap = toObservable(this.itemConfigMap).pipe(map(v => !v ? {} : v)), $snap = toObservable(this.snap), $isLazy = toObservable(this.collectionMode).pipe(map(v => this.getIsLazy(v || DEFAULT_COLLECTION_MODE))), $enabledBufferOptimization = toObservable(this.enabledBufferOptimization), $snappingMethod = toObservable(this.snappingMethod).pipe(map(v => this.getIsSnappingMethodAdvanced(v || DEFAULT_SNAPPING_METHOD))), $methodForSelecting = toObservable(this.methodForSelecting), $selectedIds = toObservable(this.selectedIds), $collapsedIds = toObservable(this.collapsedIds).pipe(map(v => Array.isArray(v) ? v : [])), $collapsedItemIds = toObservable(this._collapsedItemIds).pipe(map(v => Array.isArray(v) ? v : [])), $actualItems = toObservable(this._actualItems), $screenReaderMessage = toObservable(this.screenReaderMessage), $displayItems = this._service.$displayItems, $cacheVersion = toObservable(this._cacheVersion);
5110
+ const $bounds = toObservable(this._bounds).pipe(filter$1(b => !!b)), $listBounds = toObservable(this._listBounds).pipe(filter$1(b => !!b)), $scrollSize = toObservable(this._scrollSize), $itemSize = toObservable(this.actualItemSize).pipe(map(v => v <= 0 ? DEFAULT_ITEM_SIZE : v)), $bufferSize = toObservable(this.bufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $maxBufferSize = toObservable(this.maxBufferSize).pipe(map(v => v < 0 ? DEFAULT_BUFFER_SIZE : v)), $itemConfigMap = toObservable(this.itemConfigMap).pipe(map(v => !v ? {} : v)), $snap = toObservable(this.snap), $isLazy = toObservable(this.collectionMode).pipe(map(v => this.getIsLazy(v || DEFAULT_COLLECTION_MODE))), $enabledBufferOptimization = toObservable(this.enabledBufferOptimization), $snappingMethod = toObservable(this.snappingMethod).pipe(map(v => this.getIsSnappingMethodAdvanced(v || DEFAULT_SNAPPING_METHOD))), $methodForSelecting = toObservable(this.methodForSelecting), $selectedIds = toObservable(this.selectedIds), $collapsedIds = toObservable(this.collapsedIds).pipe(map(v => Array.isArray(v) ? v : [])), $collapsedItemIds = toObservable(this._collapsedItemIds).pipe(map(v => Array.isArray(v) ? v : [])), $actualItems = toObservable(this._actualItems), $screenReaderMessage = toObservable(this.screenReaderMessage), $displayItems = this._service.$displayItems, $cacheVersion = toObservable(this._cacheVersion);
5017
5111
  combineLatest([$displayItems, $screenReaderMessage, $isVertical, $scrollSize, $bounds]).pipe(takeUntilDestroyed(), distinctUntilChanged(), debounceTime(100), takeUntilDestroyed(), tap(([items, screenReaderMessage, isVertical, scrollSize, bounds]) => {
5018
5112
  this.screenReaderFormattedMessage.set(formatScreenReaderMessage(items, screenReaderMessage, scrollSize, isVertical, bounds));
5019
5113
  })).subscribe();
5020
5114
  $isLazy.pipe(takeUntilDestroyed(), tap(v => {
5021
5115
  this._trackBox.isLazy = v;
5022
5116
  })).subscribe();
5023
- combineLatest([$items, $itemSize]).pipe(takeUntilDestroyed(), map(([items, itemSize]) => ({ items, itemSize })), tap(({ items, itemSize }) => {
5024
- this._trackBox.resetCollection(items, itemSize);
5117
+ $items.pipe(takeUntilDestroyed(), debounceTime(0), tap(items => {
5118
+ this._trackBox.resetCollection(items, this.actualItemSize());
5119
+ if (!this._readyToShow) {
5120
+ this._readyToShow = this._isUserScrolling = false;
5121
+ this.refreshActualItemSize(false);
5122
+ this._trackBox.isScrollEnd = true;
5123
+ this._updateIterations = 0;
5124
+ this._prevScrollStateVersion = EMPTY_SCROLL_STATE_VERSION;
5125
+ const scrollerComponent = this._scrollerComponent();
5126
+ if (scrollerComponent) {
5127
+ scrollerComponent.prepared = false;
5128
+ scrollerComponent.stopScrolling();
5129
+ }
5130
+ this.classes.set({ prepared: false, [READY_TO_START]: false, [WAIT_FOR_PREPARATION]: false });
5131
+ this._$show.next(false);
5132
+ }
5025
5133
  })).subscribe();
5026
- combineLatest([$items, $collapsedItemIds, $itemConfigMap, $trackBy]).pipe(takeUntilDestroyed(), tap(([items, collapsedIds, itemConfigMap, trackBy]) => {
5134
+ combineLatest([$items, $collapsedItemIds, $itemConfigMap, $trackBy]).pipe(takeUntilDestroyed(), debounceTime(0), tap(([items, collapsedIds, itemConfigMap, trackBy]) => {
5027
5135
  const hiddenItems = new CMap();
5028
5136
  let isCollapsed = false;
5029
5137
  for (let i = 0, l = items.length; i < l; i++) {
@@ -5087,131 +5195,47 @@ class NgVirtualListComponent {
5087
5195
  })).subscribe();
5088
5196
  const $snapScrollToEndCanceller = this.$snapScrollToEndCanceller;
5089
5197
  $snapScrollToEndCanceller.pipe(takeUntilDestroyed(), filter$1(v => !!v), tap((v) => {
5090
- const scroller = this._scrollerComponent();
5091
- if (scroller) {
5092
- this._trackBox.cancelScrollSnappingToEnd(true);
5198
+ if (this._readyToShow) {
5199
+ const scroller = this._scrollerComponent();
5200
+ if (scroller) {
5201
+ this._trackBox.cancelScrollSnappingToEnd(true);
5202
+ }
5093
5203
  }
5094
5204
  }), tap(() => {
5095
- this._$snapScrollToEndCanceller.next(false);
5096
- })).subscribe();
5097
- const update = (params) => {
5098
- const { snapScrollToBottom, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion, } = params;
5099
- const scroller = this._scrollerComponent();
5100
- if (scroller) {
5101
- let actualScrollSize = !prepared && snapScrollToBottom ? (isVertical ? scroller.scrollHeight ?? 0 : scroller.scrollWidth ?? 0) :
5102
- (isVertical ? scroller.scrollTop ?? 0 : scroller.scrollLeft ?? 0), totalSize = 0, displayItems;
5103
- const { width, height, x, y } = bounds, viewportSize = (isVertical ? height : width);
5104
- let scrollLength = Math.round(this._totalSize()) ?? 0, actualScrollLength = Math.round(scrollLength === 0 ? 0 : scrollLength > viewportSize ? scrollLength - viewportSize : scrollLength), roundedMaxPosition = Math.round(actualScrollLength), scrollPosition = Math.round(actualScrollSize);
5105
- const opts = {
5106
- bounds: { width, height, x, y }, dynamicSize, isVertical, itemSize,
5107
- bufferSize, maxBufferSize, scrollSize: actualScrollSize, snap, enabledBufferOptimization,
5108
- };
5109
- if (snapScrollToBottom && !prepared) {
5110
- const { displayItems: calculatedDisplayItems, totalSize: calculatedTotalSize1 } = this._trackBox.updateCollection(items, itemConfigMap, { ...opts, scrollSize: actualScrollSize });
5111
- displayItems = calculatedDisplayItems;
5112
- totalSize = calculatedTotalSize1;
5113
- scrollLength = Math.round(totalSize) ?? 0;
5114
- actualScrollLength = Math.round(scrollLength === 0 ? 0 : scrollLength > viewportSize ? scrollLength - viewportSize : scrollLength);
5115
- roundedMaxPosition = Math.round(actualScrollLength);
5116
- scrollPosition = Math.round(actualScrollSize);
5117
- }
5118
- else {
5119
- const { displayItems: calculatedDisplayItems, totalSize: calculatedTotalSize } = this._trackBox.updateCollection(items, itemConfigMap, opts);
5120
- displayItems = calculatedDisplayItems;
5121
- totalSize = calculatedTotalSize;
5122
- }
5123
- scroller.totalSize = totalSize;
5124
- this._totalSize.set(totalSize);
5125
- this._service.collection = displayItems;
5126
- this.resetBoundsSize(isVertical, totalSize);
5127
- this.createDisplayComponentsIfNeed(displayItems);
5128
- this.tracking();
5129
- if (prepared && readyToStart && actualScrollLength > 0) {
5130
- const isScrollStart = isUserScrolling && scrollPosition < MIN_SCROLL_TO_START_PIXELS;
5131
- this._isScrollStart.set(isScrollStart);
5132
- if (isScrollStart) {
5133
- this._isScrollFinished.set(false);
5134
- }
5135
- else {
5136
- this._isScrollFinished.set(scrollPosition >= roundedMaxPosition);
5137
- }
5138
- }
5139
- actualScrollSize = !prepared && snapScrollToBottom ? (isVertical ? scroller.scrollHeight ?? 0 : scroller.scrollWidth ?? 0) :
5140
- (isVertical ? scroller.scrollTop ?? 0 : scroller.scrollLeft ?? 0);
5141
- const delta = this._trackBox.delta, roundedActualScrollSize = Math.round(actualScrollSize), scrollPositionAfterUpdate = actualScrollSize + delta, roundedScrollPositionAfterUpdate = Math.round(scrollPositionAfterUpdate), roundedMaxPositionAfterUpdate = Math.round(totalSize - viewportSize);
5142
- if (this._isSnappingMethodAdvanced) {
5143
- this.updateRegularRenderer();
5144
- }
5145
- scroller.delta = delta;
5146
- this._trackBox.clearDelta();
5147
- if ((snapScrollToBottom && this._trackBox.isSnappedToEnd) ||
5148
- (snapScrollToBottom && actualScrollSize > 0 &&
5149
- ((roundedScrollPositionAfterUpdate >= scrollPosition) &&
5150
- (scrollPosition >= roundedMaxPosition) &&
5151
- (roundedMaxPositionAfterUpdate >= roundedMaxPosition)))) {
5152
- if (!this._trackBox.isSnappedToEnd) {
5153
- this._isScrollFinished.set(true);
5154
- }
5155
- this._trackBox.isScrollEnd = true;
5156
- if (prepared && readyToStart) {
5157
- this.emitScrollEvent(true, false);
5158
- }
5159
- if (roundedMaxPositionAfterUpdate > 0) {
5160
- const params = {
5161
- [isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: roundedMaxPositionAfterUpdate,
5162
- fireUpdate: false, behavior: BEHAVIOR_INSTANT,
5163
- blending: scroller.isMoving, duration: this.animationParams().scrollToItem,
5164
- };
5165
- scroller?.scrollTo?.(params);
5166
- this._$update.next(this.getScrollStateVersion(totalSize, this._isVertical ? scroller.scrollTop : scroller.scrollLeft, cacheVersion));
5167
- return;
5168
- }
5169
- }
5170
- else if (roundedActualScrollSize !== roundedScrollPositionAfterUpdate && scrollPositionAfterUpdate > 0) {
5171
- if (!snapScrollToBottom && scrollPositionAfterUpdate >= roundedMaxPosition) {
5172
- if (!this._trackBox.isSnappedToEnd) {
5173
- this._isScrollFinished.set(true);
5174
- }
5175
- }
5176
- if (this._scrollSize() !== scrollPositionAfterUpdate) {
5177
- const params = {
5178
- [isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollPositionAfterUpdate, blending: prepared && readyToStart,
5179
- fireUpdate: false, behavior: BEHAVIOR_INSTANT, duration: this.animationParams().scrollToItem,
5180
- };
5181
- scroller.scrollTo(params);
5182
- this._$update.next(this.getScrollStateVersion(totalSize, this._isVertical ? scroller.scrollTop : scroller.scrollLeft, cacheVersion));
5183
- return;
5184
- }
5185
- }
5186
- if (!prepared && !readyToStart) {
5187
- this._$update.next(this.getScrollStateVersion(totalSize, this._isVertical ? scroller.scrollTop : scroller.scrollLeft, cacheVersion));
5188
- }
5205
+ if (this._readyToShow) {
5206
+ this._$snapScrollToEndCanceller.next(false);
5189
5207
  }
5190
- };
5191
- combineLatest([$snapScrollToBottom, $bounds, $listBounds, $scrollEndOffset, $actualItems, $itemConfigMap, $scrollSize, $itemSize,
5192
- $bufferSize, $maxBufferSize, $snap, $isVertical, $dynamicSize, $enabledBufferOptimization, $cacheVersion, this.$fireUpdate,
5193
- ]).pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(([snapScrollToBottom, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,]) => {
5194
- update({
5195
- snapScrollToBottom, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize,
5196
- bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,
5197
- });
5198
5208
  })).subscribe();
5199
- combineLatest([$items, $dynamicSize]).pipe(takeUntilDestroyed(), filter$1(([, dynamic]) => !dynamic), delay(0), takeUntilDestroyed(), tap(() => {
5209
+ $viewInit.pipe(takeUntilDestroyed(), filter$1(v => !!v), switchMap$1(() => {
5210
+ return combineLatest([$snapScrollToBottom, $bounds, $listBounds, $scrollEndOffset, $actualItems, $itemConfigMap, $scrollSize, $itemSize,
5211
+ $bufferSize, $maxBufferSize, $snap, $isVertical, $dynamicSize, $enabledBufferOptimization, $cacheVersion, this.$fireUpdate,
5212
+ ]).pipe(takeUntilDestroyed(this._destroyRef), distinctUntilChanged(), tap(([snapScrollToBottom, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,]) => {
5213
+ update({
5214
+ snapScrollToBottom, bounds, listBounds, scrollEndOffset, items, itemConfigMap, scrollSize, itemSize,
5215
+ bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,
5216
+ });
5217
+ }));
5218
+ })).subscribe();
5219
+ combineLatest([$items, $dynamicSize]).pipe(takeUntilDestroyed(), debounceTime(0), filter$1(([, dynamic]) => !dynamic), delay(0), takeUntilDestroyed(), tap(() => {
5200
5220
  this._scrollerComponent()?.refresh(true);
5201
5221
  })).subscribe();
5202
5222
  const $scroller = toObservable(this._scroller).pipe(takeUntilDestroyed(), filter$1(v => !!v), map(v => v.nativeElement), take(1)), $scrollerScroll = toObservable(this._scrollerComponent).pipe(takeUntilDestroyed(), filter$1(v => !!v), take(1), switchMap$1(scroller => scroller.$scroll)), $scrollerScrollEnd = toObservable(this._scrollerComponent).pipe(takeUntilDestroyed(), filter$1(v => !!v), take(1), switchMap$1(scroller => scroller.$scrollEnd)), $list = toObservable(this._list).pipe(takeUntilDestroyed(), filter$1(v => !!v), map(v => v.nativeElement), take(1));
5203
5223
  $scroller.pipe(takeUntilDestroyed(), distinctUntilChanged(), switchMap$1(scroller => {
5204
5224
  return fromEvent(scroller, SCROLLER_WHEEL, { passive: true }).pipe(takeUntilDestroyed(this._destroyRef), filter$1(() => {
5205
- return !!this._trackBox.isSnappedToEnd;
5225
+ return !!this._trackBox.isSnappedToEnd && this._readyToShow;
5206
5226
  }), tap(() => {
5207
- this._$snapScrollToEndCanceller.next(true);
5227
+ if (this._readyToShow) {
5228
+ this._$snapScrollToEndCanceller.next(true);
5229
+ }
5208
5230
  }));
5209
5231
  })).subscribe();
5210
5232
  $scroller.pipe(takeUntilDestroyed(), distinctUntilChanged(), switchMap$1(scroller => {
5211
5233
  return fromEvent(scroller, SCROLLER_SCROLLBAR_SCROLL, { passive: true }).pipe(takeUntilDestroyed(this._destroyRef), filter$1(() => {
5212
5234
  return !!this._trackBox.isSnappedToEnd;
5213
5235
  }), tap(() => {
5214
- this._$snapScrollToEndCanceller.next(true);
5236
+ if (this._readyToShow) {
5237
+ this._$snapScrollToEndCanceller.next(true);
5238
+ }
5215
5239
  }));
5216
5240
  })).subscribe();
5217
5241
  const $docPointerUp = fromEvent(document, MOUSE_UP, { passive: true }).pipe(take(1)), $docPointerLeave = fromEvent(document, MOUSE_LEAVE, { passive: true }).pipe(take(1)), $docPointerOut = fromEvent(document, MOUSE_OUT, { passive: true }).pipe(take(1)), $pointerMoveTakeUntil = race([$docPointerUp, $docPointerLeave, $docPointerOut]).pipe(takeUntilDestroyed(), take(1));
@@ -5228,14 +5252,16 @@ class NgVirtualListComponent {
5228
5252
  }
5229
5253
  return 0;
5230
5254
  }), tap(() => {
5231
- this._$snapScrollToEndCanceller.next(true);
5255
+ if (this._readyToShow) {
5256
+ this._$snapScrollToEndCanceller.next(true);
5257
+ }
5232
5258
  }));
5233
5259
  })).subscribe();
5234
5260
  const $docTouchUp = fromEvent(document, TOUCH_END, { passive: true }).pipe(take(1)), $docTouchLeave = fromEvent(document, TOUCH_LEAVE, { passive: true }).pipe(take(1)), $docTouchOut = fromEvent(document, TOUCH_OUT, { passive: true }).pipe(take(1)), $touchMoveTakeUntil = race([$docTouchUp, $docTouchLeave, $docTouchOut]).pipe(takeUntilDestroyed(), take(1));
5235
5261
  $scroller.pipe(takeUntilDestroyed(), distinctUntilChanged(), switchMap$1(scroller => {
5236
5262
  return fromEvent(scroller, TOUCH_START, { passive: true }).pipe(takeUntilDestroyed(this._destroyRef), switchMap$1(e => {
5237
5263
  return $scrollerScroll.pipe(takeUntilDestroyed(this._destroyRef), takeUntil$1($touchMoveTakeUntil), filter$1(() => {
5238
- return !!this._trackBox.isSnappedToEnd;
5264
+ return !!this._trackBox.isSnappedToEnd && this._readyToShow;
5239
5265
  }));
5240
5266
  }), map(e => {
5241
5267
  const scroller = this._scrollerComponent();
@@ -5245,18 +5271,22 @@ class NgVirtualListComponent {
5245
5271
  }
5246
5272
  return 0;
5247
5273
  }), tap(() => {
5248
- this._$snapScrollToEndCanceller.next(true);
5274
+ if (this._readyToShow) {
5275
+ this._$snapScrollToEndCanceller.next(true);
5276
+ }
5249
5277
  }));
5250
5278
  })).subscribe();
5251
5279
  $scroller.pipe(takeUntilDestroyed(), distinctUntilChanged(), switchMap$1(scroller => {
5252
5280
  return $scrollerScroll.pipe(takeUntilDestroyed(this._destroyRef));
5253
5281
  }), tap(userAction => {
5254
- isUserScrolling = userAction;
5282
+ this._isUserScrolling = userAction;
5255
5283
  const scrollerEl = this._scroller()?.nativeElement, scrollerComponent = this._scrollerComponent();
5256
5284
  if (scrollerEl && scrollerComponent) {
5257
- const event = this.emitScrollEvent(false);
5285
+ const event = this.emitScrollEvent(false, this._readyToShow);
5258
5286
  if (userAction) {
5259
- this._$snapScrollToEndCanceller.next(true);
5287
+ if (this._readyToShow) {
5288
+ this._$snapScrollToEndCanceller.next(true);
5289
+ }
5260
5290
  if (!this.dynamicSize()) {
5261
5291
  this._$fireUpdate.next(event);
5262
5292
  }
@@ -5266,12 +5296,14 @@ class NgVirtualListComponent {
5266
5296
  $scroller.pipe(takeUntilDestroyed(), distinctUntilChanged(), switchMap$1(scroller => {
5267
5297
  return $scrollerScrollEnd.pipe(takeUntilDestroyed(this._destroyRef));
5268
5298
  }), tap(userAction => {
5269
- isUserScrolling = userAction;
5299
+ this._isUserScrolling = userAction;
5270
5300
  const scrollerEl = this._scroller()?.nativeElement, scrollerComponent = this._scrollerComponent();
5271
5301
  if (scrollerEl && scrollerComponent) {
5272
- const event = this.emitScrollEvent(true);
5302
+ const event = this.emitScrollEvent(true, this._readyToShow);
5273
5303
  if (userAction) {
5274
- this._$snapScrollToEndCanceller.next(true);
5304
+ if (this._readyToShow) {
5305
+ this._$snapScrollToEndCanceller.next(true);
5306
+ }
5275
5307
  if (!this.dynamicSize()) {
5276
5308
  this._$fireUpdate.next(event);
5277
5309
  }
@@ -5284,9 +5316,11 @@ class NgVirtualListComponent {
5284
5316
  const scroller = this._scrollerComponent();
5285
5317
  if (scroller) {
5286
5318
  const isVertical = this._isVertical, bounds = this._bounds(), listBounds = this._listBounds(), scrollSize = (isVertical ? scroller.scrollTop : scroller.scrollLeft), scrollLength = isVertical ? (listBounds?.height ?? 0) - (bounds?.height ?? 0) : (listBounds?.width ?? 0) - (bounds?.width ?? 0), actualScrollSize = scrollSize;
5287
- if (this._trackBox.isSnappedToEnd) {
5288
- if (scrollSize < scrollLength) {
5289
- this._trackBox.cancelScrollSnappingToEnd();
5319
+ if (this._readyToShow) {
5320
+ if (this._trackBox.isSnappedToEnd) {
5321
+ if (scrollSize < scrollLength) {
5322
+ this._trackBox.cancelScrollSnappingToEnd();
5323
+ }
5290
5324
  }
5291
5325
  }
5292
5326
  this._scrollSize.set(actualScrollSize);
@@ -5310,14 +5344,14 @@ class NgVirtualListComponent {
5310
5344
  })).subscribe();
5311
5345
  const $scrollTo = this.$scrollTo;
5312
5346
  combineLatest([$scroller, $trackBy, $scrollTo]).pipe(takeUntilDestroyed(), filter$1(([scroller]) => scroller !== undefined), map(([scroller, trackBy, event]) => ({ scroller: scroller, trackBy, event })), switchMap$1(({ scroller, trackBy, event }) => {
5313
- if (!prepared || !readyToStart) {
5347
+ if (!this._readyToShow) {
5314
5348
  return of([false]);
5315
5349
  }
5316
5350
  const scrollerComponent = this._scrollerComponent(), { id, iteration = 0, blending = false, isLastIteration = false, scrollCalled = false, cb, } = event;
5317
5351
  if (scrollerComponent) {
5318
5352
  const items = this._actualItems();
5319
5353
  if (items && items.length) {
5320
- const dynamicSize = this.dynamicSize(), itemSize = this.itemSize();
5354
+ const dynamicSize = this.dynamicSize(), itemSize = this.actualItemSize();
5321
5355
  if (dynamicSize) {
5322
5356
  const { width, height, x, y } = this._bounds() || { x: 0, y: 0, width: DEFAULT_LIST_SIZE, height: DEFAULT_LIST_SIZE }, itemConfigMap = this.itemConfigMap(), items = this._actualItems(), isVertical = this._isVertical, currentScrollSize = (isVertical ? scrollerComponent.scrollTop : scrollerComponent.scrollLeft), delta = this._trackBox.delta, opts = {
5323
5357
  bounds: { width, height, x, y }, collection: items, dynamicSize, isVertical: this._isVertical, itemSize,
@@ -5348,8 +5382,9 @@ class NgVirtualListComponent {
5348
5382
  }
5349
5383
  this._$snapScrollToEndCanceller.next(true);
5350
5384
  const notChanged = actualScrollSize === currentScrollSize;
5351
- scrollerComponent?.scrollTo?.(params);
5352
- if ((!notChanged && iteration < MAX_SCROLL_TO_ITERATIONS) || iteration < MAX_SCROLL_TO_ITERATIONS) {
5385
+ if ((!notChanged && iteration < MAX_SCROLL_TO_ITERATIONS) ||
5386
+ (!this.snapScrollToBottom() && iteration < MAX_SCROLL_TO_ITERATIONS)) {
5387
+ scrollerComponent?.scrollTo?.(params);
5353
5388
  this._$scrollTo.next(params);
5354
5389
  return of([false, {
5355
5390
  id, scroller: scrollerComponent, iteration: iteration + 1, blending,
@@ -5364,7 +5399,7 @@ class NgVirtualListComponent {
5364
5399
  else {
5365
5400
  const index = items.findIndex(item => item[trackBy] === id);
5366
5401
  if (index > -1) {
5367
- const isVertical = this._isVertical, currentScrollSize = (isVertical ? scrollerComponent.scrollTop : scrollerComponent.scrollLeft), scrollSize = index * this.itemSize();
5402
+ const isVertical = this._isVertical, currentScrollSize = (isVertical ? scrollerComponent.scrollTop : scrollerComponent.scrollLeft), scrollSize = index * this.actualItemSize();
5368
5403
  if (currentScrollSize !== scrollSize) {
5369
5404
  this._$snapScrollToEndCanceller.next(true);
5370
5405
  const params = {
@@ -5383,10 +5418,12 @@ class NgVirtualListComponent {
5383
5418
  if (!finished) {
5384
5419
  if (!!params) {
5385
5420
  this._$scrollTo.next(params);
5421
+ return;
5386
5422
  }
5387
- return;
5388
5423
  }
5389
- this._trackBox.cancelScrollSnappingToEnd(true);
5424
+ if (this._readyToShow) {
5425
+ this._trackBox.cancelScrollSnappingToEnd(true);
5426
+ }
5390
5427
  const p = params;
5391
5428
  if (p.scrollCalled && p.scroller) {
5392
5429
  this._scrollerComponent()?.refresh();
@@ -5446,6 +5483,9 @@ class NgVirtualListComponent {
5446
5483
  $collapsedIds.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
5447
5484
  this._service.setCollapsedIds(v);
5448
5485
  })).subscribe();
5486
+ }
5487
+ ngAfterViewInit() {
5488
+ this._$viewInit.next(true);
5449
5489
  this._$fireUpdate.next({
5450
5490
  scrollSize: 0,
5451
5491
  scrollWeight: 0,
@@ -5496,6 +5536,24 @@ class NgVirtualListComponent {
5496
5536
  }
5497
5537
  }
5498
5538
  }
5539
+ refreshActualItemSize(value) {
5540
+ if (!this.waitForPreparation()) {
5541
+ return;
5542
+ }
5543
+ let size;
5544
+ const bounds = this._bounds();
5545
+ if (value === false) {
5546
+ size = (this._isVertical ?
5547
+ bounds?.height || DEFAULT_LIST_SIZE :
5548
+ bounds?.width || DEFAULT_LIST_SIZE);
5549
+ this.actualItemSize.set(size);
5550
+ }
5551
+ else {
5552
+ size = this.itemSize();
5553
+ this.actualItemSize.set(size);
5554
+ }
5555
+ this._trackBox.resetCache(this._actualItems(), this.trackBy(), this._isVertical, size, bounds);
5556
+ }
5499
5557
  getIsSnappingMethodAdvanced(m) {
5500
5558
  const method = m || this.snappingMethod();
5501
5559
  return isSnappingMethodAdvenced(method);
@@ -5578,17 +5636,6 @@ class NgVirtualListComponent {
5578
5636
  l.nativeElement.style[prop] = `${size}${PX$2}`;
5579
5637
  }
5580
5638
  }
5581
- updateToEnd() {
5582
- const scroller = this._scrollerComponent();
5583
- if (!!scroller) {
5584
- const isVerrtical = this._isVertical, actualScrollSize = isVerrtical ? (scroller?.scrollHeight ?? 0) : (scroller?.scrollWidth ?? 0), params = {
5585
- [isVerrtical ? TOP_PROP_NAME : LEFT_PROP_NAME]: actualScrollSize,
5586
- blending: false, fireUpdate: true, userAction: false, behavior: BEHAVIOR_INSTANT,
5587
- };
5588
- scroller.scrollTo(params);
5589
- scroller.refresh();
5590
- }
5591
- }
5592
5639
  /**
5593
5640
  * Returns the bounds of an element with a given id
5594
5641
  */
@@ -5684,7 +5731,9 @@ class NgVirtualListComponent {
5684
5731
  if (scrollerComponent) {
5685
5732
  scrollerComponent.reset();
5686
5733
  }
5687
- this._$prepared.next(false);
5734
+ if (this._scrollerComponent()?.scrollable) {
5735
+ this._$isResetedReachStart.next(true);
5736
+ }
5688
5737
  }
5689
5738
  /**
5690
5739
  * Stops the list from snapping to the bottom edge.