@@ -17,7 +17,7 @@ import { FocusScope, Key, useKeyboard } from 'react-aria';
1717import { Section as BaseSection , Item , ListState } from 'react-stately' ;
1818
1919import { useWarn } from '../../../_internal/hooks/use-warn' ;
20- import { DirectionIcon } from '../../../icons' ;
20+ import { DirectionIcon , LoadingIcon } from '../../../icons' ;
2121import { useProviderProps } from '../../../provider' ;
2222import {
2323 BASE_STYLES ,
@@ -238,6 +238,21 @@ export const FilterPicker = forwardRef(function FilterPicker<T extends object>(
238238 const cachedItemsOrder = useRef < T [ ] | null > ( null ) ;
239239 const triggerRef = useRef < HTMLButtonElement > ( null ) ;
240240
241+ // ---------------------------------------------------------------------------
242+ // Invalidate cached sorting whenever the available options change.
243+ // This ensures newly provided options are displayed and properly sorted on
244+ // the next popover open instead of re-using a stale order from a previous
245+ // session (which caused only the previously selected options to be rendered
246+ // or the list to appear unsorted).
247+ // ---------------------------------------------------------------------------
248+ useEffect ( ( ) => {
249+ cachedChildrenOrder . current = null ;
250+ } , [ children ] ) ;
251+
252+ useEffect ( ( ) => {
253+ cachedItemsOrder . current = null ;
254+ } , [ items ] ) ;
255+
241256 const isControlledSingle = selectedKey !== undefined ;
242257 const isControlledMultiple = selectedKeys !== undefined ;
243258
@@ -252,12 +267,20 @@ export const FilterPicker = forwardRef(function FilterPicker<T extends object>(
252267 // can compare them with user-provided keys.
253268 const normalizeKeyValue = ( key : Key ) : string => {
254269 if ( key == null ) return '' ;
255- const str = String ( key ) ;
256- return str . startsWith ( '.$' )
257- ? str . slice ( 2 )
258- : str . startsWith ( '.' )
259- ? str . slice ( 1 )
260- : str ;
270+ // React escapes "=" as "=0" and ":" as "=2" when it stores keys internally.
271+ // We strip the possible React prefixes first and then un-escape those sequences
272+ // so that callers work with the original key values supplied by the user.
273+ let str = String ( key ) ;
274+
275+ // Remove React array/object key prefixes (".$" or ".") if present.
276+ if ( str . startsWith ( '.$' ) ) {
277+ str = str . slice ( 2 ) ;
278+ } else if ( str . startsWith ( '.' ) ) {
279+ str = str . slice ( 1 ) ;
280+ }
281+
282+ // Un-escape React's internal key encodings.
283+ return str . replace ( / = 2 / g, ':' ) . replace ( / = 0 / g, '=' ) ;
261284 } ;
262285
263286 // ---------------------------------------------------------------------------
@@ -867,16 +890,17 @@ export const FilterPicker = forwardRef(function FilterPicker<T extends object>(
867890 type = { type }
868891 theme = { validationState === 'invalid' ? 'danger' : theme }
869892 size = { size }
870- isDisabled = { isDisabled }
871- isLoading = { isLoading }
893+ isDisabled = { isDisabled || isLoading }
872894 mods = { {
873895 placeholder : ! hasSelection ,
874896 selected : hasSelection ,
875897 ...externalMods ,
876898 } }
877899 icon = { icon }
878900 rightIcon = {
879- rightIcon !== undefined ? (
901+ isLoading ? (
902+ < LoadingIcon />
903+ ) : rightIcon !== undefined ? (
880904 rightIcon
881905 ) : (
882906 < DirectionIcon to = { state . isOpen ? 'top' : 'bottom' } />
@@ -927,6 +951,7 @@ export const FilterPicker = forwardRef(function FilterPicker<T extends object>(
927951 selectionMode = { selectionMode }
928952 validationState = { validationState }
929953 isDisabled = { isDisabled }
954+ isLoading = { isLoading }
930955 stateRef = { listStateRef }
931956 isCheckable = { isCheckable }
932957 mods = { {
0 commit comments