-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: Tree multiple level loading support and only count "items" for collection size #8349
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
390b6b0
50c6f14
f99e4bd
76bc6dd
7123f7e
1b4b7b5
5dbf204
63a9fd8
ddffc91
f24361d
3c8058f
6ca4b80
8749e85
493c680
1d26003
c719c18
fbfae78
19ea161
6095683
74db6cb
b6bb68b
da608f3
81de58a
6907e1e
7217b93
eb1aa3c
4eab8de
88b725a
463115d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -253,41 +253,47 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte | |
|
|
||
| protected buildCollection(y: number = this.padding): LayoutNode[] { | ||
| let collection = this.virtualizer!.collection; | ||
| let skipped = 0; | ||
| let collectionNodes = [...collection]; | ||
| let loaderNodes = collectionNodes.filter(node => node.type === 'loader'); | ||
| let nodes: LayoutNode[] = []; | ||
| let isEmptyOrLoading = collection?.size === 0 || (collection.size === 1 && collection.getItem(collection.getFirstKey()!)!.type === 'loader'); | ||
| let isEmptyOrLoading = collection?.size === 0; | ||
| if (isEmptyOrLoading) { | ||
| y = 0; | ||
| } | ||
|
|
||
| for (let node of collection) { | ||
| for (let node of collectionNodes) { | ||
| let rowHeight = (this.rowHeight ?? this.estimatedRowHeight ?? DEFAULT_HEIGHT) + this.gap; | ||
| // Skip rows before the valid rectangle unless they are already cached. | ||
| if (node.type === 'item' && y + rowHeight < this.requestedRect.y && !this.isValid(node, y)) { | ||
| y += rowHeight; | ||
| skipped++; | ||
| continue; | ||
| } | ||
|
|
||
| let layoutNode = this.buildChild(node, this.padding, y, null); | ||
| y = layoutNode.layoutInfo.rect.maxY + this.gap; | ||
| nodes.push(layoutNode); | ||
| if (node.type === 'item' && y > this.requestedRect.maxY) { | ||
| let itemsAfterRect = collection.size - (nodes.length + skipped); | ||
| let lastNode = collection.getItem(collection.getLastKey()!); | ||
| if (lastNode?.type === 'loader') { | ||
| itemsAfterRect--; | ||
| } | ||
|
|
||
| y += itemsAfterRect * rowHeight; | ||
| if (node.type === 'loader') { | ||
| let index = loaderNodes.indexOf(node); | ||
| loaderNodes.splice(index, 1); | ||
| } | ||
|
|
||
| // Always add the loader sentinel if present. This assumes the loader is the last option/row | ||
| // will need to refactor when handling multi section loading | ||
| if (lastNode?.type === 'loader' && nodes.at(-1)?.layoutInfo.type !== 'loader') { | ||
| let loader = this.buildChild(lastNode, this.padding, y, null); | ||
| // Build each loader that exists in the collection that is outside the visible rect so that they are persisted | ||
| // at the proper estimated location. If the node.type is "section" then we don't do this shortcut since we have to | ||
| // build the sections to see how tall they are. | ||
| if ((node.type === 'item' || node.type === 'loader') && y > this.requestedRect.maxY) { | ||
| let lastProcessedIndex = collectionNodes.indexOf(node); | ||
| for (let loaderNode of loaderNodes) { | ||
| let loaderNodeIndex = collectionNodes.indexOf(loaderNode); | ||
| // Subtract by an additional 1 since we've already added the current item's height to y | ||
| y += (loaderNodeIndex - lastProcessedIndex - 1) * rowHeight; | ||
| let loader = this.buildChild(loaderNode, this.padding, y, null); | ||
| nodes.push(loader); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this potentially reorder the loaders? This would put them all at the end, even if they were somewhere else within the collection originally.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we only hit this point if we past the virtualizer's requested rect though right? At that point we only need/want to build and persist the loaders, and the order of these remaining loaders should be correct provided that iterating over the collection provides the nodes in their proper order
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. my mental model for this flow is essentially:
so theoretically the order of the loaders should be preserved right? |
||
| y = loader.layoutInfo.rect.maxY; | ||
| lastProcessedIndex = loaderNodeIndex; | ||
| } | ||
|
|
||
| // Account for the rest of the items after the last loader spinner, subtract by 1 since we've processed the current node's height already | ||
| y += (collectionNodes.length - lastProcessedIndex - 1) * rowHeight; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.