jsx import { Fragment , ReactNode , useMemo } from 'react' ; import { jsx } from '@emotion/react' ; import A11yText from '../internal/A11yText' ; import { defaultAriaLiveMessages , AriaSelection } from '../accessibility' ; import { CommonProps , GroupBase , OnChangeValue , Options } from '../types' ; export interface LiveRegionProps < Option , IsMulti extends boolean , Group extends GroupBase < Option > > extends CommonProps < Option , IsMulti , Group > { children : ReactNode ; innerProps : { className ? : string ; } ; ariaSelection : AriaSelection < Option , IsMulti > ; focusedOption : Option | null ; focusedValue : Option | null ; selectValue : Options < Option > ; focusableOptions : Options < Option > ; isFocused : boolean ; id : string ; } const LiveRegion = < Option , IsMulti extends boolean , Group extends GroupBase < Option > > ( props ) => { const { ariaSelection , focusedOption , focusedValue , focusableOptions , isFocused , selectValue , selectProps , id , } = props ; const { ariaLiveMessages , getOptionLabel , inputValue , isMulti , isOptionDisabled , isSearchable , menuIsOpen , options , screenReaderStatus , tabSelectsValue , } = selectProps ; const ariaLabel = selectProps [ 'aria-label' ] ; const ariaLive = selectProps [ 'aria-live' ] ; const messages = useMemo ( ( ) => ( { ... defaultAriaLiveMessages , ... ( ariaLiveMessages || { } ) , } ) , [ ariaLiveMessages ] ) ; const ariaSelected = useMemo ( ( ) => { let message = '' ; if ( ariaSelection && messages . onChange ) { const { option , options : selectedOptions , removedValue , removedValues , value , } = ariaSelection ; const asOption = ( val ) : Option | null => ! Array . isArray ( val ) ? ( val as Option ) : null ; const selected = removedValue || option || asOption ( value ) ; const label = selected ? getOptionLabel ( selected ) : '' ; const multiSelected = selectedOptions || removedValues || undefined ; const labels = multiSelected ? multiSelected . map ( getOptionLabel ) : [ ] ; const onChangeProps = { isDisabled : selected && isOptionDisabled ( selected , selectValue ) , label , labels , ... ariaSelection , } ; message = messages . onChange ( onChangeProps ) ; } return message ; } , [ ariaSelection , messages , isOptionDisabled , selectValue , getOptionLabel ] ) ; const ariaFocused = useMemo ( ( ) => { let focusMsg = '' ; const focused = focusedOption || focusedValue ; const isSelected = ! ! ( focusedOption && selectValue && selectValue . includes ( focusedOption ) ) ; if ( focused && messages . onFocus ) { const onFocusProps = { focused , label : getOptionLabel ( focused ) , isDisabled : isOptionDisabled ( focused , selectValue ) , isSelected , options , context : focused === focusedOption ? ( 'menu' as const ) : ( 'value' as const ) , selectValue , } ; focusMsg = messages . onFocus ( onFocusProps ) ; } return focusMsg ; } , [ focusedOption , focusedValue , getOptionLabel , isOptionDisabled , messages , options , selectValue , ] ) ; const ariaResults = useMemo ( ( ) => { let resultsMsg = '' ; if ( menuIsOpen && options . length && messages . onFilter ) { const resultsMessage = screenReaderStatus ( { count : focusableOptions . length , } ) ; resultsMsg = messages . onFilter ( { inputValue , resultsMessage } ) ; } return resultsMsg ; } , [ focusableOptions , inputValue , menuIsOpen , messages , options , screenReaderStatus , ] ) ; const ariaGuidance = useMemo ( ( ) => { let guidanceMsg = '' ; if ( messages . guidance ) { const context = focusedValue ? 'value' : menuIsOpen ? 'menu' : 'input' ; guidanceMsg = messages . guidance ( { 'aria-label' : ariaLabel , context , isDisabled : focusedOption && isOptionDisabled ( focusedOption , selectValue ) , isMulti , isSearchable , tabSelectsValue , } ) ; } return guidanceMsg ; } , [ ariaLabel , focusedOption , focusedValue , isMulti , isOptionDisabled , isSearchable , menuIsOpen , messages , selectValue , tabSelectsValue , ] ) ; const ariaContext = `${ ariaFocused } ${ ariaResults } ${ ariaGuidance }` ; const ScreenReaderText = ( < Fragment > < span id = "aria-selection" > { ariaSelected } < /span> < span id = "aria-context" > { ariaContext } < /span> < /Fragment>); const isInitialFocus = ariaSelection ?. action === 'initial-input-focus' ; return ( < Fragment > { } { } < A11yText id = { id } > { isInitialFocus && ScreenReaderText } < /A11yText> < A11yText aria - live = { ariaLive } aria - atomic = "false" aria - relevant = "additions text" > { isFocused && ! isInitialFocus && ScreenReaderText } < /A11yText> < /Fragment>); } ; export default LiveRegion ;