@react-stately/virtualizer 3.6.9-nightly.4555 → 3.6.9-nightly.4558

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 (66) hide show
  1. package/dist/Layout.main.js +75 -0
  2. package/dist/Layout.main.js.map +1 -0
  3. package/dist/Layout.mjs +70 -0
  4. package/dist/Layout.module.js +70 -0
  5. package/dist/Layout.module.js.map +1 -0
  6. package/dist/LayoutInfo.main.js +51 -0
  7. package/dist/LayoutInfo.main.js.map +1 -0
  8. package/dist/LayoutInfo.mjs +46 -0
  9. package/dist/LayoutInfo.module.js +46 -0
  10. package/dist/LayoutInfo.module.js.map +1 -0
  11. package/dist/OverscanManager.main.js +87 -0
  12. package/dist/OverscanManager.main.js.map +1 -0
  13. package/dist/OverscanManager.mjs +82 -0
  14. package/dist/OverscanManager.module.js +82 -0
  15. package/dist/OverscanManager.module.js.map +1 -0
  16. package/dist/Point.main.js +40 -0
  17. package/dist/Point.main.js.map +1 -0
  18. package/dist/Point.mjs +35 -0
  19. package/dist/Point.module.js +35 -0
  20. package/dist/Point.module.js.map +1 -0
  21. package/dist/Rect.main.js +130 -0
  22. package/dist/Rect.main.js.map +1 -0
  23. package/dist/Rect.mjs +125 -0
  24. package/dist/Rect.module.js +125 -0
  25. package/dist/Rect.module.js.map +1 -0
  26. package/dist/ReusableView.main.js +33 -0
  27. package/dist/ReusableView.main.js.map +1 -0
  28. package/dist/ReusableView.mjs +28 -0
  29. package/dist/ReusableView.module.js +28 -0
  30. package/dist/ReusableView.module.js.map +1 -0
  31. package/dist/Size.main.js +40 -0
  32. package/dist/Size.main.js.map +1 -0
  33. package/dist/Size.mjs +35 -0
  34. package/dist/Size.module.js +35 -0
  35. package/dist/Size.module.js.map +1 -0
  36. package/dist/Transaction.main.js +32 -0
  37. package/dist/Transaction.main.js.map +1 -0
  38. package/dist/Transaction.mjs +27 -0
  39. package/dist/Transaction.module.js +27 -0
  40. package/dist/Transaction.module.js.map +1 -0
  41. package/dist/Virtualizer.main.js +813 -0
  42. package/dist/Virtualizer.main.js.map +1 -0
  43. package/dist/Virtualizer.mjs +808 -0
  44. package/dist/Virtualizer.module.js +808 -0
  45. package/dist/Virtualizer.module.js.map +1 -0
  46. package/dist/import.mjs +7 -1399
  47. package/dist/main.js +14 -1406
  48. package/dist/main.js.map +1 -1
  49. package/dist/module.js +7 -1399
  50. package/dist/module.js.map +1 -1
  51. package/dist/tween.main.js +67 -0
  52. package/dist/tween.main.js.map +1 -0
  53. package/dist/tween.mjs +61 -0
  54. package/dist/tween.module.js +61 -0
  55. package/dist/tween.module.js.map +1 -0
  56. package/dist/useVirtualizerState.main.js +96 -0
  57. package/dist/useVirtualizerState.main.js.map +1 -0
  58. package/dist/useVirtualizerState.mjs +91 -0
  59. package/dist/useVirtualizerState.module.js +91 -0
  60. package/dist/useVirtualizerState.module.js.map +1 -0
  61. package/dist/utils.main.js +53 -0
  62. package/dist/utils.main.js.map +1 -0
  63. package/dist/utils.mjs +46 -0
  64. package/dist/utils.module.js +46 -0
  65. package/dist/utils.module.js.map +1 -0
  66. package/package.json +4 -4
