Skip to content

fix: Clear Autocomplete virtualFocus upon paste/undo/redo and other focus fixes #8438

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 10 commits into from
Jul 8, 2025

Conversation

LFDanLu
Copy link
Member

@LFDanLu LFDanLu commented Jun 24, 2025

Closes RSP Component Milestones (view)

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

Go to the RAC autocomplete stories and try typing/backspacing/cut/paste/redo/undo operations. Only typing forward should autofocus the first item in the list, the rest should clear virtual focus. Sanity check announcements, most should not be interrupted since we clear virtual focus so you should be able to hear what you've just typed/pasted/etc

🧢 Your Project:

RSP

@rspbot
Copy link

rspbot commented Jun 24, 2025

@rspbot
Copy link

rspbot commented Jun 25, 2025

@@ -419,7 +418,11 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions

// If no focusable items exist in the list, make sure to clear any activedescendant that may still exist
if (keyToFocus == null) {
let previousActiveElement = getActiveElement();
// TODO: Bit gross, but we need the first moveVirtualFocus to clear the previous aria-activeDescendant, then
Copy link
Member

Choose a reason for hiding this comment

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

i don't quite follow, what's going on here? and what are the repercussions across other collections?

Copy link
Member Author

Choose a reason for hiding this comment

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

ah sorry, I'll add a more illustrative comment once I confirm this is the only way to do this. What this is handling is the case where the user types into the autocomplete input -> tells the filtered collection to try to virtually focus its first key -> the filtered collection filters itself and ends up in a state where there are no focusable items (aka only disabled items/no matching items at all) -> it needs to then tell the autocomplete input to clear its old aria-activeDescendant and that the input should be focused instead.

I was hoping to remove moveVirtualFocus(ref.current) in favor of the dispatchVirtualFocus below since it feels weird to do two separate virtual focus move operation but the autocomplete input will only clear its focused node when it detects that a focusin on the collection itself

This shouldn't have an repercussions for other standalone collections because it only runs when FOCUS_EVENT is fired from useAutocomplete

Copy link
Member

Choose a reason for hiding this comment

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

That's very helpful, thank you for explaining again <3

@LFDanLu LFDanLu changed the title fix: Clear Autocomplete virtualFocus upon paste/undo/redo fix: Clear Autocomplete virtualFocus upon paste/undo/redo and other focus fixes Jun 26, 2025
Copy link
Member Author

Choose a reason for hiding this comment

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

only has cut/paste, undo and redo didn't seem to fire properly

@rspbot
Copy link

rspbot commented Jun 26, 2025

Comment on lines +502 to +503
// If 500ms hasn't elapsed the aria-activedecendant hasn't been updated
act(() => jest.advanceTimersByTime(300));
Copy link
Member

Choose a reason for hiding this comment

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

500 v 300?

Copy link
Member Author

Choose a reason for hiding this comment

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

yep, if I advance more than 500ms, the aria-activedescendant will be set which is the typical flow tested by the other tests via runAllTimers. The buggy flow was if the user then backspaces before that 500ms finishes resulting in a state where the input "blurred" away from itself, but then interrupts updating the activedescendant, resulting in a state where getVirtuallyFocusedElement doesn't return a value and moveVirtualFocus will think that virtual focus didn't move away from the input.

@rspbot
Copy link

rspbot commented Jun 27, 2025

@LFDanLu LFDanLu added the release label Jul 7, 2025
@rspbot
Copy link

rspbot commented Jul 7, 2025

@rspbot
Copy link

rspbot commented Jul 7, 2025

## API Changes

react-aria-components

/react-aria-components:FileTrigger

 FileTrigger {
   acceptDirectory?: boolean
-  acceptedFileTypes?: ReadonlyArray<string>
+  acceptedFileTypes?: Array<string>
   allowsMultiple?: boolean
   children?: ReactNode
   defaultCamera?: 'user' | 'environment'
   onSelect?: (FileList | null) => void

/react-aria-components:FileTriggerProps

 FileTriggerProps {
   acceptDirectory?: boolean
-  acceptedFileTypes?: ReadonlyArray<string>
+  acceptedFileTypes?: Array<string>
   allowsMultiple?: boolean
   children?: ReactNode
   defaultCamera?: 'user' | 'environment'
   onSelect?: (FileList | null) => void

/react-aria-components:CheckboxGroupState

 CheckboxGroupState {
   addValue: (string) => void
   commitValidation: () => void
-  defaultValue: readonly Array<string>
   displayValidation: ValidationResult
   isDisabled: boolean
   isInvalid: boolean
   isReadOnly: boolean
   isSelected: (string) => boolean
   realtimeValidation: ValidationResult
   removeValue: (string) => void
   resetValidation: () => void
   setInvalid: (string, ValidationResult) => void
   setValue: (Array<string>) => void
   toggleValue: (string) => void
   updateValidation: (ValidationResult) => void
   value: readonly Array<string>
 }

/react-aria-components:ColorAreaState

 ColorAreaState {
   channels: {
     xChannel: ColorChannel
   yChannel: ColorChannel
   zChannel: ColorChannel
 }
   decrementX: (number) => void
   decrementY: (number) => void
-  defaultValue: Color
   getDisplayColor: () => Color
   getThumbPosition: () => {
     x: number
   y: number
   incrementX: (number) => void
   incrementY: (number) => void
   isDragging: boolean
   setColorFromPoint: (number, number) => void
   setDragging: (boolean) => void
   setValue: (string | Color) => void
   setXValue: (number) => void
   setYValue: (number) => void
   value: Color
   xChannelPageStep: number
   xChannelStep: number
   xValue: number
   yChannelPageStep: number
   yChannelStep: number
   yValue: number
 }

/react-aria-components:ColorFieldState

 ColorFieldState {
   colorValue: Color | null
   commit: () => void
   commitValidation: () => void
   decrement: () => void
   decrementToMin: () => void
-  defaultColorValue: Color | null
   displayValidation: ValidationResult
   increment: () => void
   incrementToMax: () => void
   inputValue: string
   realtimeValidation: ValidationResult
   resetValidation: () => void
-  setColorValue: (Color | null) => void
   setInputValue: (string) => void
   updateValidation: (ValidationResult) => void
   validate: (string) => boolean
 }

/react-aria-components:ColorSliderState

 ColorSliderState {
   decrementThumb: (number, number) => void
-  defaultValues: Array<number>
   focusedThumb: number | undefined
   getDisplayColor: () => Color
   getFormattedValue: (number) => string
   getPercentValue: (number) => number
   getThumbMinValue: (number) => number
   getThumbPercent: (number) => number
   getThumbValue: (number) => number
   getThumbValueLabel: (number) => string
   getValuePercent: (number) => number
   incrementThumb: (number, number) => void
   isDisabled: boolean
   isDragging: boolean
   isThumbDragging: (number) => boolean
   isThumbEditable: (number) => boolean
   orientation: Orientation
   pageSize: number
   setFocusedThumb: (number | undefined) => void
   setThumbDragging: (number, boolean) => void
   setThumbEditable: (number, boolean) => void
   setThumbPercent: (number, number) => void
   setThumbValue: (number, number) => void
   setValue: (string | Color) => void
   step: number
   value: Color
   values: Array<number>
 }

/react-aria-components:ColorWheelState

 ColorWheelState {
   decrement: (number) => void
-  defaultValue: Color
   getDisplayColor: () => Color
   getThumbPosition: (number) => {
     x: number
   y: number
   hue: number
   increment: (number) => void
   isDisabled: boolean
   isDragging: boolean
   pageStep: number
   setDragging: (boolean) => void
   setHue: (number) => void
   setHueFromPoint: (number, number, number) => void
   setValue: (string | Color) => void
   step: number
   value: Color
 }

/react-aria-components:ComboBoxState

 ComboBoxState <T> {
   close: () => void
   collection: Collection<Node<T>>
   commit: () => void
   commitValidation: () => void
-  defaultInputValue: string
-  defaultSelectedKey: Key | null
   disabledKeys: Set<Key>
   displayValidation: ValidationResult
   focusStrategy: FocusStrategy | null
   inputValue: string
   isOpen: boolean
   open: (FocusStrategy | null, MenuTriggerAction) => void
   realtimeValidation: ValidationResult
   resetValidation: () => void
   revert: () => void
   selectedItem: Node<T> | null
   selectedKey: Key | null
   selectionManager: SelectionManager
   setFocused: (boolean) => void
   setInputValue: (string) => void
   setOpen: (boolean) => void
   setSelectedKey: (Key | null) => void
   toggle: (FocusStrategy | null, MenuTriggerAction) => void
   updateValidation: (ValidationResult) => void
 }

/react-aria-components:DateFieldState

 DateFieldState {
   calendar: Calendar
   clearSegment: (SegmentType) => void
   commitValidation: () => void
   confirmPlaceholder: () => void
   dateFormatter: DateFormatter
   dateValue: Date
   decrement: (SegmentType) => void
   decrementPage: (SegmentType) => void
-  defaultValue: DateValue | null
   displayValidation: ValidationResult
   formatValue: (FieldOptions) => string
   getDateFormatter: (string, FormatterOptions) => DateFormatter
   granularity: Granularity
   incrementPage: (SegmentType) => void
   isDisabled: boolean
   isInvalid: boolean
   isReadOnly: boolean
   isRequired: boolean
   maxGranularity: 'year' | 'month' | Granularity
   realtimeValidation: ValidationResult
   resetValidation: () => void
   segments: Array<DateSegment>
   setSegment: (SegmentType, number) => void
   setValue: (DateValue | null) => void
   updateValidation: (ValidationResult) => void
   value: DateValue | null
 }

/react-aria-components:DatePickerState

 DatePickerState {
   close: () => void
   commitValidation: () => void
   dateValue: DateValue | null
-  defaultValue: DateValue | null
   displayValidation: ValidationResult
   formatValue: (string, FieldOptions) => string
   getDateFormatter: (string, FormatterOptions) => DateFormatter
   granularity: Granularity
   isInvalid: boolean
   isOpen: boolean
   open: () => void
   realtimeValidation: ValidationResult
   resetValidation: () => void
   setDateValue: (DateValue) => void
   setOpen: (boolean) => void
   setTimeValue: (TimeValue) => void
   setValue: (DateValue | null) => void
   timeValue: TimeValue | null
   toggle: () => void
   updateValidation: (ValidationResult) => void
   value: DateValue | null
 }

/react-aria-components:DateRangePickerState

 DateRangePickerState {
   close: () => void
   commitValidation: () => void
   dateRange: RangeValue<DateValue | null> | null
-  defaultValue: DateRange | null
   displayValidation: ValidationResult
   formatValue: (string, FieldOptions) => {
     start: string
   end: string
   getDateFormatter: (string, FormatterOptions) => DateFormatter
   granularity: Granularity
   hasTime: boolean
   isInvalid: boolean
   isOpen: boolean
   open: () => void
   realtimeValidation: ValidationResult
   resetValidation: () => void
   setDate: ('start' | 'end', DateValue | null) => void
   setDateRange: (DateRange) => void
   setDateTime: ('start' | 'end', DateValue | null) => void
   setOpen: (boolean) => void
   setTime: ('start' | 'end', TimeValue | null) => void
   setTimeRange: (TimeRange) => void
   setValue: (DateRange | null) => void
   timeRange: RangeValue<TimeValue | null> | null
   toggle: () => void
   updateValidation: (ValidationResult) => void
   value: RangeValue<DateValue | null>
 }

/react-aria-components:NumberFieldState

 NumberFieldState {
   canDecrement: boolean
   canIncrement: boolean
   commit: () => void
   commitValidation: () => void
   decrement: () => void
   decrementToMin: () => void
-  defaultNumberValue: number
   displayValidation: ValidationResult
   increment: () => void
   incrementToMax: () => void
   inputValue: string
   minValue?: number
   numberValue: number
   realtimeValidation: ValidationResult
   resetValidation: () => void
   setInputValue: (string) => void
   setNumberValue: (number) => void
   updateValidation: (ValidationResult) => void
   validate: (string) => boolean
 }

/react-aria-components:RadioGroupState

 RadioGroupState {
   commitValidation: () => void
-  defaultSelectedValue: string | null
   displayValidation: ValidationResult
   isDisabled: boolean
   isInvalid: boolean
   isReadOnly: boolean
   lastFocusedValue: string | null
   realtimeValidation: ValidationResult
   resetValidation: () => void
   selectedValue: string | null
   setLastFocusedValue: (string | null) => void
   setSelectedValue: (string | null) => void
   updateValidation: (ValidationResult) => void
 }

/react-aria-components:SelectState

 SelectState <T> {
   close: () => void
   collection: Collection<Node<T>>
   commitValidation: () => void
-  defaultSelectedKey: Key | null
   disabledKeys: Set<Key>
   displayValidation: ValidationResult
   focusStrategy: FocusStrategy | null
   isFocused: boolean
   open: (FocusStrategy | null) => void
   realtimeValidation: ValidationResult
   resetValidation: () => void
   selectedItem: Node<T> | null
   selectedKey: Key | null
   selectionManager: SelectionManager
   setFocused: (boolean) => void
   setOpen: (boolean) => void
   setSelectedKey: (Key | null) => void
   toggle: (FocusStrategy | null) => void
   updateValidation: (ValidationResult) => void
 }

/react-aria-components:SliderState

 SliderState {
   decrementThumb: (number, number) => void
-  defaultValues: Array<number>
   focusedThumb: number | undefined
   getFormattedValue: (number) => string
   getPercentValue: (number) => number
   getThumbMaxValue: (number) => number
   getThumbPercent: (number) => number
   getThumbValue: (number) => number
   getThumbValueLabel: (number) => string
   getValuePercent: (number) => number
   incrementThumb: (number, number) => void
   isDisabled: boolean
   isThumbDragging: (number) => boolean
   isThumbEditable: (number) => boolean
   orientation: Orientation
   pageSize: number
   setFocusedThumb: (number | undefined) => void
   setThumbDragging: (number, boolean) => void
   setThumbEditable: (number, boolean) => void
   setThumbPercent: (number, number) => void
   setThumbValue: (number, number) => void
   step: number
   values: Array<number>
 }

/react-aria-components:TimeFieldState

 TimeFieldState {
   calendar: Calendar
   clearSegment: (SegmentType) => void
   commitValidation: () => void
   confirmPlaceholder: () => void
   dateFormatter: DateFormatter
   dateValue: Date
   decrement: (SegmentType) => void
   decrementPage: (SegmentType) => void
-  defaultValue: DateValue | null
   displayValidation: ValidationResult
   formatValue: (FieldOptions) => string
   getDateFormatter: (string, FormatterOptions) => DateFormatter
   granularity: Granularity
   incrementPage: (SegmentType) => void
   isDisabled: boolean
   isInvalid: boolean
   isReadOnly: boolean
   isRequired: boolean
   maxGranularity: 'year' | 'month' | Granularity
   realtimeValidation: ValidationResult
   resetValidation: () => void
   segments: Array<DateSegment>
   setSegment: (SegmentType, number) => void
   setValue: (DateValue | null) => void
   timeValue: Time
   updateValidation: (ValidationResult) => void
   value: DateValue | null
 }

/react-aria-components:ToggleState

 ToggleState {
-  defaultSelected: boolean
   isSelected: boolean
   setSelected: (boolean) => void
   toggle: () => void
 }

@react-spectrum/filetrigger

/@react-spectrum/filetrigger:FileTrigger

 FileTrigger {
   acceptDirectory?: boolean
-  acceptedFileTypes?: ReadonlyArray<string>
+  acceptedFileTypes?: Array<string>
   allowsMultiple?: boolean
   children?: ReactNode
   defaultCamera?: 'user' | 'environment'
   onSelect?: (FileList | null) => void

/@react-spectrum/filetrigger:FileTriggerProps

 FileTriggerProps {
   acceptDirectory?: boolean
-  acceptedFileTypes?: ReadonlyArray<string>
+  acceptedFileTypes?: Array<string>
   allowsMultiple?: boolean
   children?: ReactNode
   defaultCamera?: 'user' | 'environment'
   onSelect?: (FileList | null) => void

@react-spectrum/s2

/@react-spectrum/s2:FileTrigger

 FileTrigger {
   acceptDirectory?: boolean
-  acceptedFileTypes?: ReadonlyArray<string>
+  acceptedFileTypes?: Array<string>
   allowsMultiple?: boolean
   children?: ReactNode
   defaultCamera?: 'user' | 'environment'
   onSelect?: (FileList | null) => void

/@react-spectrum/s2:FileTriggerProps

 FileTriggerProps {
   acceptDirectory?: boolean
-  acceptedFileTypes?: ReadonlyArray<string>
+  acceptedFileTypes?: Array<string>
   allowsMultiple?: boolean
   children?: ReactNode
   defaultCamera?: 'user' | 'environment'
   onSelect?: (FileList | null) => void

@react-stately/checkbox

/@react-stately/checkbox:CheckboxGroupState

 CheckboxGroupState {
   addValue: (string) => void
   commitValidation: () => void
-  defaultValue: readonly Array<string>
   displayValidation: ValidationResult
   isDisabled: boolean
   isInvalid: boolean
   isReadOnly: boolean
   isSelected: (string) => boolean
   realtimeValidation: ValidationResult
   removeValue: (string) => void
   resetValidation: () => void
   setInvalid: (string, ValidationResult) => void
   setValue: (Array<string>) => void
   toggleValue: (string) => void
   updateValidation: (ValidationResult) => void
   value: readonly Array<string>
 }

@react-stately/color

/@react-stately/color:ColorAreaState

 ColorAreaState {
   channels: {
     xChannel: ColorChannel
   yChannel: ColorChannel
   zChannel: ColorChannel
 }
   decrementX: (number) => void
   decrementY: (number) => void
-  defaultValue: Color
   getDisplayColor: () => Color
   getThumbPosition: () => {
     x: number
   y: number
   incrementX: (number) => void
   incrementY: (number) => void
   isDragging: boolean
   setColorFromPoint: (number, number) => void
   setDragging: (boolean) => void
   setValue: (string | Color) => void
   setXValue: (number) => void
   setYValue: (number) => void
   value: Color
   xChannelPageStep: number
   xChannelStep: number
   xValue: number
   yChannelPageStep: number
   yChannelStep: number
   yValue: number
 }

/@react-stately/color:ColorSliderState

 ColorSliderState {
   decrementThumb: (number, number) => void
-  defaultValues: Array<number>
   focusedThumb: number | undefined
   getDisplayColor: () => Color
   getFormattedValue: (number) => string
   getPercentValue: (number) => number
   getThumbMinValue: (number) => number
   getThumbPercent: (number) => number
   getThumbValue: (number) => number
   getThumbValueLabel: (number) => string
   getValuePercent: (number) => number
   incrementThumb: (number, number) => void
   isDisabled: boolean
   isDragging: boolean
   isThumbDragging: (number) => boolean
   isThumbEditable: (number) => boolean
   orientation: Orientation
   pageSize: number
   setFocusedThumb: (number | undefined) => void
   setThumbDragging: (number, boolean) => void
   setThumbEditable: (number, boolean) => void
   setThumbPercent: (number, number) => void
   setThumbValue: (number, number) => void
   setValue: (string | Color) => void
   step: number
   value: Color
   values: Array<number>
 }

/@react-stately/color:ColorWheelState

 ColorWheelState {
   decrement: (number) => void
-  defaultValue: Color
   getDisplayColor: () => Color
   getThumbPosition: (number) => {
     x: number
   y: number
   hue: number
   increment: (number) => void
   isDisabled: boolean
   isDragging: boolean
   pageStep: number
   setDragging: (boolean) => void
   setHue: (number) => void
   setHueFromPoint: (number, number, number) => void
   setValue: (string | Color) => void
   step: number
   value: Color
 }

/@react-stately/color:ColorFieldState

 ColorFieldState {
   colorValue: Color | null
   commit: () => void
   commitValidation: () => void
   decrement: () => void
   decrementToMin: () => void
-  defaultColorValue: Color | null
   displayValidation: ValidationResult
   increment: () => void
   incrementToMax: () => void
   inputValue: string
   realtimeValidation: ValidationResult
   resetValidation: () => void
-  setColorValue: (Color | null) => void
   setInputValue: (string) => void
   updateValidation: (ValidationResult) => void
   validate: (string) => boolean
 }

/@react-stately/color:ColorChannelFieldState

 ColorChannelFieldState {
   canDecrement: boolean
   canIncrement: boolean
   colorValue: Color
   commit: () => void
   commitValidation: () => void
   decrement: () => void
   decrementToMin: () => void
-  defaultColorValue: Color | null
-  defaultNumberValue: number
   displayValidation: ValidationResult
   increment: () => void
   incrementToMax: () => void
   inputValue: string
   maxValue?: number
   minValue?: number
   numberValue: number
   realtimeValidation: ValidationResult
   resetValidation: () => void
-  setColorValue: (Color | null) => void
   setInputValue: (string) => void
   setNumberValue: (number) => void
   updateValidation: (ValidationResult) => void
   validate: (string) => boolean

@react-stately/combobox

/@react-stately/combobox:ComboBoxState

 ComboBoxState <T> {
   close: () => void
   collection: Collection<Node<T>>
   commit: () => void
   commitValidation: () => void
-  defaultInputValue: string
-  defaultSelectedKey: Key | null
   disabledKeys: Set<Key>
   displayValidation: ValidationResult
   focusStrategy: FocusStrategy | null
   inputValue: string
   isOpen: boolean
   open: (FocusStrategy | null, MenuTriggerAction) => void
   realtimeValidation: ValidationResult
   resetValidation: () => void
   revert: () => void
   selectedItem: Node<T> | null
   selectedKey: Key | null
   selectionManager: SelectionManager
   setFocused: (boolean) => void
   setInputValue: (string) => void
   setOpen: (boolean) => void
   setSelectedKey: (Key | null) => void
   toggle: (FocusStrategy | null, MenuTriggerAction) => void
   updateValidation: (ValidationResult) => void
 }

@react-stately/datepicker

/@react-stately/datepicker:DateFieldState

 DateFieldState {
   calendar: Calendar
   clearSegment: (SegmentType) => void
   commitValidation: () => void
   confirmPlaceholder: () => void
   dateFormatter: DateFormatter
   dateValue: Date
   decrement: (SegmentType) => void
   decrementPage: (SegmentType) => void
-  defaultValue: DateValue | null
   displayValidation: ValidationResult
   formatValue: (FieldOptions) => string
   getDateFormatter: (string, FormatterOptions) => DateFormatter
   granularity: Granularity
   incrementPage: (SegmentType) => void
   isDisabled: boolean
   isInvalid: boolean
   isReadOnly: boolean
   isRequired: boolean
   maxGranularity: 'year' | 'month' | Granularity
   realtimeValidation: ValidationResult
   resetValidation: () => void
   segments: Array<DateSegment>
   setSegment: (SegmentType, number) => void
   setValue: (DateValue | null) => void
   updateValidation: (ValidationResult) => void
   value: DateValue | null
 }

/@react-stately/datepicker:DatePickerState

 DatePickerState {
   close: () => void
   commitValidation: () => void
   dateValue: DateValue | null
-  defaultValue: DateValue | null
   displayValidation: ValidationResult
   formatValue: (string, FieldOptions) => string
   getDateFormatter: (string, FormatterOptions) => DateFormatter
   granularity: Granularity
   isInvalid: boolean
   isOpen: boolean
   open: () => void
   realtimeValidation: ValidationResult
   resetValidation: () => void
   setDateValue: (DateValue) => void
   setOpen: (boolean) => void
   setTimeValue: (TimeValue) => void
   setValue: (DateValue | null) => void
   timeValue: TimeValue | null
   toggle: () => void
   updateValidation: (ValidationResult) => void
   value: DateValue | null
 }

/@react-stately/datepicker:DateRangePickerState

 DateRangePickerState {
   close: () => void
   commitValidation: () => void
   dateRange: RangeValue<DateValue | null> | null
-  defaultValue: DateRange | null
   displayValidation: ValidationResult
   formatValue: (string, FieldOptions) => {
     start: string
   end: string
   getDateFormatter: (string, FormatterOptions) => DateFormatter
   granularity: Granularity
   hasTime: boolean
   isInvalid: boolean
   isOpen: boolean
   open: () => void
   realtimeValidation: ValidationResult
   resetValidation: () => void
   setDate: ('start' | 'end', DateValue | null) => void
   setDateRange: (DateRange) => void
   setDateTime: ('start' | 'end', DateValue | null) => void
   setOpen: (boolean) => void
   setTime: ('start' | 'end', TimeValue | null) => void
   setTimeRange: (TimeRange) => void
   setValue: (DateRange | null) => void
   timeRange: RangeValue<TimeValue | null> | null
   toggle: () => void
   updateValidation: (ValidationResult) => void
   value: RangeValue<DateValue | null>
 }

/@react-stately/datepicker:TimeFieldState

 TimeFieldState {
   calendar: Calendar
   clearSegment: (SegmentType) => void
   commitValidation: () => void
   confirmPlaceholder: () => void
   dateFormatter: DateFormatter
   dateValue: Date
   decrement: (SegmentType) => void
   decrementPage: (SegmentType) => void
-  defaultValue: DateValue | null
   displayValidation: ValidationResult
   formatValue: (FieldOptions) => string
   getDateFormatter: (string, FormatterOptions) => DateFormatter
   granularity: Granularity
   incrementPage: (SegmentType) => void
   isDisabled: boolean
   isInvalid: boolean
   isReadOnly: boolean
   isRequired: boolean
   maxGranularity: 'year' | 'month' | Granularity
   realtimeValidation: ValidationResult
   resetValidation: () => void
   segments: Array<DateSegment>
   setSegment: (SegmentType, number) => void
   setValue: (DateValue | null) => void
   timeValue: Time
   updateValidation: (ValidationResult) => void
   value: DateValue | null
 }

@react-stately/numberfield

/@react-stately/numberfield:NumberFieldState

 NumberFieldState {
   canDecrement: boolean
   canIncrement: boolean
   commit: () => void
   commitValidation: () => void
   decrement: () => void
   decrementToMin: () => void
-  defaultNumberValue: number
   displayValidation: ValidationResult
   increment: () => void
   incrementToMax: () => void
   inputValue: string
   minValue?: number
   numberValue: number
   realtimeValidation: ValidationResult
   resetValidation: () => void
   setInputValue: (string) => void
   setNumberValue: (number) => void
   updateValidation: (ValidationResult) => void
   validate: (string) => boolean
 }

@react-stately/radio

/@react-stately/radio:RadioGroupState

 RadioGroupState {
   commitValidation: () => void
-  defaultSelectedValue: string | null
   displayValidation: ValidationResult
   isDisabled: boolean
   isInvalid: boolean
   isReadOnly: boolean
   lastFocusedValue: string | null
   realtimeValidation: ValidationResult
   resetValidation: () => void
   selectedValue: string | null
   setLastFocusedValue: (string | null) => void
   setSelectedValue: (string | null) => void
   updateValidation: (ValidationResult) => void
 }

@react-stately/select

/@react-stately/select:SelectState

 SelectState <T> {
   close: () => void
   collection: Collection<Node<T>>
   commitValidation: () => void
-  defaultSelectedKey: Key | null
   disabledKeys: Set<Key>
   displayValidation: ValidationResult
   focusStrategy: FocusStrategy | null
   isFocused: boolean
   open: (FocusStrategy | null) => void
   realtimeValidation: ValidationResult
   resetValidation: () => void
   selectedItem: Node<T> | null
   selectedKey: Key | null
   selectionManager: SelectionManager
   setFocused: (boolean) => void
   setOpen: (boolean) => void
   setSelectedKey: (Key | null) => void
   toggle: (FocusStrategy | null) => void
   updateValidation: (ValidationResult) => void
 }

@react-stately/slider

/@react-stately/slider:SliderState

 SliderState {
   decrementThumb: (number, number) => void
-  defaultValues: Array<number>
   focusedThumb: number | undefined
   getFormattedValue: (number) => string
   getPercentValue: (number) => number
   getThumbMaxValue: (number) => number
   getThumbPercent: (number) => number
   getThumbValue: (number) => number
   getThumbValueLabel: (number) => string
   getValuePercent: (number) => number
   incrementThumb: (number, number) => void
   isDisabled: boolean
   isThumbDragging: (number) => boolean
   isThumbEditable: (number) => boolean
   orientation: Orientation
   pageSize: number
   setFocusedThumb: (number | undefined) => void
   setThumbDragging: (number, boolean) => void
   setThumbEditable: (number, boolean) => void
   setThumbPercent: (number, number) => void
   setThumbValue: (number, number) => void
   step: number
   values: Array<number>
 }

@react-stately/toggle

/@react-stately/toggle:ToggleState

 ToggleState {
-  defaultSelected: boolean
   isSelected: boolean
   setSelected: (boolean) => void
   toggle: () => void
 }

@LFDanLu LFDanLu added this pull request to the merge queue Jul 8, 2025
Merged via the queue into main with commit e8dcc2b Jul 8, 2025
31 checks passed
@LFDanLu LFDanLu deleted the autocomplete_virtual_focus_improvements branch July 8, 2025 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants