From 4f83f4e92f1597f80f91aa01f992e9b24a71a634 Mon Sep 17 00:00:00 2001 From: XiaoYan Li Date: Wed, 28 Jan 2026 19:14:27 +0800 Subject: [PATCH 1/4] fix(RAC): use the correct approach to retrieve the items array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `collection.getKeys()` doesn’t guarantee the correct order. --- packages/@react-stately/list/src/useListState.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/@react-stately/list/src/useListState.ts b/packages/@react-stately/list/src/useListState.ts index c373633426e..6bd89b8311d 100644 --- a/packages/@react-stately/list/src/useListState.ts +++ b/packages/@react-stately/list/src/useListState.ts @@ -90,18 +90,8 @@ function useFocusedKeyReset(collection: Collection>, selectionManager useEffect(() => { if (selectionManager.focusedKey != null && !collection.getItem(selectionManager.focusedKey) && cachedCollection.current) { const startItem = cachedCollection.current.getItem(selectionManager.focusedKey); - const cachedItemNodes = [...cachedCollection.current.getKeys()].map( - key => { - const itemNode = cachedCollection.current!.getItem(key); - return itemNode?.type === 'item' ? itemNode : null; - } - ).filter(node => node !== null); - const itemNodes = [...collection.getKeys()].map( - key => { - const itemNode = collection.getItem(key); - return itemNode?.type === 'item' ? itemNode : null; - } - ).filter(node => node !== null); + const cachedItemNodes = Array.from(collection).filter(itemNode => itemNode.type === 'item'); + const itemNodes = Array.from(collection).filter(itemNode => itemNode.type === 'item'); const diff: number = (cachedItemNodes?.length ?? 0) - (itemNodes?.length ?? 0); let index = Math.min( ( From 07c6d721c4ad717618175bc0b989478a577ae68c Mon Sep 17 00:00:00 2001 From: XiaoYan Li Date: Thu, 29 Jan 2026 01:27:11 +0800 Subject: [PATCH 2/4] fix: add a story to reproduce the issue --- .../stories/TagGroup.stories.tsx | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/react-aria-components/stories/TagGroup.stories.tsx b/packages/react-aria-components/stories/TagGroup.stories.tsx index 7fe3a0159a2..8ff2888bef1 100644 --- a/packages/react-aria-components/stories/TagGroup.stories.tsx +++ b/packages/react-aria-components/stories/TagGroup.stories.tsx @@ -11,9 +11,9 @@ */ import {action} from '@storybook/addon-actions'; -import {Button, Label, OverlayArrow, Tag, TagGroup, TagGroupProps, TagList, TagProps, Tooltip, TooltipTrigger} from 'react-aria-components'; +import {Button, Label, OverlayArrow, Tag, TagGroup, TagGroupProps, TagList, TagProps, Tooltip, TooltipTrigger, useListData} from 'react-aria-components'; import {Meta, StoryObj} from '@storybook/react'; -import React from 'react'; +import React, {useRef} from 'react'; import './styles.css'; const meta: Meta = { @@ -120,3 +120,33 @@ export const EmptyTagGroup: Story = { ) }; + +export const RestoreFocusExample: Story = { + render: (props: TagGroupProps) => { + const list = useListData<{id: number, label: string}>({ + initialItems: [], + }); + + const nextIdRef = useRef(0); + + const insertItem = () => { + const id = nextIdRef.current++; + list.insert(0, { + id, + label: `Item ${id + 1}`, + }); + }; + + return ( +
+ list.remove(...keys)}> + + + 'No categories.'}> + {item => {item.label}} + + +
+ ); + }, +}; From 12f298aa1e87ee316121a1bbbfe508cb109aaaf6 Mon Sep 17 00:00:00 2001 From: XiaoYan Li Date: Thu, 29 Jan 2026 01:57:39 +0800 Subject: [PATCH 3/4] fix: lint errors --- .../stories/TagGroup.stories.tsx | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/packages/react-aria-components/stories/TagGroup.stories.tsx b/packages/react-aria-components/stories/TagGroup.stories.tsx index 8ff2888bef1..393bbb064b8 100644 --- a/packages/react-aria-components/stories/TagGroup.stories.tsx +++ b/packages/react-aria-components/stories/TagGroup.stories.tsx @@ -121,32 +121,36 @@ export const EmptyTagGroup: Story = { ) }; -export const RestoreFocusExample: Story = { - render: (props: TagGroupProps) => { - const list = useListData<{id: number, label: string}>({ - initialItems: [], - }); +const RestoreFocus = (props: TagGroupProps) => { + const list = useListData<{id: number, label: string}>({ + initialItems: [] + }); - const nextIdRef = useRef(0); + const nextIdRef = useRef(0); - const insertItem = () => { - const id = nextIdRef.current++; - list.insert(0, { - id, - label: `Item ${id + 1}`, - }); - }; + const insertItem = () => { + const id = nextIdRef.current++; + list.insert(0, { + id, + label: `Item ${id + 1}` + }); + }; - return ( -
- list.remove(...keys)}> - - - 'No categories.'}> - {item => {item.label}} - - -
- ); - }, + return ( +
+ list.remove(...keys)}> + + + 'No categories.'}> + {item => {item.label}} + + +
+ ); +}; + +export const RestoreFocusExample: Story = { + render: (props: TagGroupProps) => ( + + ) }; From 21900bd5bdd81cd9c33345c04257f5aa803db1d1 Mon Sep 17 00:00:00 2001 From: XiaoYan Li Date: Thu, 29 Jan 2026 02:30:58 +0800 Subject: [PATCH 4/4] fix: typo --- packages/@react-stately/list/src/useListState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@react-stately/list/src/useListState.ts b/packages/@react-stately/list/src/useListState.ts index 6bd89b8311d..22d4a497cbd 100644 --- a/packages/@react-stately/list/src/useListState.ts +++ b/packages/@react-stately/list/src/useListState.ts @@ -90,7 +90,7 @@ function useFocusedKeyReset(collection: Collection>, selectionManager useEffect(() => { if (selectionManager.focusedKey != null && !collection.getItem(selectionManager.focusedKey) && cachedCollection.current) { const startItem = cachedCollection.current.getItem(selectionManager.focusedKey); - const cachedItemNodes = Array.from(collection).filter(itemNode => itemNode.type === 'item'); + const cachedItemNodes = Array.from(cachedCollection.current).filter(itemNode => itemNode.type === 'item'); const itemNodes = Array.from(collection).filter(itemNode => itemNode.type === 'item'); const diff: number = (cachedItemNodes?.length ?? 0) - (itemNodes?.length ?? 0); let index = Math.min(