Skip to content

Commit 87d2d7e

Browse files
authored
fix: CardView skeleton loading should appear even if renderEmptyState is provided (#8603)
1 parent 0cb9045 commit 87d2d7e

File tree

5 files changed

+50
-8
lines changed

5 files changed

+50
-8
lines changed

packages/@react-spectrum/s2/chromatic/CardView.stories.tsx

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {CardView, Content, Heading, IllustratedMessage} from '../src';
13+
import {CardView, Content, Heading, IllustratedMessage, SkeletonCollection} from '../src';
1414
import EmptyIcon from '../spectrum-illustrations/gradient/generic1/Image';
1515
import type {Meta, StoryObj} from '@storybook/react';
16+
import {PhotoCard} from '../stories/CardView.stories';
1617
import {style} from '../style/spectrum-theme' with {type: 'macro'};
1718

1819
const meta: Meta<typeof CardView> = {
@@ -49,3 +50,36 @@ export const Empty: StoryObj<typeof CardView> = {
4950
</CardView>
5051
)
5152
};
53+
54+
export const Loading: StoryObj<typeof CardView> = {
55+
render: (args) => (
56+
<CardView
57+
aria-label="Assets"
58+
loadingState="loading"
59+
styles={cardViewStyles}
60+
renderEmptyState={() => (
61+
<IllustratedMessage size="L">
62+
<EmptyIcon />
63+
<Heading>Create your first asset.</Heading>
64+
<Content>Get started by uploading or importing some assets.</Content>
65+
</IllustratedMessage>
66+
)}
67+
{...args}>
68+
<SkeletonCollection>
69+
{() => (
70+
<PhotoCard
71+
layout="grid"
72+
item={{
73+
id: Math.random(),
74+
user: {name: 'Devon Govett', profile_image: {small: ''}},
75+
urls: {regular: ''},
76+
description: 'This is a fake description. Kinda long so it wraps to a new line.',
77+
alt_description: '',
78+
width: 400,
79+
height: 200 + Math.max(0, Math.round(Math.random() * 400))
80+
}} />
81+
)}
82+
</SkeletonCollection>
83+
</CardView>
84+
)
85+
};

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,10 @@ export const CardView = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ca
203203
UNSAFE_className = '',
204204
UNSAFE_style,
205205
styles,
206+
loadingState,
206207
onLoadMore,
207208
items,
209+
renderEmptyState,
208210
...otherProps} = props;
209211
let domRef = useDOMRef(ref);
210212
let innerRef = useRef(null);
@@ -244,9 +246,11 @@ export const CardView = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ca
244246

245247
let {selectedKeys, onSelectionChange, actionBar, actionBarHeight} = useActionBarContainer({...props, scrollRef});
246248

249+
let isLoading = loadingState === 'loading' || loadingState === 'loadingMore';
247250
let renderer;
248251
let cardLoadingSentinel = (
249252
<GridListLoadMoreItem
253+
isLoading={isLoading}
250254
onLoadMore={onLoadMore} />
251255
);
252256

@@ -276,6 +280,7 @@ export const CardView = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ca
276280
<AriaGridList
277281
ref={scrollRef}
278282
{...otherProps}
283+
renderEmptyState={!isLoading ? renderEmptyState : undefined}
279284
items={items}
280285
layout="grid"
281286
selectionBehavior={selectionStyle === 'highlight' ? 'replace' : 'toggle'}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const meta: Meta<typeof CardView> = {
4444
args: {
4545
onLoadMore: fn()
4646
},
47-
excludeStories: ['ExampleRender']
47+
excludeStories: ['ExampleRender', 'PhotoCard']
4848
};
4949

5050
export default meta;
@@ -78,7 +78,7 @@ const avatarSize = {
7878
XL: 32
7979
} as const;
8080

81-
function PhotoCard({item, layout}: {item: Item, layout: string}) {
81+
export function PhotoCard({item, layout}: {item: Item, layout: string}) {
8282
return (
8383
<Card id={item.id} textValue={item.description || item.alt_description}>
8484
{({size}) => (<>

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,11 @@ export class GridLayout<T, O extends GridLayoutOptions = GridLayoutOptions> exte
122122

123123
let collection = this.virtualizer!.collection;
124124
// 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
126-
let isEmptyOrLoading = collection?.size === 0;
127-
let rows = isEmptyOrLoading ? 0 : Math.ceil(collection.size / numColumns);
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);
128130
let iterator = collection[Symbol.iterator]();
129131
let y = rows > 0 ? minSpace.height : 0;
130132
let newLayoutInfos = new Map();

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ export class WaterfallLayout<T extends object, O extends WaterfallLayoutOptions
169169
newLayoutInfos.set(lastNode.key, layoutInfo);
170170
}
171171

172-
// Reset all columns to the maximum for the next section. If loading, set to 0 so virtualizer doesn't render its body since there aren't items to render
173-
let isEmptyOrLoading = collection?.size === 0;
172+
// Reset all columns to the maximum for the next section. If loading, set to 0 so virtualizer doesn't render its body since there aren't items to render,
173+
// except if we are performing skeleton loading
174+
let isEmptyOrLoading = collection?.size === 0 && collection.getItem(collection.getFirstKey()!)?.type !== 'skeleton';
174175
let maxHeight = isEmptyOrLoading ? 0 : Math.max(...columnHeights);
175176
this.contentSize = new Size(this.virtualizer!.visibleRect.width, maxHeight);
176177
this.layoutInfos = newLayoutInfos;

0 commit comments

Comments
 (0)