@@ -0,0 +1,808 @@
1
+ import {easeOut as $3eb131dcf37ad5f8$export$57636bb43b1ccbb0, tween as $3eb131dcf37ad5f8$export$dc0b63720788090c} from "./tween.module.js";
2
+ import {concatIterators as $fc36f9a046a9ce79$export$cfc14088dfefce5f, difference as $fc36f9a046a9ce79$export$acaf96a27438246b, isSetEqual as $fc36f9a046a9ce79$export$a8d0d0c8d1c5df64} from "./utils.module.js";
3
+ import {OverscanManager as $364191b3decf3697$export$4455ee6afb38dcbb} from "./OverscanManager.module.js";
4
+ import {Point as $3041db3296945e6e$export$baf26146a414f24a} from "./Point.module.js";
5
+ import {Rect as $60423f92c7f9ad87$export$c79fc6492f3af13d} from "./Rect.module.js";
6
+ import {ReusableView as $ad1d98aa8f0c31b4$export$1a5223887c560441} from "./ReusableView.module.js";
7
+ import {Size as $ee1bfa90a957fb8a$export$cb6da89c6af1a8ec} from "./Size.module.js";
8
+ import {Transaction as $8e135e531d8dcb66$export$febc5573c75cefb0} from "./Transaction.module.js";
9
+
10
+ /*
11
+ * Copyright 2020 Adobe. All rights reserved.
12
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
13
+ * you may not use this file except in compliance with the License. You may obtain a copy
14
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software distributed under
17
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
18
+ * OF ANY KIND, either express or implied. See the License for the specific language
19
+ * governing permissions and limitations under the License.
20
+ */
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+ class $38b9490c1cca8fc4$export$89be5a243e59c4b2 {
29
+ _setContentSize(size) {
30
+ this._contentSize = size;
31
+ this.delegate.setContentSize(size);
32
+ }
33
+ _setContentOffset(offset) {
34
+ let rect = new (0, $60423f92c7f9ad87$export$c79fc6492f3af13d)(offset.x, offset.y, this._visibleRect.width, this._visibleRect.height);
35
+ this.delegate.setVisibleRect(rect);
36
+ }
37
+ /**
38
+ * Get the size of the scrollable content.
39
+ */ get contentSize() {
40
+ return this._contentSize;
41
+ }
42
+ /**
43
+ * Get the collection view's currently visible rectangle.
44
+ */ get visibleRect() {
45
+ return this._visibleRect;
46
+ }
47
+ /**
48
+ * Set the collection view's currently visible rectangle.
49
+ */ set visibleRect(rect) {
50
+ this._setVisibleRect(rect);
51
+ }
52
+ _setVisibleRect(rect, forceUpdate = false) {
53
+ let current = this._visibleRect;
54
+ // Ignore if the rects are equal
55
+ if (rect.equals(current)) return;
56
+ if (this.shouldOverscan) this._overscanManager.setVisibleRect(rect);
57
+ let shouldInvalidate = this.layout && this.layout.shouldInvalidate(rect, this._visibleRect);
58
+ this._resetAnimatedContentOffset();
59
+ this._visibleRect = rect;
60
+ if (shouldInvalidate) // We are already in a layout effect when this method is called, so relayoutNow is appropriate.
61
+ this.relayoutNow({
62
+ offsetChanged: !rect.pointEquals(current),
63
+ sizeChanged: !rect.sizeEquals(current)
64
+ });
65
+ else this.updateSubviews(forceUpdate);
66
+ }
67
+ get collection() {
68
+ return this._collection;
69
+ }
70
+ set collection(data) {
71
+ this._setData(data);
72
+ }
73
+ _setData(data) {
74
+ if (data === this._collection) return;
75
+ if (this._collection) this._runTransaction(()=>{
76
+ this._collection = data;
77
+ }, this.transitionDuration > 0);
78
+ else {
79
+ this._collection = data;
80
+ this.reloadData();
81
+ }
82
+ }
83
+ /**
84
+ * Reloads the data from the data source and relayouts the collection view.
85
+ * Does not animate any changes. Equivalent to re-assigning the same data source
86
+ * to the collection view.
87
+ */ reloadData() {
88
+ this.relayout({
89
+ contentChanged: true
90
+ });
91
+ }
92
+ /**
93
+ * Returns the item with the given key.
94
+ */ getItem(key) {
95
+ return this._collection ? this._collection.getItem(key) : null;
96
+ }
97
+ /** The set of persisted keys are always present in the DOM, even if not currently in view. */ get persistedKeys() {
98
+ return this._persistedKeys;
99
+ }
100
+ /** The set of persisted keys are always present in the DOM, even if not currently in view. */ set persistedKeys(persistedKeys) {
101
+ if (!(0, $fc36f9a046a9ce79$export$a8d0d0c8d1c5df64)(persistedKeys, this._persistedKeys)) {
102
+ this._persistedKeys = persistedKeys;
103
+ this.updateSubviews();
104
+ }
105
+ }
106
+ /** Returns whether the given key, or an ancestor, is persisted. */ isPersistedKey(key) {
107
+ // Quick check if the key is directly in the set of persisted keys.
108
+ if (this._persistedKeys.has(key)) return true;
109
+ // If not, check if the key is an ancestor of any of the persisted keys.
110
+ for (let k of this._persistedKeys)while(k != null){
111
+ let layoutInfo = this.layout.getLayoutInfo(k);
112
+ if (!layoutInfo) break;
113
+ k = layoutInfo.parentKey;
114
+ if (k === key) return true;
115
+ }
116
+ return false;
117
+ }
118
+ /**
119
+ * Get the collection view's layout.
120
+ */ get layout() {
121
+ return this._layout;
122
+ }
123
+ /**
124
+ * Set the collection view's layout.
125
+ */ set layout(layout) {
126
+ this.setLayout(layout);
127
+ }
128
+ /**
129
+ * Sets the collection view's layout, optionally with an animated transition
130
+ * from the current layout to the new layout.
131
+ * @param layout The layout to switch to.
132
+ * @param animated Whether to animate the layout change.
133
+ */ setLayout(layout, animated = false) {
134
+ if (layout === this._layout) return;
135
+ let applyLayout = ()=>{
136
+ if (this._layout) // @ts-ignore
137
+ this._layout.virtualizer = null;
138
+ layout.virtualizer = this;
139
+ this._layout = layout;
140
+ };
141
+ if (animated) // Animated layout transitions are really simple, thanks to our transaction support.
142
+ // We just set the layout inside a transaction action, which runs after the initial
143
+ // layout infos for the animation are retrieved from the previous layout. Then, the
144
+ // final layout infos are retrieved from the new layout, and animations occur.
145
+ this._runTransaction(applyLayout);
146
+ else {
147
+ applyLayout();
148
+ this.relayout();
149
+ }
150
+ }
151
+ _getReuseType(layoutInfo, content) {
152
+ if (layoutInfo.type === "item" && content) {
153
+ let type = this.delegate.getType ? this.delegate.getType(content) : "item";
154
+ let reuseType = type === "item" ? "item" : layoutInfo.type + "_" + type;
155
+ return {
156
+ type: type,
157
+ reuseType: reuseType
158
+ };
159
+ }
160
+ return {
161
+ type: layoutInfo.type,
162
+ reuseType: layoutInfo.type
163
+ };
164
+ }
165
+ getReusableView(layoutInfo) {
166
+ let content = this.getItem(layoutInfo.key);
167
+ let { reuseType: reuseType } = this._getReuseType(layoutInfo, content);
168
+ if (!this._reusableViews[reuseType]) this._reusableViews[reuseType] = [];
169
+ let reusable = this._reusableViews[reuseType];
170
+ let view = reusable.length > 0 ? reusable.pop() : new (0, $ad1d98aa8f0c31b4$export$1a5223887c560441)(this);
171
+ view.viewType = reuseType;
172
+ if (!this._animatedContentOffset.isOrigin()) {
173
+ layoutInfo = layoutInfo.copy();
174
+ layoutInfo.rect.x += this._animatedContentOffset.x;
175
+ layoutInfo.rect.y += this._animatedContentOffset.y;
176
+ }
177
+ view.layoutInfo = layoutInfo;
178
+ this._renderView(view);
179
+ return view;
180
+ }
181
+ _renderView(reusableView) {
182
+ let { type: type, key: key } = reusableView.layoutInfo;
183
+ reusableView.content = this.getItem(key);
184
+ reusableView.rendered = this._renderContent(type, reusableView.content);
185
+ }
186
+ _renderContent(type, content) {
187
+ let cached = this._renderedContent.get(content);
188
+ if (cached != null) return cached;
189
+ let rendered = this.delegate.renderView(type, content);
190
+ if (content) this._renderedContent.set(content, rendered);
191
+ return rendered;
192
+ }
193
+ /**
194
+ * Returns an array of all currently visible views, including both
195
+ * item views and supplementary views.
196
+ */ get visibleViews() {
197
+ return Array.from(this._visibleViews.values());
198
+ }
199
+ /**
200
+ * Gets the visible view for the given type and key. Returns null if
201
+ * the view is not currently visible.
202
+ *
203
+ * @param key The key of the view to retrieve.
204
+ */ getView(key) {
205
+ return this._visibleViews.get(key) || null;
206
+ }
207
+ /**
208
+ * Returns an array of visible views matching the given type.
209
+ * @param type The view type to find.
210
+ */ getViewsOfType(type) {
211
+ return this.visibleViews.filter((v)=>v.layoutInfo && v.layoutInfo.type === type);
212
+ }
213
+ /**
214
+ * Returns the key for the given view. Returns null
215
+ * if the view is not currently visible.
216
+ */ keyForView(view) {
217
+ if (view && view.layoutInfo) return view.layoutInfo.key;
218
+ return null;
219
+ }
220
+ /**
221
+ * Returns the key for the item view currently at the given point.
222
+ */ keyAtPoint(point) {
223
+ let rect = new (0, $60423f92c7f9ad87$export$c79fc6492f3af13d)(point.x, point.y, 1, 1);
224
+ let layoutInfos = this.layout.getVisibleLayoutInfos(rect);
225
+ // Layout may return multiple layout infos in the case of
226
+ // persisted keys, so find the first one that actually intersects.
227
+ for (let layoutInfo of layoutInfos){
228
+ if (layoutInfo.rect.intersects(rect)) return layoutInfo.key;
229
+ }
230
+ return null;
231
+ }
232
+ /**
233
+ * Cleanup for when the Virtualizer will be unmounted.
234
+ */ willUnmount() {
235
+ cancelAnimationFrame(this._relayoutRaf);
236
+ }
237
+ /**
238
+ * Triggers a layout invalidation, and updates the visible subviews.
239
+ */ relayout(context = {}) {
240
+ // Ignore relayouts while animating the scroll position
241
+ if (this._scrollAnimation || typeof requestAnimationFrame === "undefined") return;
242
+ // If we already scheduled a relayout, extend the invalidation
243
+ // context so we coalesce multiple relayouts in the same frame.
244
+ if (this._invalidationContext) {
245
+ Object.assign(this._invalidationContext, context);
246
+ return;
247
+ }
248
+ this._invalidationContext = context;
249
+ }
250
+ /**
251
+ * Performs a relayout immediately. Prefer {@link relayout} over this method
252
+ * where possible, since it coalesces multiple layout passes in the same tick.
253
+ */ relayoutNow(context = this._invalidationContext || {}) {
254
+ // Cancel the scheduled relayout, since we're doing it now.
255
+ if (this._relayoutRaf) {
256
+ cancelAnimationFrame(this._relayoutRaf);
257
+ this._relayoutRaf = null;
258
+ // Update the provided context with the current invalidationContext since we are cancelling
259
+ // a scheduled relayoutNow call that has this._invalidationContext set as its default context arg (relayoutNow() in relayout)
260
+ context = {
261
+ ...this._invalidationContext,
262
+ ...context
263
+ };
264
+ }
265
+ // Reset the invalidation context
266
+ this._invalidationContext = null;
267
+ // Do nothing if we don't have a layout or content, or we are
268
+ // in the middle of an animated scroll transition.
269
+ if (!this.layout || !this._collection || this._scrollAnimation) return;
270
+ let scrollAnchor = this._getScrollAnchor();
271
+ // Trigger the beforeLayout hook, if provided
272
+ if (typeof context.beforeLayout === "function") context.beforeLayout();
273
+ // Validate the layout
274
+ this.layout.validate(context);
275
+ this._setContentSize(this.layout.getContentSize());
276
+ // Trigger the afterLayout hook, if provided
277
+ if (typeof context.afterLayout === "function") context.afterLayout();
278
+ // Adjust scroll position based on scroll anchor, and constrain.
279
+ // If the content changed, scroll to the top.
280
+ let visibleRect = this.getVisibleRect();
281
+ let restoredScrollAnchor = this._restoreScrollAnchor(scrollAnchor, context);
282
+ let contentOffsetX = context.contentChanged ? 0 : restoredScrollAnchor.x;
283
+ let contentOffsetY = context.contentChanged ? 0 : restoredScrollAnchor.y;
284
+ contentOffsetX = Math.max(0, Math.min(this.contentSize.width - visibleRect.width, contentOffsetX));
285
+ contentOffsetY = Math.max(0, Math.min(this.contentSize.height - visibleRect.height, contentOffsetY));
286
+ let hasLayoutUpdates = false;
287
+ if (contentOffsetX !== visibleRect.x || contentOffsetY !== visibleRect.y) {
288
+ // If this is an animated relayout, we do not immediately scroll because it would be jittery.
289
+ // Save the difference between the current and new content offsets, and apply it to the
290
+ // individual content items instead. At the end of the animation, we'll reset and set the
291
+ // scroll offset for real. This ensures jitter-free animation since we don't need to sync
292
+ // the scroll animation and the content animation.
293
+ if (context.animated || !this._animatedContentOffset.isOrigin()) {
294
+ this._animatedContentOffset.x += visibleRect.x - contentOffsetX;
295
+ this._animatedContentOffset.y += visibleRect.y - contentOffsetY;
296
+ hasLayoutUpdates = this.updateSubviews(context.contentChanged);
297
+ } else this._setContentOffset(new (0, $3041db3296945e6e$export$baf26146a414f24a)(contentOffsetX, contentOffsetY));
298
+ } else hasLayoutUpdates = this.updateSubviews(context.contentChanged);
299
+ // Apply layout infos, unless this is coming from an animated transaction
300
+ if (!(context.transaction && context.animated)) this._applyLayoutInfos();
301
+ // Wait for animations, and apply the afterAnimation hook, if provided
302
+ if (context.animated && hasLayoutUpdates) {
303
+ this._enableTransitions();
304
+ let done = ()=>{
305
+ this._disableTransitions();
306
+ // Reset scroll position after animations (see above comment).
307
+ if (!this._animatedContentOffset.isOrigin()) {
308
+ // Get the content offset to scroll to, taking _animatedContentOffset into account.
309
+ let { x: x, y: y } = this.getVisibleRect();
310
+ this._resetAnimatedContentOffset();
311
+ this._setContentOffset(new (0, $3041db3296945e6e$export$baf26146a414f24a)(x, y));
312
+ }
313
+ if (typeof context.afterAnimation === "function") context.afterAnimation();
314
+ };
315
+ // Sometimes the animation takes slightly longer than expected.
316
+ setTimeout(done, this.transitionDuration + 100);
317
+ return;
318
+ } else if (typeof context.afterAnimation === "function") context.afterAnimation();
319
+ }
320
+ /**
321
+ * Corrects DOM order of visible views to match item order of collection.
322
+ */ _correctItemOrder() {
323
+ // Defer until after scrolling and animated transactions are complete
324
+ if (this._isScrolling || this._transaction) return;
325
+ for (let key of this._visibleLayoutInfos.keys()){
326
+ let view = this._visibleViews.get(key);
327
+ this._children.delete(view);
328
+ this._children.add(view);
329
+ }
330
+ }
331
+ _enableTransitions() {
332
+ this.delegate.beginAnimations();
333
+ }
334
+ _disableTransitions() {
335
+ this.delegate.endAnimations();
336
+ }
337
+ _getScrollAnchor() {
338
+ if (!this.anchorScrollPosition) return null;
339
+ let visibleRect = this.getVisibleRect();
340
+ // Ask the delegate to provide a scroll anchor, if possible
341
+ if (this.delegate.getScrollAnchor) {
342
+ let key = this.delegate.getScrollAnchor(visibleRect);
343
+ if (key != null) {
344
+ let layoutInfo = this.layout.getLayoutInfo(key);
345
+ let corner = layoutInfo.rect.getCornerInRect(visibleRect);
346
+ if (corner) {
347
+ let key = layoutInfo.key;
348
+ let offset = layoutInfo.rect[corner].y - visibleRect.y;
349
+ return {
350
+ key: key,
351
+ layoutInfo: layoutInfo,
352
+ corner: corner,
353
+ offset: offset
354
+ };
355
+ }
356
+ }
357
+ }
358
+ // No need to anchor the scroll position if it is at the top
359
+ if (visibleRect.y === 0 && !this.anchorScrollPositionAtTop) return null;
360
+ // Find a view with a visible corner that has the smallest distance to the top of the collection view
361
+ let cornerAnchor = null;
362
+ for (let [key, view] of this._visibleViews){
363
+ let layoutInfo = view.layoutInfo;
364
+ if (layoutInfo && layoutInfo.rect.area > 0) {
365
+ let corner = layoutInfo.rect.getCornerInRect(visibleRect);
366
+ if (corner) {
367
+ let offset = layoutInfo.rect[corner].y - visibleRect.y;
368
+ if (!cornerAnchor || offset < cornerAnchor.offset) cornerAnchor = {
369
+ key: key,
370
+ layoutInfo: layoutInfo,
371
+ corner: corner,
372
+ offset: offset
373
+ };
374
+ }
375
+ }
376
+ }
377
+ return cornerAnchor;
378
+ }
379
+ _restoreScrollAnchor(scrollAnchor, context) {
380
+ let contentOffset = this.getVisibleRect();
381
+ if (scrollAnchor) {
382
+ var _context_transaction;
383
+ let finalAnchor = ((_context_transaction = context.transaction) === null || _context_transaction === void 0 ? void 0 : _context_transaction.animated) ? context.transaction.finalMap.get(scrollAnchor.key) : this.layout.getLayoutInfo(scrollAnchor.layoutInfo.key);
384
+ if (finalAnchor) {
385
+ let adjustment = finalAnchor.rect[scrollAnchor.corner].y - contentOffset.y - scrollAnchor.offset;
386
+ contentOffset.y += adjustment;
387
+ }
388
+ }
389
+ return contentOffset;
390
+ }
391
+ getVisibleRect() {
392
+ let v = this.visibleRect;
393
+ let x = v.x - this._animatedContentOffset.x;
394
+ let y = v.y - this._animatedContentOffset.y;
395
+ return new (0, $60423f92c7f9ad87$export$c79fc6492f3af13d)(x, y, v.width, v.height);
396
+ }
397
+ getVisibleLayoutInfos() {
398
+ let isTestEnv = false;
399
+ let isClientWidthMocked = Object.getOwnPropertyNames(window.HTMLElement.prototype).includes("clientWidth");
400
+ let isClientHeightMocked = Object.getOwnPropertyNames(window.HTMLElement.prototype).includes("clientHeight");
401
+ let rect;
402
+ if (isTestEnv && !(isClientWidthMocked && isClientHeightMocked)) rect = this._getContentRect();
403
+ else rect = this.shouldOverscan ? this._overscanManager.getOverscannedRect() : this.getVisibleRect();
404
+ this._visibleLayoutInfos = this._getLayoutInfoMap(rect);
405
+ return this._visibleLayoutInfos;
406
+ }
407
+ _getLayoutInfoMap(rect, copy = false) {
408
+ let layoutInfos = this.layout.getVisibleLayoutInfos(rect);
409
+ let map = new Map;
410
+ for (let layoutInfo of layoutInfos){
411
+ if (copy) layoutInfo = layoutInfo.copy();
412
+ map.set(layoutInfo.key, layoutInfo);
413
+ }
414
+ return map;
415
+ }
416
+ updateSubviews(forceUpdate = false) {
417
+ if (!this._collection) return;
418
+ let visibleLayoutInfos = this.getVisibleLayoutInfos();
419
+ let currentlyVisible = this._visibleViews;
420
+ let toAdd, toRemove, toUpdate;
421
+ // If this is a force update, remove and re-add all views.
422
+ // Otherwise, find and update the diff.
423
+ if (forceUpdate) {
424
+ toAdd = visibleLayoutInfos;
425
+ toRemove = currentlyVisible;
426
+ toUpdate = new Set();
427
+ } else {
428
+ ({ toAdd: toAdd, toRemove: toRemove, toUpdate: toUpdate } = (0, $fc36f9a046a9ce79$export$acaf96a27438246b)(currentlyVisible, visibleLayoutInfos));
429
+ for (let key of toUpdate){
430
+ let view = currentlyVisible.get(key);
431
+ if (!view || !view.layoutInfo) continue;
432
+ let item = this.getItem(visibleLayoutInfos.get(key).key);
433
+ if (view.content === item) toUpdate.delete(key);
434
+ else {
435
+ // If the view type changes, delete and recreate the view instead of updating
436
+ let { reuseType: reuseType } = this._getReuseType(view.layoutInfo, item);
437
+ if (view.viewType !== reuseType) {
438
+ toUpdate.delete(key);
439
+ toAdd.add(key);
440
+ toRemove.add(key);
441
+ }
442
+ }
443
+ }
444
+ // We are done if the sets are equal
445
+ if (toAdd.size === 0 && toRemove.size === 0 && toUpdate.size === 0) {
446
+ if (this._transaction) this._applyLayoutInfos();
447
+ return;
448
+ }
449
+ }
450
+ // Track views that should be removed. They are not removed from
451
+ // the DOM immediately, since we may reuse and need to re-insert
452
+ // them back into the DOM anyway.
453
+ let removed = new Set();
454
+ for (let key of toRemove.keys()){
455
+ let view = this._visibleViews.get(key);
456
+ if (view) {
457
+ removed.add(view);
458
+ this._visibleViews.delete(key);
459
+ // If we are in the middle of a transaction, wait until the end
460
+ // of the animations to remove the views from the DOM. Also means
461
+ // we can't reuse those views immediately.
462
+ if (this._transaction) this._transaction.toRemove.set(key, view);
463
+ else this.reuseView(view);
464
+ }
465
+ }
466
+ for (let key of toAdd.keys()){
467
+ let layoutInfo = visibleLayoutInfos.get(key);
468
+ let view;
469
+ // If we're in a transaction, and a layout change happens
470
+ // during the animations such that a view that was going
471
+ // to be removed is now not, we don't create a new view
472
+ // since the old one is still in the DOM, marked as toRemove.
473
+ if (this._transaction) {
474
+ // if transaction, get initial layout attributes for the animation
475
+ if (this._transaction.initialLayoutInfo.has(key)) layoutInfo = this._transaction.initialLayoutInfo.get(key);
476
+ view = this._transaction.toRemove.get(key);
477
+ if (view) {
478
+ this._transaction.toRemove.delete(key);
479
+ this._applyLayoutInfo(view, layoutInfo);
480
+ }
481
+ }
482
+ if (!view) {
483
+ // Create or reuse a view for this row
484
+ view = this.getReusableView(layoutInfo);
485
+ // Add the view to the DOM if needed
486
+ if (!removed.has(view)) this._children.add(view);
487
+ }
488
+ this._visibleViews.set(key, view);
489
+ removed.delete(view);
490
+ }
491
+ for (let key of toUpdate){
492
+ let view = currentlyVisible.get(key);
493
+ this._renderedContent.delete(key);
494
+ this._renderView(view);
495
+ }
496
+ // Remove the remaining rows to delete from the DOM
497
+ if (!this._transaction) this.removeViews(removed);
498
+ this._correctItemOrder();
499
+ this._flushVisibleViews();
500
+ let hasLayoutUpdates = this._transaction && (toAdd.size > 0 || toRemove.size > 0 || this._hasLayoutUpdates());
501
+ if (hasLayoutUpdates) requestAnimationFrame(()=>{
502
+ // If we're in a transaction, apply animations to visible views
503
+ // and "to be removed" views, which animate off screen.
504
+ if (this._transaction) requestAnimationFrame(()=>this._applyLayoutInfos());
505
+ });
506
+ return hasLayoutUpdates;
507
+ }
508
+ afterRender() {
509
+ if (this._transactionQueue.length > 0) this._processTransactionQueue();
510
+ else if (this._invalidationContext) this.relayoutNow();
511
+ if (this.shouldOverscan) this._overscanManager.collectMetrics();
512
+ }
513
+ _flushVisibleViews() {
514
+ // CollectionVirtualizer deals with a flattened set of LayoutInfos, but they can represent hierarchy
515
+ // by referencing a parentKey. Just before rendering the visible views, we rebuild this hierarchy
516
+ // by creating a mapping of views by parent key and recursively calling the delegate's renderWrapper
517
+ // method to build the final tree.
518
+ let viewsByParentKey = new Map([
519
+ [
520
+ null,
521
+ []
522
+ ]
523
+ ]);
524
+ for (let view of this._children){
525
+ var _view_layoutInfo, _viewsByParentKey_get, _view_layoutInfo1, _view_layoutInfo2, _view_layoutInfo3;
526
+ if (((_view_layoutInfo = view.layoutInfo) === null || _view_layoutInfo === void 0 ? void 0 : _view_layoutInfo.parentKey) != null && !viewsByParentKey.has(view.layoutInfo.parentKey)) viewsByParentKey.set(view.layoutInfo.parentKey, []);
527
+ (_viewsByParentKey_get = viewsByParentKey.get((_view_layoutInfo1 = view.layoutInfo) === null || _view_layoutInfo1 === void 0 ? void 0 : _view_layoutInfo1.parentKey)) === null || _viewsByParentKey_get === void 0 ? void 0 : _viewsByParentKey_get.push(view);
528
+ if (!viewsByParentKey.has((_view_layoutInfo2 = view.layoutInfo) === null || _view_layoutInfo2 === void 0 ? void 0 : _view_layoutInfo2.key)) viewsByParentKey.set((_view_layoutInfo3 = view.layoutInfo) === null || _view_layoutInfo3 === void 0 ? void 0 : _view_layoutInfo3.key, []);
529
+ }
530
+ let buildTree = (parent, views)=>views.map((view)=>{
531
+ let children = viewsByParentKey.get(view.layoutInfo.key);
532
+ return this.delegate.renderWrapper(parent, view, children, (childViews)=>buildTree(view, childViews));
533
+ });
534
+ let children = buildTree(null, viewsByParentKey.get(null));
535
+ this.delegate.setVisibleViews(children);
536
+ }
537
+ _applyLayoutInfo(view, layoutInfo) {
538
+ if (view.layoutInfo === layoutInfo) return false;
539
+ view.layoutInfo = layoutInfo;
540
+ return true;
541
+ }
542
+ _applyLayoutInfos() {
543
+ let updated = false;
544
+ // Apply layout infos to visible views
545
+ for (let view of this._visibleViews.values()){
546
+ let cur = view.layoutInfo;
547
+ if ((cur === null || cur === void 0 ? void 0 : cur.key) != null) {
548
+ let layoutInfo = this.layout.getLayoutInfo(cur.key);
549
+ if (this._applyLayoutInfo(view, layoutInfo)) updated = true;
550
+ }
551
+ }
552
+ // Apply final layout infos for views that will be removed
553
+ if (this._transaction) {
554
+ for (let view of this._transaction.toRemove.values()){
555
+ let cur = view.layoutInfo;
556
+ if ((cur === null || cur === void 0 ? void 0 : cur.key) != null) {
557
+ let layoutInfo = this.layout.getLayoutInfo(cur.key);
558
+ if (this._applyLayoutInfo(view, layoutInfo)) updated = true;
559
+ }
560
+ }
561
+ for (let view of this._transaction.removed.values()){
562
+ let cur = view.layoutInfo;
563
+ let layoutInfo = this._transaction.finalLayoutInfo.get(cur.key) || cur;
564
+ layoutInfo = this.layout.getFinalLayoutInfo(layoutInfo.copy());
565
+ if (this._applyLayoutInfo(view, layoutInfo)) updated = true;
566
+ }
567
+ }
568
+ if (updated) this._flushVisibleViews();
569
+ }
570
+ _hasLayoutUpdates() {
571
+ if (!this._transaction) return false;
572
+ for (let view of this._visibleViews.values()){
573
+ let cur = view.layoutInfo;
574
+ if (!cur) return true;
575
+ let layoutInfo = this.layout.getLayoutInfo(cur.key);
576
+ if (// Uses equals rather than pointEquals so that width/height changes are taken into account
577
+ !cur.rect.equals(layoutInfo.rect) || cur.opacity !== layoutInfo.opacity || cur.transform !== layoutInfo.transform) return true;
578
+ }
579
+ return false;
580
+ }
581
+ reuseView(view) {
582
+ view.prepareForReuse();
583
+ this._reusableViews[view.viewType].push(view);
584
+ }
585
+ removeViews(toRemove) {
586
+ for (let view of toRemove)this._children.delete(view);
587
+ }
588
+ updateItemSize(key, size) {
589
+ // TODO: we should be able to invalidate a single index path
590
+ // @ts-ignore
591
+ if (!this.layout.updateItemSize) return;
592
+ // If the scroll position is currently animating, add the update
593
+ // to a queue to be processed after the animation is complete.
594
+ if (this._scrollAnimation) {
595
+ this._sizeUpdateQueue.set(key, size);
596
+ return;
597
+ }
598
+ // @ts-ignore
599
+ let changed = this.layout.updateItemSize(key, size);
600
+ if (changed) this.relayout();
601
+ }
602
+ startScrolling() {
603
+ this._isScrolling = true;
604
+ }
605
+ endScrolling() {
606
+ this._isScrolling = false;
607
+ this._correctItemOrder();
608
+ this._flushVisibleViews();
609
+ }
610
+ _resetAnimatedContentOffset() {
611
+ // Reset the animated content offset of subviews. See comment in relayoutNow for details.
612
+ if (!this._animatedContentOffset.isOrigin()) {
613
+ this._animatedContentOffset = new (0, $3041db3296945e6e$export$baf26146a414f24a)(0, 0);
614
+ this._applyLayoutInfos();
615
+ }
616
+ }
617
+ /**
618
+ * Scrolls the item with the given key into view, optionally with an animation.
619
+ * @param key The key of the item to scroll into view.
620
+ * @param duration The duration of the scroll animation.
621
+ */ scrollToItem(key, options) {
622
+ // key can be 0, so check if null or undefined
623
+ if (key == null) return;
624
+ let layoutInfo = this.layout.getLayoutInfo(key);
625
+ if (!layoutInfo) return;
626
+ let { duration: duration = 300, shouldScrollX: shouldScrollX = true, shouldScrollY: shouldScrollY = true, offsetX: offsetX = 0, offsetY: offsetY = 0 } = options;
627
+ let x = this.visibleRect.x;
628
+ let y = this.visibleRect.y;
629
+ let minX = layoutInfo.rect.x - offsetX;
630
+ let minY = layoutInfo.rect.y - offsetY;
631
+ let maxX = x + this.visibleRect.width;
632
+ let maxY = y + this.visibleRect.height;
633
+ if (shouldScrollX) {
634
+ if (minX <= x || maxX === 0) x = minX;
635
+ else if (layoutInfo.rect.maxX > maxX) x += layoutInfo.rect.maxX - maxX;
636
+ }
637
+ if (shouldScrollY) {
638
+ if (minY <= y || maxY === 0) y = minY;
639
+ else if (layoutInfo.rect.maxY > maxY) y += layoutInfo.rect.maxY - maxY;
640
+ }
641
+ return this.scrollTo(new (0, $3041db3296945e6e$export$baf26146a414f24a)(x, y), duration);
642
+ }
643
+ /**
644
+ * Performs an animated scroll to the given offset.
645
+ * @param offset - The offset to scroll to.
646
+ * @param duration The duration of the animation.
647
+ * @returns A promise that resolves when the animation is complete.
648
+ */ scrollTo(offset, duration = 300) {
649
+ // Cancel the current scroll animation
650
+ if (this._scrollAnimation) {
651
+ this._scrollAnimation.cancel();
652
+ this._scrollAnimation = null;
653
+ }
654
+ // Set the content offset synchronously if the duration is zero
655
+ if (duration <= 0 || this.visibleRect.pointEquals(offset)) {
656
+ this._setContentOffset(offset);
657
+ return Promise.resolve();
658
+ }
659
+ this.startScrolling();
660
+ this._scrollAnimation = (0, $3eb131dcf37ad5f8$export$dc0b63720788090c)(this.visibleRect, offset, duration, (0, $3eb131dcf37ad5f8$export$57636bb43b1ccbb0), (offset)=>{
661
+ this._setContentOffset(offset);
662
+ });
663
+ this._scrollAnimation.then(()=>{
664
+ this._scrollAnimation = null;
665
+ // Process view size updates that occurred during the animation.
666
+ // Only views that are still visible will be actually updated.
667
+ for (let [key, size] of this._sizeUpdateQueue)this.updateItemSize(key, size);
668
+ this._sizeUpdateQueue.clear();
669
+ this.relayout();
670
+ this._processTransactionQueue();
671
+ this.endScrolling();
672
+ });
673
+ return this._scrollAnimation;
674
+ }
675
+ _runTransaction(action, animated) {
676
+ this._startTransaction();
677
+ if (this._nextTransaction) this._nextTransaction.actions.push(action);
678
+ this._endTransaction(animated);
679
+ }
680
+ _startTransaction() {
681
+ if (!this._nextTransaction) this._nextTransaction = new (0, $8e135e531d8dcb66$export$febc5573c75cefb0);
682
+ this._nextTransaction.level++;
683
+ }
684
+ _endTransaction(animated) {
685
+ if (!this._nextTransaction) return false;
686
+ // Save whether the transaction should be animated.
687
+ if (animated != null) this._nextTransaction.animated = animated;
688
+ // If we haven't reached level 0, we are still in a
689
+ // nested transaction. Wait for the parent to end.
690
+ if (--this._nextTransaction.level > 0) return false;
691
+ // Do nothing for empty transactions
692
+ if (this._nextTransaction.actions.length === 0) {
693
+ this._nextTransaction = null;
694
+ return false;
695
+ }
696
+ // Default animations to true
697
+ if (this._nextTransaction.animated == null) this._nextTransaction.animated = true;
698
+ // Enqueue the transaction
699
+ this._transactionQueue.push(this._nextTransaction);
700
+ this._nextTransaction = null;
701
+ return true;
702
+ }
703
+ _processTransactionQueue() {
704
+ // If the current transaction is animating, wait until the end
705
+ // to process the next transaction.
706
+ if (this._transaction || this._scrollAnimation) return;
707
+ let next = this._transactionQueue.shift();
708
+ if (next) this._performTransaction(next);
709
+ }
710
+ _getContentRect() {
711
+ return new (0, $60423f92c7f9ad87$export$c79fc6492f3af13d)(0, 0, this.contentSize.width, this.contentSize.height);
712
+ }
713
+ _performTransaction(transaction) {
714
+ this._transaction = transaction;
715
+ this.relayoutNow({
716
+ transaction: transaction,
717
+ animated: transaction.animated,
718
+ beforeLayout: ()=>{
719
+ // Get the initial layout infos for all views before the updates
720
+ // so we can figure out which views to add and remove.
721
+ if (transaction.animated) transaction.initialMap = this._getLayoutInfoMap(this._getContentRect(), true);
722
+ // Apply the actions that occurred during this transaction
723
+ for (let action of transaction.actions)action();
724
+ },
725
+ afterLayout: ()=>{
726
+ // Get the final layout infos after the updates
727
+ if (transaction.animated) {
728
+ transaction.finalMap = this._getLayoutInfoMap(this._getContentRect());
729
+ this._setupTransactionAnimations(transaction);
730
+ } else this._transaction = null;
731
+ },
732
+ afterAnimation: ()=>{
733
+ // Remove and reuse views when animations are done
734
+ if (transaction.toRemove.size > 0 || transaction.removed.size > 0) for (let view of (0, $fc36f9a046a9ce79$export$cfc14088dfefce5f)(transaction.toRemove.values(), transaction.removed.values())){
735
+ this._children.delete(view);
736
+ this.reuseView(view);
737
+ }
738
+ this._transaction = null;
739
+ // Ensure DOM order is correct for accessibility after animations are complete
740
+ this._correctItemOrder();
741
+ this._flushVisibleViews();
742
+ this._processTransactionQueue();
743
+ }
744
+ });
745
+ }
746
+ _setupTransactionAnimations(transaction) {
747
+ let { initialMap: initialMap, finalMap: finalMap } = transaction;
748
+ // Store initial and final layout infos for animations
749
+ for (let [key, layoutInfo] of initialMap)if (finalMap.has(key)) // Store the initial layout info for use during animations.
750
+ transaction.initialLayoutInfo.set(key, layoutInfo);
751
+ else // This view was removed. Store the layout info for use
752
+ // in Layout#getFinalLayoutInfo during animations.
753
+ transaction.finalLayoutInfo.set(layoutInfo.key, layoutInfo);
754
+ // Get initial layout infos for views that were added
755
+ for (let [key, layoutInfo] of finalMap)if (!initialMap.has(key)) {
756
+ let initialLayoutInfo = this.layout.getInitialLayoutInfo(layoutInfo.copy());
757
+ transaction.initialLayoutInfo.set(key, initialLayoutInfo);
758
+ }
759
+ // Figure out which views were removed.
760
+ for (let [key, view] of this._visibleViews)// If an item has a width of 0, there is no need to remove it from the _visibleViews.
761
+ // Removing an item with width of 0 can cause a loop where the item gets added, removed,
762
+ // added, removed... etc in a loop.
763
+ if (!finalMap.has(key) && view.layoutInfo.rect.width > 0) {
764
+ transaction.removed.set(key, view);
765
+ this._visibleViews.delete(key);
766
+ // In case something weird happened, where we have a view but no
767
+ // initial layout info, use the one attached to the view.
768
+ if (view.layoutInfo) {
769
+ if (!transaction.finalLayoutInfo.has(view.layoutInfo.key)) transaction.finalLayoutInfo.set(view.layoutInfo.key, view.layoutInfo);
770
+ }
771
+ }
772
+ }
773
+ constructor(options = {}){
774
+ this._contentSize = new (0, $ee1bfa90a957fb8a$export$cb6da89c6af1a8ec);
775
+ this._visibleRect = new (0, $60423f92c7f9ad87$export$c79fc6492f3af13d);
776
+ this._reusableViews = {};
777
+ this._visibleLayoutInfos = new Map();
778
+ this._visibleViews = new Map();
779
+ this._renderedContent = new WeakMap();
780
+ this._children = new Set();
781
+ this._invalidationContext = null;
782
+ this._overscanManager = new (0, $364191b3decf3697$export$4455ee6afb38dcbb)();
783
+ this._persistedKeys = new Set();
784
+ this._scrollAnimation = null;
785
+ this._isScrolling = false;
786
+ this._sizeUpdateQueue = new Map();
787
+ this._animatedContentOffset = new (0, $3041db3296945e6e$export$baf26146a414f24a)(0, 0);
788
+ this._transaction = null;
789
+ this._nextTransaction = null;
790
+ this._transactionQueue = [];
791
+ var _options_transitionDuration;
792
+ // Set options from passed object if given
793
+ this.transitionDuration = (_options_transitionDuration = options.transitionDuration) !== null && _options_transitionDuration !== void 0 ? _options_transitionDuration : 500;
794
+ this.anchorScrollPosition = options.anchorScrollPosition || false;
795
+ this.anchorScrollPositionAtTop = options.anchorScrollPositionAtTop || false;
796
+ this.shouldOverscan = options.shouldOverscan !== false;
797
+ for (let key of [
798
+ "delegate",
799
+ "size",
800
+ "layout",
801
+ "collection"
802
+ ])if (options[key]) this[key] = options[key];
803
+ }
804
+ }
805
+
806
+
807
+ export {$38b9490c1cca8fc4$export$89be5a243e59c4b2 as Virtualizer};
808
+ //# sourceMappingURL=Virtualizer.module.js.map