@angular/cdk-experimental 21.0.0-next.9 → 21.0.0-rc.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.
@@ -4,441 +4,324 @@ import * as i0 from '@angular/core';
4
4
  import { forwardRef, Directive, Input, NgModule } from '@angular/core';
5
5
  import { Observable } from 'rxjs';
6
6
 
7
- /**
8
- * A class that tracks the size of items that have been seen and uses it to estimate the average
9
- * item size.
10
- */
11
7
  class ItemSizeAverager {
12
- /** The total amount of weight behind the current average. */
13
- _totalWeight = 0;
14
- /** The current average item size. */
15
- _averageItemSize;
16
- /** The default size to use for items when no data is available. */
17
- _defaultItemSize;
18
- /** @param defaultItemSize The default size to use for items when no data is available. */
19
- constructor(defaultItemSize = 50) {
20
- this._defaultItemSize = defaultItemSize;
21
- this._averageItemSize = defaultItemSize;
22
- }
23
- /** Returns the average item size. */
24
- getAverageItemSize() {
25
- return this._averageItemSize;
26
- }
27
- /**
28
- * Adds a measurement sample for the estimator to consider.
29
- * @param range The measured range.
30
- * @param size The measured size of the given range in pixels.
31
- */
32
- addSample(range, size) {
33
- const newTotalWeight = this._totalWeight + range.end - range.start;
34
- if (newTotalWeight) {
35
- const newAverageItemSize = (size + this._averageItemSize * this._totalWeight) / newTotalWeight;
36
- if (newAverageItemSize) {
37
- this._averageItemSize = newAverageItemSize;
38
- this._totalWeight = newTotalWeight;
39
- }
40
- }
41
- }
42
- /** Resets the averager. */
43
- reset() {
44
- this._averageItemSize = this._defaultItemSize;
45
- this._totalWeight = 0;
8
+ _totalWeight = 0;
9
+ _averageItemSize;
10
+ _defaultItemSize;
11
+ constructor(defaultItemSize = 50) {
12
+ this._defaultItemSize = defaultItemSize;
13
+ this._averageItemSize = defaultItemSize;
14
+ }
15
+ getAverageItemSize() {
16
+ return this._averageItemSize;
17
+ }
18
+ addSample(range, size) {
19
+ const newTotalWeight = this._totalWeight + range.end - range.start;
20
+ if (newTotalWeight) {
21
+ const newAverageItemSize = (size + this._averageItemSize * this._totalWeight) / newTotalWeight;
22
+ if (newAverageItemSize) {
23
+ this._averageItemSize = newAverageItemSize;
24
+ this._totalWeight = newTotalWeight;
25
+ }
46
26
  }
27
+ }
28
+ reset() {
29
+ this._averageItemSize = this._defaultItemSize;
30
+ this._totalWeight = 0;
31
+ }
47
32
  }
48
- /** Virtual scrolling strategy for lists with items of unknown or dynamic size. */
49
33
  class AutoSizeVirtualScrollStrategy {
50
- /** @docs-private Implemented as part of VirtualScrollStrategy. */
51
- scrolledIndexChange = new Observable(() => {
52
- // TODO(mmalerba): Implement.
53
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
54
- throw Error('cdk-virtual-scroll: scrolledIndexChange is currently not supported for the' +
55
- ' autosize scroll strategy');
56
- }
57
- });
58
- /** The attached viewport. */
59
- _viewport = null;
60
- /** The minimum amount of buffer rendered beyond the viewport (in pixels). */
61
- _minBufferPx;
62
- /** The number of buffer items to render beyond the edge of the viewport (in pixels). */
63
- _maxBufferPx;
64
- /** The estimator used to estimate the size of unseen items. */
65
- _averager;
66
- /** The last measured scroll offset of the viewport. */
67
- _lastScrollOffset;
68
- /** The last measured size of the rendered content in the viewport. */
69
- _lastRenderedContentSize;
70
- /** The last measured size of the rendered content in the viewport. */
71
- _lastRenderedContentOffset;
72
- /**
73
- * The number of consecutive cycles where removing extra items has failed. Failure here means that
74
- * we estimated how many items we could safely remove, but our estimate turned out to be too much
75
- * and it wasn't safe to remove that many elements.
76
- */
77
- _removalFailures = 0;
78
- /**
79
- * @param minBufferPx The minimum amount of buffer rendered beyond the viewport (in pixels).
80
- * If the amount of buffer dips below this number, more items will be rendered.
81
- * @param maxBufferPx The number of pixels worth of buffer to shoot for when rendering new items.
82
- * If the actual amount turns out to be less it will not necessarily trigger an additional
83
- * rendering cycle (as long as the amount of buffer is still greater than `minBufferPx`).
84
- * @param averager The averager used to estimate the size of unseen items.
85
- */
86
- constructor(minBufferPx, maxBufferPx, averager = new ItemSizeAverager()) {
87
- this._minBufferPx = minBufferPx;
88
- this._maxBufferPx = maxBufferPx;
89
- this._averager = averager;
90
- }
91
- /**
92
- * Attaches this scroll strategy to a viewport.
93
- * @param viewport The viewport to attach this strategy to.
94
- */
95
- attach(viewport) {
96
- this._averager.reset();
97
- this._viewport = viewport;
98
- this._renderContentForCurrentOffset();
34
+ scrolledIndexChange = new Observable(() => {
35
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
36
+ throw Error('cdk-virtual-scroll: scrolledIndexChange is currently not supported for the' + ' autosize scroll strategy');
99
37
  }
100
- /** Detaches this scroll strategy from the currently attached viewport. */
101
- detach() {
102
- this._viewport = null;
38
+ });
39
+ _viewport = null;
40
+ _minBufferPx;
41
+ _maxBufferPx;
42
+ _averager;
43
+ _lastScrollOffset;
44
+ _lastRenderedContentSize;
45
+ _lastRenderedContentOffset;
46
+ _removalFailures = 0;
47
+ constructor(minBufferPx, maxBufferPx, averager = new ItemSizeAverager()) {
48
+ this._minBufferPx = minBufferPx;
49
+ this._maxBufferPx = maxBufferPx;
50
+ this._averager = averager;
51
+ }
52
+ attach(viewport) {
53
+ this._averager.reset();
54
+ this._viewport = viewport;
55
+ this._renderContentForCurrentOffset();
56
+ }
57
+ detach() {
58
+ this._viewport = null;
59
+ }
60
+ onContentScrolled() {
61
+ if (this._viewport) {
62
+ this._updateRenderedContentAfterScroll();
103
63
  }
104
- /** @docs-private Implemented as part of VirtualScrollStrategy. */
105
- onContentScrolled() {
106
- if (this._viewport) {
107
- this._updateRenderedContentAfterScroll();
108
- }
64
+ }
65
+ onDataLengthChanged() {
66
+ if (this._viewport) {
67
+ this._renderContentForCurrentOffset();
68
+ this._checkRenderedContentSize();
109
69
  }
110
- /** @docs-private Implemented as part of VirtualScrollStrategy. */
111
- onDataLengthChanged() {
112
- if (this._viewport) {
113
- this._renderContentForCurrentOffset();
114
- this._checkRenderedContentSize();
115
- }
70
+ }
71
+ onContentRendered() {
72
+ if (this._viewport) {
73
+ this._checkRenderedContentSize();
116
74
  }
117
- /** @docs-private Implemented as part of VirtualScrollStrategy. */
118
- onContentRendered() {
119
- if (this._viewport) {
120
- this._checkRenderedContentSize();
121
- }
75
+ }
76
+ onRenderedOffsetChanged() {
77
+ if (this._viewport) {
78
+ this._checkRenderedContentOffset();
122
79
  }
123
- /** @docs-private Implemented as part of VirtualScrollStrategy. */
124
- onRenderedOffsetChanged() {
125
- if (this._viewport) {
126
- this._checkRenderedContentOffset();
127
- }
80
+ }
81
+ scrollToIndex() {
82
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
83
+ throw Error('cdk-virtual-scroll: scrollToIndex is currently not supported for the autosize' + ' scroll strategy');
128
84
  }
129
- /** Scroll to the offset for the given index. */
130
- scrollToIndex() {
131
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
132
- // TODO(mmalerba): Implement.
133
- throw Error('cdk-virtual-scroll: scrollToIndex is currently not supported for the autosize' +
134
- ' scroll strategy');
135
- }
85
+ }
86
+ updateBufferSize(minBufferPx, maxBufferPx) {
87
+ if (maxBufferPx < minBufferPx) {
88
+ throw Error('CDK virtual scroll: maxBufferPx must be greater than or equal to minBufferPx');
136
89
  }
137
- /**
138
- * Update the buffer parameters.
139
- * @param minBufferPx The minimum amount of buffer rendered beyond the viewport (in pixels).
140
- * @param maxBufferPx The number of buffer items to render beyond the edge of the viewport (in
141
- * pixels).
142
- */
143
- updateBufferSize(minBufferPx, maxBufferPx) {
144
- if (maxBufferPx < minBufferPx) {
145
- throw Error('CDK virtual scroll: maxBufferPx must be greater than or equal to minBufferPx');
146
- }
147
- this._minBufferPx = minBufferPx;
148
- this._maxBufferPx = maxBufferPx;
90
+ this._minBufferPx = minBufferPx;
91
+ this._maxBufferPx = maxBufferPx;
92
+ }
93
+ _updateRenderedContentAfterScroll() {
94
+ const viewport = this._viewport;
95
+ const scrollOffset = viewport.measureScrollOffset();
96
+ let scrollDelta = scrollOffset - this._lastScrollOffset;
97
+ let scrollMagnitude = Math.abs(scrollDelta);
98
+ const renderedRange = viewport.getRenderedRange();
99
+ let offsetCorrection = 0;
100
+ if (scrollDelta < 0) {
101
+ const predictedOffset = renderedRange.start * this._averager.getAverageItemSize();
102
+ const offsetDifference = predictedOffset - this._lastRenderedContentOffset;
103
+ offsetCorrection = Math.round(offsetDifference * Math.max(0, Math.min(1, scrollMagnitude / (scrollOffset + scrollMagnitude))));
104
+ scrollDelta = scrollDelta - offsetCorrection;
105
+ scrollMagnitude = Math.abs(scrollDelta);
149
106
  }
150
- /** Update the rendered content after the user scrolls. */
151
- _updateRenderedContentAfterScroll() {
152
- const viewport = this._viewport;
153
- // The current scroll offset.
154
- const scrollOffset = viewport.measureScrollOffset();
155
- // The delta between the current scroll offset and the previously recorded scroll offset.
156
- let scrollDelta = scrollOffset - this._lastScrollOffset;
157
- // The magnitude of the scroll delta.
158
- let scrollMagnitude = Math.abs(scrollDelta);
159
- // The currently rendered range.
160
- const renderedRange = viewport.getRenderedRange();
161
- // If we're scrolling toward the top, we need to account for the fact that the predicted amount
162
- // of content and the actual amount of scrollable space may differ. We address this by slowly
163
- // correcting the difference on each scroll event.
164
- let offsetCorrection = 0;
107
+ const startBuffer = this._lastScrollOffset - this._lastRenderedContentOffset;
108
+ const endBuffer = this._lastRenderedContentOffset + this._lastRenderedContentSize - (this._lastScrollOffset + viewport.getViewportSize());
109
+ const underscan = scrollMagnitude + this._minBufferPx - (scrollDelta < 0 ? startBuffer : endBuffer);
110
+ if (underscan > 0) {
111
+ if (scrollMagnitude >= viewport.getViewportSize()) {
112
+ this._renderContentForCurrentOffset();
113
+ } else {
114
+ const addItems = Math.max(0, Math.ceil((underscan - this._minBufferPx + this._maxBufferPx) / this._averager.getAverageItemSize()));
115
+ const overscan = (scrollDelta < 0 ? endBuffer : startBuffer) - this._minBufferPx + scrollMagnitude;
116
+ const unboundedRemoveItems = Math.floor(overscan / this._averager.getAverageItemSize() / (this._removalFailures + 1));
117
+ const removeItems = Math.min(renderedRange.end - renderedRange.start, Math.max(0, unboundedRemoveItems));
118
+ const range = this._expandRange(renderedRange, scrollDelta < 0 ? addItems : 0, scrollDelta > 0 ? addItems : 0);
165
119
  if (scrollDelta < 0) {
166
- // The content offset we would expect based on the average item size.
167
- const predictedOffset = renderedRange.start * this._averager.getAverageItemSize();
168
- // The difference between the predicted size of the un-rendered content at the beginning and
169
- // the actual available space to scroll over. We need to reduce this to zero by the time the
170
- // user scrolls to the top.
171
- // - 0 indicates that the predicted size and available space are the same.
172
- // - A negative number that the predicted size is smaller than the available space.
173
- // - A positive number indicates the predicted size is larger than the available space
174
- const offsetDifference = predictedOffset - this._lastRenderedContentOffset;
175
- // The amount of difference to correct during this scroll event. We calculate this as a
176
- // percentage of the total difference based on the percentage of the distance toward the top
177
- // that the user scrolled.
178
- offsetCorrection = Math.round(offsetDifference *
179
- Math.max(0, Math.min(1, scrollMagnitude / (scrollOffset + scrollMagnitude))));
180
- // Based on the offset correction above, we pretend that the scroll delta was bigger or
181
- // smaller than it actually was, this way we can start to eliminate the difference.
182
- scrollDelta = scrollDelta - offsetCorrection;
183
- scrollMagnitude = Math.abs(scrollDelta);
120
+ range.end = Math.max(range.start + 1, range.end - removeItems);
121
+ } else {
122
+ range.start = Math.min(range.end - 1, range.start + removeItems);
184
123
  }
185
- // The current amount of buffer past the start of the viewport.
186
- const startBuffer = this._lastScrollOffset - this._lastRenderedContentOffset;
187
- // The current amount of buffer past the end of the viewport.
188
- const endBuffer = this._lastRenderedContentOffset +
189
- this._lastRenderedContentSize -
190
- (this._lastScrollOffset + viewport.getViewportSize());
191
- // The amount of unfilled space that should be filled on the side the user is scrolling toward
192
- // in order to safely absorb the scroll delta.
193
- const underscan = scrollMagnitude + this._minBufferPx - (scrollDelta < 0 ? startBuffer : endBuffer);
194
- // Check if there's unfilled space that we need to render new elements to fill.
195
- if (underscan > 0) {
196
- // Check if the scroll magnitude was larger than the viewport size. In this case the user
197
- // won't notice a discontinuity if we just jump to the new estimated position in the list.
198
- // However, if the scroll magnitude is smaller than the viewport the user might notice some
199
- // jitteriness if we just jump to the estimated position. Instead we make sure to scroll by
200
- // the same number of pixels as the scroll magnitude.
201
- if (scrollMagnitude >= viewport.getViewportSize()) {
202
- this._renderContentForCurrentOffset();
203
- }
204
- else {
205
- // The number of new items to render on the side the user is scrolling towards. Rather than
206
- // just filling the underscan space, we actually fill enough to have a buffer size of
207
- // `maxBufferPx`. This gives us a little wiggle room in case our item size estimate is off.
208
- const addItems = Math.max(0, Math.ceil((underscan - this._minBufferPx + this._maxBufferPx) /
209
- this._averager.getAverageItemSize()));
210
- // The amount of filled space beyond what is necessary on the side the user is scrolling
211
- // away from.
212
- const overscan = (scrollDelta < 0 ? endBuffer : startBuffer) - this._minBufferPx + scrollMagnitude;
213
- // The number of currently rendered items to remove on the side the user is scrolling away
214
- // from. If removal has failed in recent cycles we are less aggressive in how much we try to
215
- // remove.
216
- const unboundedRemoveItems = Math.floor(overscan / this._averager.getAverageItemSize() / (this._removalFailures + 1));
217
- const removeItems = Math.min(renderedRange.end - renderedRange.start, Math.max(0, unboundedRemoveItems));
218
- // The new range we will tell the viewport to render. We first expand it to include the new
219
- // items we want rendered, we then contract the opposite side to remove items we no longer
220
- // want rendered.
221
- const range = this._expandRange(renderedRange, scrollDelta < 0 ? addItems : 0, scrollDelta > 0 ? addItems : 0);
222
- if (scrollDelta < 0) {
223
- range.end = Math.max(range.start + 1, range.end - removeItems);
224
- }
225
- else {
226
- range.start = Math.min(range.end - 1, range.start + removeItems);
227
- }
228
- // The new offset we want to set on the rendered content. To determine this we measure the
229
- // number of pixels we removed and then adjust the offset to the start of the rendered
230
- // content or to the end of the rendered content accordingly (whichever one doesn't require
231
- // that the newly added items to be rendered to calculate.)
232
- let contentOffset;
233
- let contentOffsetTo;
234
- if (scrollDelta < 0) {
235
- let removedSize = viewport.measureRangeSize({
236
- start: range.end,
237
- end: renderedRange.end,
238
- });
239
- // Check that we're not removing too much.
240
- if (removedSize <= overscan) {
241
- contentOffset =
242
- this._lastRenderedContentOffset + this._lastRenderedContentSize - removedSize;
243
- this._removalFailures = 0;
244
- }
245
- else {
246
- // If the removal is more than the overscan can absorb just undo it and record the fact
247
- // that the removal failed so we can be less aggressive next time.
248
- range.end = renderedRange.end;
249
- contentOffset = this._lastRenderedContentOffset + this._lastRenderedContentSize;
250
- this._removalFailures++;
251
- }
252
- contentOffsetTo = 'to-end';
253
- }
254
- else {
255
- const removedSize = viewport.measureRangeSize({
256
- start: renderedRange.start,
257
- end: range.start,
258
- });
259
- // Check that we're not removing too much.
260
- if (removedSize <= overscan) {
261
- contentOffset = this._lastRenderedContentOffset + removedSize;
262
- this._removalFailures = 0;
263
- }
264
- else {
265
- // If the removal is more than the overscan can absorb just undo it and record the fact
266
- // that the removal failed so we can be less aggressive next time.
267
- range.start = renderedRange.start;
268
- contentOffset = this._lastRenderedContentOffset;
269
- this._removalFailures++;
270
- }
271
- contentOffsetTo = 'to-start';
272
- }
273
- // Set the range and offset we calculated above.
274
- viewport.setRenderedRange(range);
275
- viewport.setRenderedContentOffset(contentOffset + offsetCorrection, contentOffsetTo);
276
- }
277
- }
278
- else if (offsetCorrection) {
279
- // Even if the rendered range didn't change, we may still need to adjust the content offset to
280
- // simulate scrolling slightly slower or faster than the user actually scrolled.
281
- viewport.setRenderedContentOffset(this._lastRenderedContentOffset + offsetCorrection);
124
+ let contentOffset;
125
+ let contentOffsetTo;
126
+ if (scrollDelta < 0) {
127
+ let removedSize = viewport.measureRangeSize({
128
+ start: range.end,
129
+ end: renderedRange.end
130
+ });
131
+ if (removedSize <= overscan) {
132
+ contentOffset = this._lastRenderedContentOffset + this._lastRenderedContentSize - removedSize;
133
+ this._removalFailures = 0;
134
+ } else {
135
+ range.end = renderedRange.end;
136
+ contentOffset = this._lastRenderedContentOffset + this._lastRenderedContentSize;
137
+ this._removalFailures++;
138
+ }
139
+ contentOffsetTo = 'to-end';
140
+ } else {
141
+ const removedSize = viewport.measureRangeSize({
142
+ start: renderedRange.start,
143
+ end: range.start
144
+ });
145
+ if (removedSize <= overscan) {
146
+ contentOffset = this._lastRenderedContentOffset + removedSize;
147
+ this._removalFailures = 0;
148
+ } else {
149
+ range.start = renderedRange.start;
150
+ contentOffset = this._lastRenderedContentOffset;
151
+ this._removalFailures++;
152
+ }
153
+ contentOffsetTo = 'to-start';
282
154
  }
283
- // Save the scroll offset to be compared to the new value on the next scroll event.
284
- this._lastScrollOffset = scrollOffset;
285
- }
286
- /**
287
- * Checks the size of the currently rendered content and uses it to update the estimated item size
288
- * and estimated total content size.
289
- */
290
- _checkRenderedContentSize() {
291
- const viewport = this._viewport;
292
- this._lastRenderedContentSize = viewport.measureRenderedContentSize();
293
- this._averager.addSample(viewport.getRenderedRange(), this._lastRenderedContentSize);
294
- this._updateTotalContentSize(this._lastRenderedContentSize);
295
- }
296
- /** Checks the currently rendered content offset and saves the value for later use. */
297
- _checkRenderedContentOffset() {
298
- const viewport = this._viewport;
299
- this._lastRenderedContentOffset = viewport.getOffsetToRenderedContentStart();
300
- }
301
- /**
302
- * Recalculates the rendered content based on our estimate of what should be shown at the current
303
- * scroll offset.
304
- */
305
- _renderContentForCurrentOffset() {
306
- const viewport = this._viewport;
307
- const scrollOffset = viewport.measureScrollOffset();
308
- this._lastScrollOffset = scrollOffset;
309
- this._removalFailures = 0;
310
- const itemSize = this._averager.getAverageItemSize();
311
- const firstVisibleIndex = Math.min(viewport.getDataLength() - 1, Math.floor(scrollOffset / itemSize));
312
- const bufferSize = Math.ceil(this._maxBufferPx / itemSize);
313
- const range = this._expandRange(this._getVisibleRangeForIndex(firstVisibleIndex), bufferSize, bufferSize);
314
155
  viewport.setRenderedRange(range);
315
- viewport.setRenderedContentOffset(itemSize * range.start);
316
- }
317
- // TODO: maybe move to base class, can probably share with fixed size strategy.
318
- /**
319
- * Gets the visible range of data for the given start index. If the start index is too close to
320
- * the end of the list it may be backed up to ensure the estimated size of the range is enough to
321
- * fill the viewport.
322
- * Note: must not be called if `this._viewport` is null
323
- * @param startIndex The index to start the range at
324
- * @return a range estimated to be large enough to fill the viewport when rendered.
325
- */
326
- _getVisibleRangeForIndex(startIndex) {
327
- const viewport = this._viewport;
328
- const range = {
329
- start: startIndex,
330
- end: startIndex + Math.ceil(viewport.getViewportSize() / this._averager.getAverageItemSize()),
331
- };
332
- const extra = range.end - viewport.getDataLength();
333
- if (extra > 0) {
334
- range.start = Math.max(0, range.start - extra);
335
- }
336
- return range;
156
+ viewport.setRenderedContentOffset(contentOffset + offsetCorrection, contentOffsetTo);
157
+ }
158
+ } else if (offsetCorrection) {
159
+ viewport.setRenderedContentOffset(this._lastRenderedContentOffset + offsetCorrection);
337
160
  }
338
- // TODO: maybe move to base class, can probably share with fixed size strategy.
339
- /**
340
- * Expand the given range by the given amount in either direction.
341
- * Note: must not be called if `this._viewport` is null
342
- * @param range The range to expand
343
- * @param expandStart The number of items to expand the start of the range by.
344
- * @param expandEnd The number of items to expand the end of the range by.
345
- * @return The expanded range.
346
- */
347
- _expandRange(range, expandStart, expandEnd) {
348
- const viewport = this._viewport;
349
- const start = Math.max(0, range.start - expandStart);
350
- const end = Math.min(viewport.getDataLength(), range.end + expandEnd);
351
- return { start, end };
352
- }
353
- /** Update the viewport's total content size. */
354
- _updateTotalContentSize(renderedContentSize) {
355
- const viewport = this._viewport;
356
- const renderedRange = viewport.getRenderedRange();
357
- const totalSize = renderedContentSize +
358
- (viewport.getDataLength() - (renderedRange.end - renderedRange.start)) *
359
- this._averager.getAverageItemSize();
360
- viewport.setTotalContentSize(totalSize);
161
+ this._lastScrollOffset = scrollOffset;
162
+ }
163
+ _checkRenderedContentSize() {
164
+ const viewport = this._viewport;
165
+ this._lastRenderedContentSize = viewport.measureRenderedContentSize();
166
+ this._averager.addSample(viewport.getRenderedRange(), this._lastRenderedContentSize);
167
+ this._updateTotalContentSize(this._lastRenderedContentSize);
168
+ }
169
+ _checkRenderedContentOffset() {
170
+ const viewport = this._viewport;
171
+ this._lastRenderedContentOffset = viewport.getOffsetToRenderedContentStart();
172
+ }
173
+ _renderContentForCurrentOffset() {
174
+ const viewport = this._viewport;
175
+ const scrollOffset = viewport.measureScrollOffset();
176
+ this._lastScrollOffset = scrollOffset;
177
+ this._removalFailures = 0;
178
+ const itemSize = this._averager.getAverageItemSize();
179
+ const firstVisibleIndex = Math.min(viewport.getDataLength() - 1, Math.floor(scrollOffset / itemSize));
180
+ const bufferSize = Math.ceil(this._maxBufferPx / itemSize);
181
+ const range = this._expandRange(this._getVisibleRangeForIndex(firstVisibleIndex), bufferSize, bufferSize);
182
+ viewport.setRenderedRange(range);
183
+ viewport.setRenderedContentOffset(itemSize * range.start);
184
+ }
185
+ _getVisibleRangeForIndex(startIndex) {
186
+ const viewport = this._viewport;
187
+ const range = {
188
+ start: startIndex,
189
+ end: startIndex + Math.ceil(viewport.getViewportSize() / this._averager.getAverageItemSize())
190
+ };
191
+ const extra = range.end - viewport.getDataLength();
192
+ if (extra > 0) {
193
+ range.start = Math.max(0, range.start - extra);
361
194
  }
195
+ return range;
196
+ }
197
+ _expandRange(range, expandStart, expandEnd) {
198
+ const viewport = this._viewport;
199
+ const start = Math.max(0, range.start - expandStart);
200
+ const end = Math.min(viewport.getDataLength(), range.end + expandEnd);
201
+ return {
202
+ start,
203
+ end
204
+ };
205
+ }
206
+ _updateTotalContentSize(renderedContentSize) {
207
+ const viewport = this._viewport;
208
+ const renderedRange = viewport.getRenderedRange();
209
+ const totalSize = renderedContentSize + (viewport.getDataLength() - (renderedRange.end - renderedRange.start)) * this._averager.getAverageItemSize();
210
+ viewport.setTotalContentSize(totalSize);
211
+ }
362
212
  }
363
- /**
364
- * Provider factory for `AutoSizeVirtualScrollStrategy` that simply extracts the already created
365
- * `AutoSizeVirtualScrollStrategy` from the given directive.
366
- * @param autoSizeDir The instance of `CdkAutoSizeVirtualScroll` to extract the
367
- * `AutoSizeVirtualScrollStrategy` from.
368
- */
369
213
  function _autoSizeVirtualScrollStrategyFactory(autoSizeDir) {
370
- return autoSizeDir._scrollStrategy;
214
+ return autoSizeDir._scrollStrategy;
371
215
  }
372
- /** A virtual scroll strategy that supports unknown or dynamic size items. */
373
216
  class CdkAutoSizeVirtualScroll {
374
- /**
375
- * The minimum amount of buffer rendered beyond the viewport (in pixels).
376
- * If the amount of buffer dips below this number, more items will be rendered. Defaults to 100px.
377
- */
378
- get minBufferPx() {
379
- return this._minBufferPx;
380
- }
381
- set minBufferPx(value) {
382
- this._minBufferPx = coerceNumberProperty(value);
383
- }
384
- _minBufferPx = 100;
385
- /**
386
- * The number of pixels worth of buffer to shoot for when rendering new items.
387
- * If the actual amount turns out to be less it will not necessarily trigger an additional
388
- * rendering cycle (as long as the amount of buffer is still greater than `minBufferPx`).
389
- * Defaults to 200px.
390
- */
391
- get maxBufferPx() {
392
- return this._maxBufferPx;
393
- }
394
- set maxBufferPx(value) {
395
- this._maxBufferPx = coerceNumberProperty(value);
396
- }
397
- _maxBufferPx = 200;
398
- /** The scroll strategy used by this directive. */
399
- _scrollStrategy = new AutoSizeVirtualScrollStrategy(this.minBufferPx, this.maxBufferPx);
400
- ngOnChanges() {
401
- this._scrollStrategy.updateBufferSize(this.minBufferPx, this.maxBufferPx);
402
- }
403
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkAutoSizeVirtualScroll, deps: [], target: i0.ɵɵFactoryTarget.Directive });
404
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CdkAutoSizeVirtualScroll, isStandalone: true, selector: "cdk-virtual-scroll-viewport[autosize]", inputs: { minBufferPx: "minBufferPx", maxBufferPx: "maxBufferPx" }, providers: [
405
- {
406
- provide: VIRTUAL_SCROLL_STRATEGY,
407
- useFactory: _autoSizeVirtualScrollStrategyFactory,
408
- deps: [forwardRef(() => CdkAutoSizeVirtualScroll)],
409
- },
410
- ], usesOnChanges: true, ngImport: i0 });
217
+ get minBufferPx() {
218
+ return this._minBufferPx;
219
+ }
220
+ set minBufferPx(value) {
221
+ this._minBufferPx = coerceNumberProperty(value);
222
+ }
223
+ _minBufferPx = 100;
224
+ get maxBufferPx() {
225
+ return this._maxBufferPx;
226
+ }
227
+ set maxBufferPx(value) {
228
+ this._maxBufferPx = coerceNumberProperty(value);
229
+ }
230
+ _maxBufferPx = 200;
231
+ _scrollStrategy = new AutoSizeVirtualScrollStrategy(this.minBufferPx, this.maxBufferPx);
232
+ ngOnChanges() {
233
+ this._scrollStrategy.updateBufferSize(this.minBufferPx, this.maxBufferPx);
234
+ }
235
+ static ɵfac = i0.ɵɵngDeclareFactory({
236
+ minVersion: "12.0.0",
237
+ version: "20.2.0-next.2",
238
+ ngImport: i0,
239
+ type: CdkAutoSizeVirtualScroll,
240
+ deps: [],
241
+ target: i0.ɵɵFactoryTarget.Directive
242
+ });
243
+ static ɵdir = i0.ɵɵngDeclareDirective({
244
+ minVersion: "14.0.0",
245
+ version: "20.2.0-next.2",
246
+ type: CdkAutoSizeVirtualScroll,
247
+ isStandalone: true,
248
+ selector: "cdk-virtual-scroll-viewport[autosize]",
249
+ inputs: {
250
+ minBufferPx: "minBufferPx",
251
+ maxBufferPx: "maxBufferPx"
252
+ },
253
+ providers: [{
254
+ provide: VIRTUAL_SCROLL_STRATEGY,
255
+ useFactory: _autoSizeVirtualScrollStrategyFactory,
256
+ deps: [forwardRef(() => CdkAutoSizeVirtualScroll)]
257
+ }],
258
+ usesOnChanges: true,
259
+ ngImport: i0
260
+ });
411
261
  }
412
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkAutoSizeVirtualScroll, decorators: [{
413
- type: Directive,
414
- args: [{
415
- selector: 'cdk-virtual-scroll-viewport[autosize]',
416
- providers: [
417
- {
418
- provide: VIRTUAL_SCROLL_STRATEGY,
419
- useFactory: _autoSizeVirtualScrollStrategyFactory,
420
- deps: [forwardRef(() => CdkAutoSizeVirtualScroll)],
421
- },
422
- ],
423
- }]
424
- }], propDecorators: { minBufferPx: [{
425
- type: Input
426
- }], maxBufferPx: [{
427
- type: Input
428
- }] } });
262
+ i0.ɵɵngDeclareClassMetadata({
263
+ minVersion: "12.0.0",
264
+ version: "20.2.0-next.2",
265
+ ngImport: i0,
266
+ type: CdkAutoSizeVirtualScroll,
267
+ decorators: [{
268
+ type: Directive,
269
+ args: [{
270
+ selector: 'cdk-virtual-scroll-viewport[autosize]',
271
+ providers: [{
272
+ provide: VIRTUAL_SCROLL_STRATEGY,
273
+ useFactory: _autoSizeVirtualScrollStrategyFactory,
274
+ deps: [forwardRef(() => CdkAutoSizeVirtualScroll)]
275
+ }]
276
+ }]
277
+ }],
278
+ propDecorators: {
279
+ minBufferPx: [{
280
+ type: Input
281
+ }],
282
+ maxBufferPx: [{
283
+ type: Input
284
+ }]
285
+ }
286
+ });
429
287
 
430
288
  class ScrollingModule {
431
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ScrollingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
432
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.0-next.2", ngImport: i0, type: ScrollingModule, imports: [CdkAutoSizeVirtualScroll], exports: [CdkAutoSizeVirtualScroll] });
433
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ScrollingModule });
289
+ static ɵfac = i0.ɵɵngDeclareFactory({
290
+ minVersion: "12.0.0",
291
+ version: "20.2.0-next.2",
292
+ ngImport: i0,
293
+ type: ScrollingModule,
294
+ deps: [],
295
+ target: i0.ɵɵFactoryTarget.NgModule
296
+ });
297
+ static ɵmod = i0.ɵɵngDeclareNgModule({
298
+ minVersion: "14.0.0",
299
+ version: "20.2.0-next.2",
300
+ ngImport: i0,
301
+ type: ScrollingModule,
302
+ imports: [CdkAutoSizeVirtualScroll],
303
+ exports: [CdkAutoSizeVirtualScroll]
304
+ });
305
+ static ɵinj = i0.ɵɵngDeclareInjector({
306
+ minVersion: "12.0.0",
307
+ version: "20.2.0-next.2",
308
+ ngImport: i0,
309
+ type: ScrollingModule
310
+ });
434
311
  }
435
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: ScrollingModule, decorators: [{
436
- type: NgModule,
437
- args: [{
438
- imports: [CdkAutoSizeVirtualScroll],
439
- exports: [CdkAutoSizeVirtualScroll],
440
- }]
441
- }] });
312
+ i0.ɵɵngDeclareClassMetadata({
313
+ minVersion: "12.0.0",
314
+ version: "20.2.0-next.2",
315
+ ngImport: i0,
316
+ type: ScrollingModule,
317
+ decorators: [{
318
+ type: NgModule,
319
+ args: [{
320
+ imports: [CdkAutoSizeVirtualScroll],
321
+ exports: [CdkAutoSizeVirtualScroll]
322
+ }]
323
+ }]
324
+ });
442
325
 
443
326
  export { AutoSizeVirtualScrollStrategy, CdkAutoSizeVirtualScroll, ItemSizeAverager, ScrollingModule, _autoSizeVirtualScrollStrategyFactory };
444
327
  //# sourceMappingURL=scrolling.mjs.map