Skip to content

Commit c845dea

Browse files
authored
fix: CardView skeleton loaders (#8610)
1 parent f5a80a0 commit c845dea

File tree

2 files changed

+26
-8
lines changed

2 files changed

+26
-8
lines changed

packages/@react-spectrum/s2/src/CardView.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
GridListItem,
1919
GridListLoadMoreItem,
2020
GridListProps,
21+
GridListRenderProps,
2122
Size,
2223
Virtualizer,
2324
WaterfallLayout
@@ -206,7 +207,7 @@ export const CardView = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ca
206207
loadingState,
207208
onLoadMore,
208209
items,
209-
renderEmptyState,
210+
renderEmptyState: renderEmptyStateProp,
210211
...otherProps} = props;
211212
let domRef = useDOMRef(ref);
212213
let innerRef = useRef(null);
@@ -272,6 +273,15 @@ export const CardView = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ca
272273
);
273274
}
274275

276+
// Wrap the renderEmptyState function so that it is not called when there is a skeleton loader.
277+
let renderEmptyState = renderEmptyStateProp ? (renderProps: GridListRenderProps) => {
278+
let collection = renderProps.state.collection;
279+
let firstKey = collection.getFirstKey();
280+
if (firstKey == null || collection.getItem(firstKey)?.type !== 'skeleton') {
281+
return renderEmptyStateProp(renderProps);
282+
}
283+
} : undefined;
284+
275285
let cardView = (
276286
<Virtualizer layout={layout} layoutOptions={options}>
277287
<InternalCardViewContext.Provider value={GridListItem}>
@@ -280,7 +290,7 @@ export const CardView = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ca
280290
<AriaGridList
281291
ref={scrollRef}
282292
{...otherProps}
283-
renderEmptyState={!isLoading ? renderEmptyState : undefined}
293+
renderEmptyState={renderEmptyState}
284294
items={items}
285295
layout="grid"
286296
selectionBehavior={selectionStyle === 'highlight' ? 'replace' : 'toggle'}

packages/@react-stately/layout/src/GridLayout.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,21 @@ export class GridLayout<T, O extends GridLayoutOptions = GridLayoutOptions> exte
120120
let horizontalSpacing = Math.floor((visibleWidth - numColumns * itemWidth) / (numColumns + 1));
121121
this.gap = new Size(horizontalSpacing, minSpace.height);
122122

123+
// If there is a skeleton loader within the last 2 items in the collection, increment the collection size
124+
// so that an additional row is added for the skeletons.
123125
let collection = this.virtualizer!.collection;
124-
// Make sure to set rows to 0 if we performing a first time load or are rendering the empty state so that Virtualizer
125-
// won't try to render its body. If we detect a skeleton as the first item, then we want to render the skeleton items in place of
126-
// the renderEmptyState.
127-
let isSkeletonLoading = collection.getItem(collection.getFirstKey()!)?.type === 'skeleton';
128-
let isEmptyOrLoading = collection?.size === 0 && !isSkeletonLoading;
129-
let rows = isEmptyOrLoading ? 0 : Math.ceil(isSkeletonLoading ? 1 : collection.size / numColumns);
126+
let collectionSize = collection.size;
127+
let lastKey = collection.getLastKey();
128+
for (let i = 0; i < 2 && lastKey != null; i++) {
129+
let item = collection.getItem(lastKey);
130+
if (item?.type === 'skeleton') {
131+
collectionSize++;
132+
break;
133+
}
134+
lastKey = collection.getKeyBefore(lastKey);
135+
}
136+
137+
let rows = Math.ceil(collectionSize / numColumns);
130138
let iterator = collection[Symbol.iterator]();
131139
let y = rows > 0 ? minSpace.height : 0;
132140
let newLayoutInfos = new Map();

0 commit comments

Comments
 (0)