Skip to content

feat: Add async spinner to PromptField autocomplete, virtualized menu and other fixes - #10614

Open
LFDanLu wants to merge 9 commits into
mainfrom
async_load_more_promptfield
Open

LFDanLu wants to merge 9 commits into
mainfrom
async_load_more_promptfield

Conversation

@LFDanLu

@LFDanLu LFDanLu commented Sep 18, 2026

Copy link
Copy Markdown
Member

from gaps found when using it in Coworker

  • adds async spinner to PromptField autocomplete on initial load, subsequent loads via typing is the same "paused rendering until new items come in" behavior
  • onExpandedChange for ExecutionTraceItems
  • move user provided onKeydown up above token field so keydown events don't bubble up and trigger that callback if the user is interacting with the autocomplete dropdown
  • virtualized menu support in S2 Menu, done for renderCompletions menu in PromptField
  • support for "steering' in PromptField via showing the submit button when generating + text is in the field

✅ 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
  • I understand every change in this PR and can explain why it's there.
  • If AI-assisted, I followed our AI contribution guidance and pointed my assistant at CLAUDE.md.

📝 Test Instructions:

  1. Test the async completions story in PromptField storybook, see that a spinner shows up when you type "/" or "@"
  2. Test virtualized S2 menu docs/story
  3. Test the steering behavior via PromptField stories using isGenerating/isReadOnlyWhileGenerating controls
  4. other stuff covered by tests but feel ree to test

🧢 Your Project:

RSP

@rspbot

rspbot commented Sep 19, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Sep 19, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Sep 21, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Sep 21, 2026

Copy link
Copy Markdown

@LFDanLu LFDanLu changed the title feat: (WIP) Add async spinner to PromptField autocomplete and other fixes feat: Add async spinner to PromptField autocomplete, virtualized menu and other fixes Sep 21, 2026
@rspbot

rspbot commented Sep 21, 2026

Copy link
Copy Markdown

@rspbot

rspbot commented Sep 21, 2026

Copy link
Copy Markdown
## API Changes

@react-spectrum/ai

/@react-spectrum/ai:PromptField

 PromptField {
   acceptedAttachmentTypes?: Array<string>
   aiDisclaimer?: React.ReactNode
   attachments?: Array<PromptFieldAttachment>
   brandColor?: string
   children: React.ReactNode
   defaultAttachments?: Array<PromptFieldAttachment>
   defaultValue?: PromptFieldValue
   isGenerating?: boolean
+  isReadOnlyWhileGenerating?: boolean = false
   onAITermsPress?: () => void
   onAddAttachments?: (Array<PromptFieldAttachment>) => void
   onAttachmentsChange?: (Array<PromptFieldAttachment>) => void
   onChange?: (PromptFieldValue) => void
   onStop?: () => void
   onSubmit?: (PromptFieldValue, Array<PromptFieldAttachment>) => void
   size?: 'S' | 'M' = 'M'
   styles?: StyleString
   value?: PromptFieldValue
   variant?: 'balanced' | 'prominent' | 'subtle' = 'balanced'
 }

/@react-spectrum/ai:ExecutionTraceItem

 ExecutionTraceItem {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   children: string
   detail?: ReactNode
   detailMaxHeight?: number = 120
   icon?: ReactNode
   id?: string
+  onExpandedChange?: (boolean) => void
   status?: 'pending' | 'failed' | 'success'
   styles?: StyleString
 }

/@react-spectrum/ai:PromptFieldProps

 PromptFieldProps {
   acceptedAttachmentTypes?: Array<string>
   aiDisclaimer?: React.ReactNode
   attachments?: Array<PromptFieldAttachment>
   brandColor?: string
   children: React.ReactNode
   defaultAttachments?: Array<PromptFieldAttachment>
   defaultValue?: PromptFieldValue
   isGenerating?: boolean
+  isReadOnlyWhileGenerating?: boolean = false
   onAITermsPress?: () => void
   onAddAttachments?: (Array<PromptFieldAttachment>) => void
   onAttachmentsChange?: (Array<PromptFieldAttachment>) => void
   onChange?: (PromptFieldValue) => void
   onStop?: () => void
   onSubmit?: (PromptFieldValue, Array<PromptFieldAttachment>) => void
   size?: 'S' | 'M' = 'M'
   styles?: StyleString
   value?: PromptFieldValue
   variant?: 'balanced' | 'prominent' | 'subtle' = 'balanced'
 }

/@react-spectrum/ai:ExecutionTraceItemProps

 ExecutionTraceItemProps {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   children: string
   detail?: ReactNode
   detailMaxHeight?: number = 120
   icon?: ReactNode
   id?: string
+  onExpandedChange?: (boolean) => void
   status?: 'pending' | 'failed' | 'success'
   styles?: StyleString
 }

@react-spectrum/s2

/@react-spectrum/s2:Menu

 Menu <T> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean | FocusStrategy
   children: ReactNode | (T) => ReactNode
   defaultSelectedKeys?: 'all' | Iterable<Key>
   dependencies?: ReadonlyArray<any>
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
   hideLinkOutIcon?: boolean
   id?: string
+  isVirtualized?: boolean = false
   items?: Iterable<T>
   loadingState?: LoadingState
   onAction?: (Key, T) => void
   onClose?: () => void
   onSelectionChange?: (Selection) => void
   selectedKeys?: 'all' | Iterable<Key>
   selectionMode?: SelectionMode
   shouldCloseOnSelect?: boolean
   shouldFocusWrap?: boolean
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   styles?: StylesProp
 }

/@react-spectrum/s2:MenuProps

 MenuProps <T> {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   autoFocus?: boolean | FocusStrategy
   children: ReactNode | (T) => ReactNode
   defaultSelectedKeys?: 'all' | Iterable<Key>
   dependencies?: ReadonlyArray<any>
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
   hideLinkOutIcon?: boolean
   id?: string
+  isVirtualized?: boolean = false
   items?: Iterable<T>
   loadingState?: LoadingState
   onAction?: (Key, T) => void
   onClose?: () => void
   onSelectionChange?: (Selection) => void
   selectedKeys?: 'all' | Iterable<Key>
   selectionMode?: SelectionMode
   shouldCloseOnSelect?: boolean
   shouldFocusWrap?: boolean
   size?: 'S' | 'M' | 'L' | 'XL' = 'M'
   slot?: string | null
   styles?: StylesProp
 }

@rspbot

rspbot commented Sep 21, 2026

Copy link
Copy Markdown

Agent Skills Changes

Modified (10)
Install

React Spectrum S2:

npx skills add https://d1pzu54gtk2aed.cloudfront.net/pr/d36c3a252727492e8bce34c7af37799709a81ab8/

React Aria:

npx skills add https://d5iwopk28bdhl.cloudfront.net/pr/d36c3a252727492e8bce34c7af37799709a81ab8/

@LFDanLu
LFDanLu marked this pull request as ready for review September 21, 2026 23:06
*
* @default false
*/
isReadOnlyWhileGenerating?: boolean;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this prop name sucks but I didn't want to call it "supportsSteering" or anything too specific. Not sure a better/shorter name tho

new TokenFieldValue.SelectedRange(
{index: lastPlaceholder, offset: 0},
{index: lastPlaceholder, offset: 1}
<div role="presentation" onKeyDown={onKeyDownProp}>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

looks big, but this change is just a wrapping div

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

just a fyi, many of the style changes/updates in here are basically taken from Picker/Combobox.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants