Skip to content

Commit 8fbe17f

Browse files
authored
fix: Updating collection when items change parents (#8052)
1 parent 7e7e33d commit 8fbe17f

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

packages/@react-aria/collections/src/Document.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,9 +460,13 @@ export class Document<T, C extends BaseCollection<T> = BaseCollection<T>> extend
460460
}
461461

462462
updateCollection(): void {
463-
// First, update the indices of dirty element children.
463+
// First, remove disconnected nodes and update the indices of dirty element children.
464464
for (let element of this.dirtyNodes) {
465-
element.updateChildIndices();
465+
if (element instanceof ElementNode && (!element.isConnected || element.isHidden)) {
466+
this.removeNode(element);
467+
} else {
468+
element.updateChildIndices();
469+
}
466470
}
467471

468472
// Next, update dirty collection nodes.
@@ -471,8 +475,6 @@ export class Document<T, C extends BaseCollection<T> = BaseCollection<T>> extend
471475
if (element.isConnected && !element.isHidden) {
472476
element.updateNode();
473477
this.addNode(element);
474-
} else {
475-
this.removeNode(element);
476478
}
477479

478480
element.isMutated = false;

packages/react-aria-components/test/ListBox.test.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,54 @@ describe('ListBox', () => {
337337
expect(getAllByRole('option').map(o => o.textContent)).toEqual(['Hi']);
338338
});
339339

340+
it('should update collection when moving item to a different section', () => {
341+
let {getAllByRole, rerender} = render(
342+
<ListBox aria-label="Test">
343+
<ListBoxSection id="veggies">
344+
<Header>Veggies</Header>
345+
<ListBoxItem key="lettuce" id="lettuce">Lettuce</ListBoxItem>
346+
<ListBoxItem key="tomato" id="tomato">Tomato</ListBoxItem>
347+
<ListBoxItem key="onion" id="onion">Onion</ListBoxItem>
348+
</ListBoxSection>
349+
<ListBoxSection id="meats">
350+
<Header>Meats</Header>
351+
<ListBoxItem key="ham" id="ham">Ham</ListBoxItem>
352+
<ListBoxItem key="tuna" id="tuna">Tuna</ListBoxItem>
353+
<ListBoxItem key="tofu" id="tofu">Tofu</ListBoxItem>
354+
</ListBoxSection>
355+
</ListBox>
356+
);
357+
358+
let sections = getAllByRole('group');
359+
let items = within(sections[0]).getAllByRole('option');
360+
expect(items).toHaveLength(3);
361+
items = within(sections[1]).getAllByRole('option');
362+
expect(items).toHaveLength(3);
363+
364+
rerender(
365+
<ListBox aria-label="Test">
366+
<ListBoxSection id="veggies">
367+
<Header>Veggies</Header>
368+
<ListBoxItem key="lettuce" id="lettuce">Lettuce</ListBoxItem>
369+
<ListBoxItem key="tomato" id="tomato">Tomato</ListBoxItem>
370+
<ListBoxItem key="onion" id="onion">Onion</ListBoxItem>
371+
<ListBoxItem key="ham" id="ham">Ham</ListBoxItem>
372+
</ListBoxSection>
373+
<ListBoxSection id="meats">
374+
<Header>Meats</Header>
375+
<ListBoxItem key="tuna" id="tuna">Tuna</ListBoxItem>
376+
<ListBoxItem key="tofu" id="tofu">Tofu</ListBoxItem>
377+
</ListBoxSection>
378+
</ListBox>
379+
);
380+
381+
sections = getAllByRole('group');
382+
items = within(sections[0]).getAllByRole('option');
383+
expect(items).toHaveLength(4);
384+
items = within(sections[1]).getAllByRole('option');
385+
expect(items).toHaveLength(2);
386+
});
387+
340388
it('should support autoFocus', () => {
341389
let {getByRole} = renderListbox({autoFocus: true});
342390
let listbox = getByRole('listbox');

0 commit comments

Comments
 (0)