@@ -64,147 +64,138 @@ The state object should be passed as an option to `useAutocomplete`.
64
64
65
65
## Example
66
66
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
+ }
82
96
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 );
96
121
97
122
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 >
119
136
);
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 >
130
156
```
131
157
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
-
139
158
<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
+ ```
149
165
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
+ }
171
183
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 ;
187
187
}
188
188
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
+ }
203
192
}
204
193
```
205
194
206
195
</details >
207
196
197
+
198
+
208
199
## Internationalization
209
200
210
201
` useAutocomplete ` handles some aspects of internationalization automatically.
0 commit comments