@@ -64,147 +64,138 @@ The state object should be passed as an option to `useAutocomplete`.
6464
6565## Example
6666
67- ``` tsx example export=true
68- import {Item } from ' @react-stately/collections' ;
69- import {useButton } from ' @react-aria/button' ;
70- import {useAutocompleteState } from ' @react-stately/autocomplete'
71- import {useAutocomplete } from ' @react-aria/autocomplete' ;
72- import {useFilter } from ' @react-aria/i18n' ;
73- import {UNSTABLE_useFilteredListState } from ' @react-stately/list' ;
74-
75- // Reuse the ListBox, Popover, and Button from your component library. See below for details.
76- import {ListBox } from ' your-component-library' ;
77-
78- function Autocomplete(props ) {
79- // Setup filter function and state.
80- let {contains} = useFilter ({sensitivity: ' base' });
81- let state = useAutocompleteState (props );
67+ ``` tsx example
68+ import {AriaAutocompleteProps , CollectionOptions , useAutocomplete } from ' @react-aria/autocomplete' ;
69+ import {AutocompleteState , useAutocompleteState } from ' @react-stately/autocomplete' ;
70+ import {mergeProps } from ' @react-aria/utils' ;
71+ import React , {createContext , RefObject , useRef } from ' react' ;
72+ import {
73+ Label ,
74+ Text ,
75+ InputContext ,
76+ Input ,
77+ Provider ,
78+ SlotProps ,
79+ SlottedContextValue ,
80+ useSlottedContext ,
81+ SearchFieldContext ,
82+ SearchField ,
83+ ListBox ,
84+ ListBoxItem ,
85+ useFilter ,
86+ UNSTABLE_InternalAutocompleteContext
87+ } from ' react-aria-components'
88+
89+ interface AutocompleteProps extends AriaAutocompleteProps , SlotProps {}
90+
91+ interface InternalAutocompleteContextValue {
92+ filter? : (nodeTextValue : string ) => boolean ,
93+ collectionProps: CollectionOptions ,
94+ collectionRef: RefObject <HTMLElement | null >
95+ }
8296
83- // Setup refs and get props for child elements.
84- let ref = React .useRef (null );
85- let inputRef = React .useRef (null );
86-
87- let {textFieldProps, collectionProps, collectionRef, filter} = useAutocomplete (
88- {
89- ... props ,
90- inputRef ,
91- collectionRef: ref ,
92- filter: contains ,
93- },
94- state
95- );
97+ const AutocompleteContext = createContext <SlottedContextValue <Partial <AutocompleteProps >>>(null );
98+ const AutocompleteStateContext = createContext <AutocompleteState | null >(null );
99+
100+ function Autocomplete(props : AutocompleteProps ) {
101+ let {contains} = useFilter ({ sensitivity: ' base' });
102+ let filter = (textValue , inputValue ) => contains (textValue , inputValue );
103+ let ctx = useSlottedContext (AutocompleteContext , props .slot );
104+ props = mergeProps (ctx , props );
105+ let {disableAutoFocusFirst} = props ;
106+ let state = useAutocompleteState (props );
107+ let inputRef = useRef <HTMLInputElement | null >(null );
108+ let collectionRef = useRef <HTMLElement >(null );
109+ let {
110+ textFieldProps,
111+ collectionProps,
112+ collectionRef : mergedCollectionRef,
113+ filter : filterFn
114+ } = useAutocomplete ({
115+ ... props ,
116+ filter ,
117+ disableAutoFocusFirst ,
118+ inputRef ,
119+ collectionRef
120+ }, state );
96121
97122 return (
98- <div style = { {display: ' inline-flex' , flexDirection: ' column' }} >
99- <label >{ props .label } </label >
100- <div >
101- <input
102- { ... textFieldProps }
103- ref = { inputRef }
104- style = { {
105- height: 24 ,
106- boxSizing: ' border-box' ,
107- marginRight: 0 ,
108- fontSize: 16
109- }} />
110- <ListBox
111- { ... collectionProps }
112- filter = { filter }
113- listBoxRef = { collectionRef }
114- state = { state } >
115- { props .children }
116- </ListBox >
117- </div >
118- </div >
123+ <Provider
124+ values = { [
125+ [AutocompleteStateContext , state ],
126+ [SearchFieldContext , textFieldProps ],
127+ [InputContext , {ref: inputRef }],
128+ [UNSTABLE_InternalAutocompleteContext , {
129+ filter: filterFn ,
130+ collectionProps ,
131+ collectionRef: mergedCollectionRef
132+ }]
133+ ]} >
134+ { props .children }
135+ </Provider >
119136 );
120- }
121-
122- <Autocomplete label = " Favorite Animal" >
123- <Item key = " red panda" >Red Panda</Item >
124- <Item key = " cat" >Cat</Item >
125- <Item key = " dog" >Dog</Item >
126- <Item key = " aardvark" >Aardvark</Item >
127- <Item key = " kangaroo" >Kangaroo</Item >
128- <Item key = " snake" >Snake</Item >
129- </Autocomplete >
137+ };
138+
139+ <div className = " autocomplete" >
140+ <Autocomplete >
141+ <SearchField >
142+ <Label >Favorite animal</Label >
143+ <Input />
144+ <Text slot = " description" >Please select a pet below.</Text >
145+ </SearchField >
146+ <ListBox selectionMode = " single" aria-label = " Possible pets" >
147+ <ListBoxItem id = " red panda" >Red Panda</ListBoxItem >
148+ <ListBoxItem id = " cat" >Cat</ListBoxItem >
149+ <ListBoxItem id = " dog" >Dog</ListBoxItem >
150+ <ListBoxItem id = " aardvark" >Aardvark</ListBoxItem >
151+ <ListBoxItem id = " kangaroo" >Kangaroo</ListBoxItem >
152+ <ListBoxItem id = " snake" >Snake</ListBoxItem >
153+ </ListBox >
154+ </Autocomplete >
155+ </div >
130156```
131157
132-
133- ### ListBox
134-
135- The ` ListBox ` and ` Option ` components are used to show the filtered list of options as the
136- user types in the ComboBox. They can also be shared with other components like a [ Select] ( useSelect.html ) . See
137- [ useListBox] ( useListBox.html ) for more examples, including sections and more complex items.
138-
139158<details >
140- <summary style = { {fontWeight: ' bold' }} ><ChevronRight size = " S" /> Show code</summary >
141-
142- ``` tsx example export=true render=false
143- import {useListBox , useOption } from ' @react-aria/listbox' ;
144-
145- function ListBox(props ) {
146- let {listBoxRef, state} = props ;
147- let newState = UNSTABLE_useFilteredListState (state , props .filter );
148- let {listBoxProps} = useListBox (props , newState , listBoxRef );
159+ <summary style = { {fontWeight: ' bold' }} ><ChevronRight size = " S" /> Show CSS</summary >
160+ ``` css hidden
161+ @import ' ../../../react-aria-components/docs/Checkbox.mdx' layer(checkbox);
162+ @import ' ../../../react-aria-components/docs/SearchField.mdx' layer(searchfield);
163+ @import ' ../../../react-aria-components/docs/ListBox.mdx' layer(listbox);
164+ ```
149165
150- return (
151- <ul
152- { ... listBoxProps }
153- ref = { listBoxRef }
154- style = { {
155- margin: 0 ,
156- padding: 0 ,
157- listStyle: " none" ,
158- maxHeight: 150 ,
159- overflow: " auto" ,
160- minWidth: 200
161- }} >
162- { [... newState .collection ].map (item => (
163- <Option
164- key = { item .key }
165- item = { item }
166- state = { state } />
167- ))}
168- </ul >
169- );
170- }
166+ ``` css
167+ @import " @react-aria/example-theme" ;
168+
169+ .autocomplete {
170+ display : flex ;
171+ flex-direction : column ;
172+ gap : 12px ;
173+ max-width : 300px ;
174+ height : 180px ;
175+ border : 1px solid var (--border-color );
176+ padding : 16px ;
177+ border-radius : 10px ;
178+ background : var (--overlay-background );
179+
180+ .react-aria-SearchField {
181+ width : 100% ;
182+ }
171183
172- function Option({item , state }) {
173- let ref = React .useRef (null );
174- let {optionProps, isSelected, isFocused, isDisabled} = useOption ({key: item .key }, state , ref );
175-
176- let backgroundColor;
177- let color = ' black' ;
178-
179- if (isSelected ) {
180- backgroundColor = ' blueviolet' ;
181- color = ' white' ;
182- } else if (isFocused ) {
183- backgroundColor = ' gray' ;
184- } else if (isDisabled ) {
185- backgroundColor = ' transparent' ;
186- color = ' gray' ;
184+ .react-aria-ListBox {
185+ flex : 1 ;
186+ overflow : auto ;
187187 }
188188
189- return (
190- <li
191- { ... optionProps }
192- ref = { ref }
193- style = { {
194- background: backgroundColor ,
195- color: color ,
196- padding: ' 2px 5px' ,
197- outline: ' none' ,
198- cursor: ' pointer'
199- }} >
200- { item .rendered }
201- </li >
202- );
189+ .react-aria-Label {
190+ margin-bottom : .5em ;
191+ }
203192}
204193```
205194
206195</details >
207196
197+
198+
208199## Internationalization
209200
210201` useAutocomplete ` handles some aspects of internationalization automatically.
0 commit comments