Skip to content

fix: properly render empty state when filtering S2 ComboBox with sections #8735

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

Merged
merged 1 commit into from
Aug 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/@react-spectrum/s2/stories/ComboBox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const meta: Meta<typeof ComboBox<any>> = {
},
tags: ['autodocs'],
argTypes: {
...categorizeArgTypes('Events', ['onInputChange', 'onOpenChange', 'onSelectionChange']),
...categorizeArgTypes('Events', ['onInputChange', 'onOpenChange', 'onSelectionChange', 'onLoadMore']),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't realize we had to do this for any action handlers due to storybook 8 making implicit actions error...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah... it's awful :(

label: {control: {type: 'text'}},
description: {control: {type: 'text'}},
errorMessage: {control: {type: 'text'}},
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-spectrum/s2/stories/Picker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const meta: Meta<typeof Picker<any>> = {
decorators: [StaticColorDecorator],
tags: ['autodocs'],
argTypes: {
...categorizeArgTypes('Events', ['onOpenChange', 'onSelectionChange']),
...categorizeArgTypes('Events', ['onOpenChange', 'onSelectionChange', 'onLoadMore']),
label: {control: {type: 'text'}},
description: {control: {type: 'text'}},
errorMessage: {control: {type: 'text'}},
Expand Down
26 changes: 15 additions & 11 deletions packages/@react-stately/list/src/ListCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,17 @@ export class ListCollection<T> implements Collection<Node<T>> {
private iterable: Iterable<Node<T>>;
private firstKey: Key | null = null;
private lastKey: Key | null = null;
private _size: number;

constructor(nodes: Iterable<Node<T>>) {
this.iterable = nodes;

let visit = (node: Node<T>) => {
// Skip the loader node so it isn't added to the keymap and thus
// doesn't influence the size count. This should only matter for RAC and S2
if (node.type !== 'loader') {
this.keyMap.set(node.key, node);

if (node.childNodes && node.type === 'section') {
for (let child of node.childNodes) {
visit(child);
}
this.keyMap.set(node.key, node);

if (node.childNodes && node.type === 'section') {
for (let child of node.childNodes) {
visit(child);
}
}
};
Expand All @@ -41,6 +38,7 @@ export class ListCollection<T> implements Collection<Node<T>> {

let last: Node<T> | null = null;
let index = 0;
let size = 0;
for (let [key, node] of this.keyMap) {
if (last) {
last.nextKey = key;
Expand All @@ -54,13 +52,19 @@ export class ListCollection<T> implements Collection<Node<T>> {
node.index = index++;
}

// Only count sections and items when determining size so that
// loaders and separators in RAC/S2 don't influence the emptyState determination
if (node.type === 'section' || node.type === 'item') {
size++;
}

Comment on lines +55 to +60
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't affect v3 theoretically since there wasn't a concept of loader/separator nodes

last = node;

// Set nextKey as undefined since this might be the last node
// If it isn't the last node, last.nextKey will properly set at start of new loop
last.nextKey = undefined;
}

this._size = size;
this.lastKey = last?.key ?? null;
}

Expand All @@ -69,7 +73,7 @@ export class ListCollection<T> implements Collection<Node<T>> {
}

get size(): number {
return this.keyMap.size;
return this._size;
}

getKeys(): IterableIterator<Key> {
Expand Down