@react-spectrum/autocomplete 3.0.0-alpha.3 → 3.0.0-alpha.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/dist/ar-AE.main.js +9 -0
  2. package/dist/ar-AE.main.js.map +1 -0
  3. package/dist/ar-AE.mjs +11 -0
  4. package/dist/ar-AE.module.js +11 -0
  5. package/dist/ar-AE.module.js.map +1 -0
  6. package/dist/bg-BG.main.js +9 -0
  7. package/dist/bg-BG.main.js.map +1 -0
  8. package/dist/bg-BG.mjs +11 -0
  9. package/dist/bg-BG.module.js +11 -0
  10. package/dist/bg-BG.module.js.map +1 -0
  11. package/dist/cs-CZ.main.js +9 -0
  12. package/dist/cs-CZ.main.js.map +1 -0
  13. package/dist/cs-CZ.mjs +11 -0
  14. package/dist/cs-CZ.module.js +11 -0
  15. package/dist/cs-CZ.module.js.map +1 -0
  16. package/dist/da-DK.main.js +9 -0
  17. package/dist/da-DK.main.js.map +1 -0
  18. package/dist/da-DK.mjs +11 -0
  19. package/dist/da-DK.module.js +11 -0
  20. package/dist/da-DK.module.js.map +1 -0
  21. package/dist/de-DE.main.js +9 -0
  22. package/dist/de-DE.main.js.map +1 -0
  23. package/dist/de-DE.mjs +11 -0
  24. package/dist/de-DE.module.js +11 -0
  25. package/dist/de-DE.module.js.map +1 -0
  26. package/dist/el-GR.main.js +9 -0
  27. package/dist/el-GR.main.js.map +1 -0
  28. package/dist/el-GR.mjs +11 -0
  29. package/dist/el-GR.module.js +11 -0
  30. package/dist/el-GR.module.js.map +1 -0
  31. package/dist/en-US.main.js +9 -0
  32. package/dist/en-US.main.js.map +1 -0
  33. package/dist/en-US.mjs +11 -0
  34. package/dist/en-US.module.js +11 -0
  35. package/dist/en-US.module.js.map +1 -0
  36. package/dist/es-ES.main.js +9 -0
  37. package/dist/es-ES.main.js.map +1 -0
  38. package/dist/es-ES.mjs +11 -0
  39. package/dist/es-ES.module.js +11 -0
  40. package/dist/es-ES.module.js.map +1 -0
  41. package/dist/et-EE.main.js +9 -0
  42. package/dist/et-EE.main.js.map +1 -0
  43. package/dist/et-EE.mjs +11 -0
  44. package/dist/et-EE.module.js +11 -0
  45. package/dist/et-EE.module.js.map +1 -0
  46. package/dist/fi-FI.main.js +9 -0
  47. package/dist/fi-FI.main.js.map +1 -0
  48. package/dist/fi-FI.mjs +11 -0
  49. package/dist/fi-FI.module.js +11 -0
  50. package/dist/fi-FI.module.js.map +1 -0
  51. package/dist/fr-FR.main.js +9 -0
  52. package/dist/fr-FR.main.js.map +1 -0
  53. package/dist/fr-FR.mjs +11 -0
  54. package/dist/fr-FR.module.js +11 -0
  55. package/dist/fr-FR.module.js.map +1 -0
  56. package/dist/he-IL.main.js +9 -0
  57. package/dist/he-IL.main.js.map +1 -0
  58. package/dist/he-IL.mjs +11 -0
  59. package/dist/he-IL.module.js +11 -0
  60. package/dist/he-IL.module.js.map +1 -0
  61. package/dist/hr-HR.main.js +9 -0
  62. package/dist/hr-HR.main.js.map +1 -0
  63. package/dist/hr-HR.mjs +11 -0
  64. package/dist/hr-HR.module.js +11 -0
  65. package/dist/hr-HR.module.js.map +1 -0
  66. package/dist/hu-HU.main.js +9 -0
  67. package/dist/hu-HU.main.js.map +1 -0
  68. package/dist/hu-HU.mjs +11 -0
  69. package/dist/hu-HU.module.js +11 -0
  70. package/dist/hu-HU.module.js.map +1 -0
  71. package/dist/import.mjs +1044 -0
  72. package/dist/it-IT.main.js +9 -0
  73. package/dist/it-IT.main.js.map +1 -0
  74. package/dist/it-IT.mjs +11 -0
  75. package/dist/it-IT.module.js +11 -0
  76. package/dist/it-IT.module.js.map +1 -0
  77. package/dist/ja-JP.main.js +9 -0
  78. package/dist/ja-JP.main.js.map +1 -0
  79. package/dist/ja-JP.mjs +11 -0
  80. package/dist/ja-JP.module.js +11 -0
  81. package/dist/ja-JP.module.js.map +1 -0
  82. package/dist/ko-KR.main.js +9 -0
  83. package/dist/ko-KR.main.js.map +1 -0
  84. package/dist/ko-KR.mjs +11 -0
  85. package/dist/ko-KR.module.js +11 -0
  86. package/dist/ko-KR.module.js.map +1 -0
  87. package/dist/lt-LT.main.js +9 -0
  88. package/dist/lt-LT.main.js.map +1 -0
  89. package/dist/lt-LT.mjs +11 -0
  90. package/dist/lt-LT.module.js +11 -0
  91. package/dist/lt-LT.module.js.map +1 -0
  92. package/dist/lv-LV.main.js +9 -0
  93. package/dist/lv-LV.main.js.map +1 -0
  94. package/dist/lv-LV.mjs +11 -0
  95. package/dist/lv-LV.module.js +11 -0
  96. package/dist/lv-LV.module.js.map +1 -0
  97. package/dist/main.css +1700 -1
  98. package/dist/main.css.map +1 -0
  99. package/dist/main.js +716 -679
  100. package/dist/main.js.map +1 -1
  101. package/dist/module.js +715 -662
  102. package/dist/module.js.map +1 -1
  103. package/dist/nb-NO.main.js +9 -0
  104. package/dist/nb-NO.main.js.map +1 -0
  105. package/dist/nb-NO.mjs +11 -0
  106. package/dist/nb-NO.module.js +11 -0
  107. package/dist/nb-NO.module.js.map +1 -0
  108. package/dist/nl-NL.main.js +9 -0
  109. package/dist/nl-NL.main.js.map +1 -0
  110. package/dist/nl-NL.mjs +11 -0
  111. package/dist/nl-NL.module.js +11 -0
  112. package/dist/nl-NL.module.js.map +1 -0
  113. package/dist/pl-PL.main.js +9 -0
  114. package/dist/pl-PL.main.js.map +1 -0
  115. package/dist/pl-PL.mjs +11 -0
  116. package/dist/pl-PL.module.js +11 -0
  117. package/dist/pl-PL.module.js.map +1 -0
  118. package/dist/pt-BR.main.js +9 -0
  119. package/dist/pt-BR.main.js.map +1 -0
  120. package/dist/pt-BR.mjs +11 -0
  121. package/dist/pt-BR.module.js +11 -0
  122. package/dist/pt-BR.module.js.map +1 -0
  123. package/dist/pt-PT.main.js +9 -0
  124. package/dist/pt-PT.main.js.map +1 -0
  125. package/dist/pt-PT.mjs +11 -0
  126. package/dist/pt-PT.module.js +11 -0
  127. package/dist/pt-PT.module.js.map +1 -0
  128. package/dist/ro-RO.main.js +9 -0
  129. package/dist/ro-RO.main.js.map +1 -0
  130. package/dist/ro-RO.mjs +11 -0
  131. package/dist/ro-RO.module.js +11 -0
  132. package/dist/ro-RO.module.js.map +1 -0
  133. package/dist/ru-RU.main.js +9 -0
  134. package/dist/ru-RU.main.js.map +1 -0
  135. package/dist/ru-RU.mjs +11 -0
  136. package/dist/ru-RU.module.js +11 -0
  137. package/dist/ru-RU.module.js.map +1 -0
  138. package/dist/sk-SK.main.js +9 -0
  139. package/dist/sk-SK.main.js.map +1 -0
  140. package/dist/sk-SK.mjs +11 -0
  141. package/dist/sk-SK.module.js +11 -0
  142. package/dist/sk-SK.module.js.map +1 -0
  143. package/dist/sl-SI.main.js +9 -0
  144. package/dist/sl-SI.main.js.map +1 -0
  145. package/dist/sl-SI.mjs +11 -0
  146. package/dist/sl-SI.module.js +11 -0
  147. package/dist/sl-SI.module.js.map +1 -0
  148. package/dist/sr-SP.main.js +9 -0
  149. package/dist/sr-SP.main.js.map +1 -0
  150. package/dist/sr-SP.mjs +11 -0
  151. package/dist/sr-SP.module.js +11 -0
  152. package/dist/sr-SP.module.js.map +1 -0
  153. package/dist/sv-SE.main.js +9 -0
  154. package/dist/sv-SE.main.js.map +1 -0
  155. package/dist/sv-SE.mjs +11 -0
  156. package/dist/sv-SE.module.js +11 -0
  157. package/dist/sv-SE.module.js.map +1 -0
  158. package/dist/tr-TR.main.js +9 -0
  159. package/dist/tr-TR.main.js.map +1 -0
  160. package/dist/tr-TR.mjs +11 -0
  161. package/dist/tr-TR.module.js +11 -0
  162. package/dist/tr-TR.module.js.map +1 -0
  163. package/dist/types.d.ts +6 -2
  164. package/dist/types.d.ts.map +1 -1
  165. package/dist/uk-UA.main.js +9 -0
  166. package/dist/uk-UA.main.js.map +1 -0
  167. package/dist/uk-UA.mjs +11 -0
  168. package/dist/uk-UA.module.js +11 -0
  169. package/dist/uk-UA.module.js.map +1 -0
  170. package/dist/zh-CN.main.js +9 -0
  171. package/dist/zh-CN.main.js.map +1 -0
  172. package/dist/zh-CN.mjs +11 -0
  173. package/dist/zh-CN.module.js +11 -0
  174. package/dist/zh-CN.module.js.map +1 -0
  175. package/dist/zh-TW.main.js +9 -0
  176. package/dist/zh-TW.main.js.map +1 -0
  177. package/dist/zh-TW.mjs +11 -0
  178. package/dist/zh-TW.module.js +11 -0
  179. package/dist/zh-TW.module.js.map +1 -0
  180. package/package.json +34 -29
  181. package/src/MobileSearchAutocomplete.tsx +226 -141
  182. package/src/SearchAutocomplete.tsx +109 -71
  183. package/src/index.ts +2 -3
  184. package/src/searchautocomplete.css +11 -4
@@ -10,35 +10,49 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
  import {AriaButtonProps} from '@react-types/button';
13
- import {classNames, useFocusableRef, useIsMobileDevice, useResizeObserver, useUnwrapDOMRef} from '@react-spectrum/utils';
13
+ import {classNames, dimensionValue, useFocusableRef, useIsMobileDevice, useResizeObserver, useUnwrapDOMRef} from '@react-spectrum/utils';
14
14
  import {ClearButton} from '@react-spectrum/button';
15
- import {DismissButton, useOverlayPosition} from '@react-aria/overlays';
16
15
  import {DOMRefValue, FocusableRef} from '@react-types/shared';
17
16
  import {Field} from '@react-spectrum/label';
17
+ import {filterDOMProps, useLayoutEffect} from '@react-aria/utils';
18
18
  import {FocusRing} from '@react-aria/focus';
19
19
  // @ts-ignore
20
20
  import intlMessages from '../intl/*.json';
21
21
  import {ListBoxBase, useListBoxLayout} from '@react-spectrum/listbox';
22
22
  import Magnifier from '@spectrum-icons/ui/Magnifier';
23
23
  import {MobileSearchAutocomplete} from './MobileSearchAutocomplete';
24
- import {Placement} from '@react-types/overlays';
25
24
  import {Popover} from '@react-spectrum/overlays';
26
25
  import {ProgressCircle} from '@react-spectrum/progress';
27
- import React, {forwardRef, InputHTMLAttributes, RefObject, useCallback, useEffect, useRef, useState} from 'react';
26
+ import React, {
27
+ forwardRef,
28
+ InputHTMLAttributes,
29
+ ReactElement,
30
+ RefObject,
31
+ useCallback,
32
+ useEffect,
33
+ useRef,
34
+ useState
35
+ } from 'react';
36
+ import searchAutocompleteStyles from './searchautocomplete.css';
28
37
  import searchStyles from '@adobe/spectrum-css-temp/components/search/vars.css';
29
38
  import {SpectrumSearchAutocompleteProps} from '@react-types/autocomplete';
30
39
  import styles from '@adobe/spectrum-css-temp/components/inputgroup/vars.css';
31
40
  import {TextFieldBase} from '@react-spectrum/textfield';
32
41
  import textfieldStyles from '@adobe/spectrum-css-temp/components/textfield/vars.css';
33
42
  import {useComboBoxState} from '@react-stately/combobox';
34
- import {useFilter, useMessageFormatter} from '@react-aria/i18n';
43
+ import {useFilter, useLocalizedStringFormatter} from '@react-aria/i18n';
44
+ import {useFormProps} from '@react-spectrum/form';
35
45
  import {useHover} from '@react-aria/interactions';
36
- import {useLayoutEffect} from '@react-aria/utils';
37
46
  import {useProvider, useProviderProps} from '@react-spectrum/provider';
38
47
  import {useSearchAutocomplete} from '@react-aria/autocomplete';
39
48
 
40
49
  function SearchAutocomplete<T extends object>(props: SpectrumSearchAutocompleteProps<T>, ref: FocusableRef<HTMLElement>) {
41
50
  props = useProviderProps(props);
51
+ props = useFormProps(props);
52
+
53
+ if (props.placeholder) {
54
+ console.warn('Placeholders are deprecated due to accessibility issues. Please use help text instead.');
55
+ }
42
56
 
43
57
  let isMobile = useIsMobileDevice();
44
58
  if (isMobile) {
@@ -49,25 +63,28 @@ function SearchAutocomplete<T extends object>(props: SpectrumSearchAutocompleteP
49
63
  }
50
64
  }
51
65
 
52
- const SearchAutocompleteBase = React.forwardRef(function SearchAutocompleteBase<T extends object>(props: SpectrumSearchAutocompleteProps<T>, ref: FocusableRef<HTMLElement>) {
66
+ function _SearchAutocompleteBase<T extends object>(props: SpectrumSearchAutocompleteProps<T>, ref: FocusableRef<HTMLElement>) {
53
67
  props = useProviderProps(props);
54
68
 
55
69
  let {
56
70
  menuTrigger = 'input',
57
71
  shouldFlip = true,
58
72
  direction = 'bottom',
73
+ align = 'start',
59
74
  isQuiet,
75
+ menuWidth: customMenuWidth,
60
76
  loadingState,
61
77
  onLoadMore,
62
- onSubmit = () => {}
78
+ onSubmit = () => {},
79
+ validate
63
80
  } = props;
64
81
 
65
- let formatMessage = useMessageFormatter(intlMessages);
82
+ let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/autocomplete');
66
83
  let isAsync = loadingState != null;
67
- let popoverRef = useRef<DOMRefValue<HTMLDivElement>>();
84
+ let popoverRef = useRef<DOMRefValue<HTMLDivElement>>(null);
68
85
  let unwrappedPopoverRef = useUnwrapDOMRef(popoverRef);
69
- let listBoxRef = useRef();
70
- let inputRef = useRef<HTMLInputElement>();
86
+ let listBoxRef = useRef(null);
87
+ let inputRef = useRef<HTMLInputElement>(null);
71
88
  let domRef = useFocusableRef(ref, inputRef);
72
89
 
73
90
  let {contains} = useFilter({sensitivity: 'base'});
@@ -79,12 +96,13 @@ const SearchAutocompleteBase = React.forwardRef(function SearchAutocompleteBase<
79
96
  allowsCustomValue: true,
80
97
  onSelectionChange: (key) => key !== null && onSubmit(null, key),
81
98
  selectedKey: undefined,
82
- defaultSelectedKey: undefined
99
+ defaultSelectedKey: undefined,
100
+ validate: useCallback(v => validate?.(v.inputValue), [validate])
83
101
  }
84
102
  );
85
- let layout = useListBoxLayout(state);
86
-
87
- let {inputProps, listBoxProps, labelProps, clearButtonProps} = useSearchAutocomplete(
103
+ let layout = useListBoxLayout(state, loadingState === 'loadingMore');
104
+
105
+ let {inputProps, listBoxProps, labelProps, clearButtonProps, descriptionProps, errorMessageProps, isInvalid, validationErrors, validationDetails} = useSearchAutocomplete(
88
106
  {
89
107
  ...props,
90
108
  keyboardDelegate: layout,
@@ -96,18 +114,8 @@ const SearchAutocompleteBase = React.forwardRef(function SearchAutocompleteBase<
96
114
  state
97
115
  );
98
116
 
99
- let {overlayProps, placement, updatePosition} = useOverlayPosition({
100
- targetRef: inputRef,
101
- overlayRef: unwrappedPopoverRef,
102
- scrollRef: listBoxRef,
103
- placement: `${direction} end` as Placement,
104
- shouldFlip: shouldFlip,
105
- isOpen: state.isOpen,
106
- onClose: state.close
107
- });
108
-
109
117
  // Measure the width of the inputfield to inform the width of the menu (below).
110
- let [menuWidth, setMenuWidth] = useState(null);
118
+ let [menuWidth, setMenuWidth] = useState<number>(0);
111
119
  let {scale} = useProvider();
112
120
 
113
121
  let onResize = useCallback(() => {
@@ -124,43 +132,42 @@ const SearchAutocompleteBase = React.forwardRef(function SearchAutocompleteBase<
124
132
 
125
133
  useLayoutEffect(onResize, [scale, onResize]);
126
134
 
127
- // Update position once the ListBox has rendered. This ensures that
128
- // it flips properly when it doesn't fit in the available space.
129
- // TODO: add ResizeObserver to useOverlayPosition so we don't need this.
130
- useLayoutEffect(() => {
131
- if (state.isOpen) {
132
- requestAnimationFrame(() => {
133
- updatePosition();
134
- });
135
- }
136
- }, [state.isOpen, updatePosition]);
137
-
135
+ let width = isQuiet ? undefined : menuWidth;
138
136
  let style = {
139
- ...overlayProps.style,
140
- width: isQuiet ? null : menuWidth,
137
+ width: customMenuWidth ? dimensionValue(customMenuWidth) : width,
141
138
  minWidth: isQuiet ? `calc(${menuWidth}px + calc(2 * var(--spectrum-dropdown-quiet-offset)))` : menuWidth
142
139
  };
143
140
 
144
141
  return (
145
142
  <>
146
- <Field {...props} labelProps={labelProps} ref={domRef}>
143
+ <Field
144
+ {...props}
145
+ descriptionProps={descriptionProps}
146
+ errorMessageProps={errorMessageProps}
147
+ labelProps={labelProps}
148
+ isInvalid={isInvalid}
149
+ validationErrors={validationErrors}
150
+ validationDetails={validationDetails}
151
+ ref={domRef}>
147
152
  <SearchAutocompleteInput
148
153
  {...props}
149
154
  isOpen={state.isOpen}
150
155
  loadingState={loadingState}
151
156
  inputProps={inputProps}
152
157
  inputRef={inputRef}
153
- clearButtonProps={clearButtonProps} />
158
+ clearButtonProps={clearButtonProps}
159
+ validationState={props.validationState || (isInvalid ? 'invalid' : undefined)} />
154
160
  </Field>
155
161
  <Popover
156
- isOpen={state.isOpen}
162
+ state={state}
157
163
  UNSAFE_style={style}
158
164
  UNSAFE_className={classNames(styles, 'spectrum-InputGroup-popover', {'spectrum-InputGroup-popover--quiet': isQuiet})}
159
165
  ref={popoverRef}
160
- placement={placement}
166
+ triggerRef={inputRef}
167
+ placement={`${direction} ${align}`}
161
168
  hideArrow
162
169
  isNonModal
163
- isDismissable={false}>
170
+ shouldFlip={shouldFlip}>
164
171
  <ListBoxBase
165
172
  {...listBoxProps}
166
173
  ref={listBoxRef}
@@ -171,30 +178,39 @@ const SearchAutocompleteBase = React.forwardRef(function SearchAutocompleteBase<
171
178
  layout={layout}
172
179
  state={state}
173
180
  shouldUseVirtualFocus
174
- isLoading={loadingState === 'loadingMore'}
181
+ isLoading={loadingState === 'loading' || loadingState === 'loadingMore'}
175
182
  onLoadMore={onLoadMore}
176
183
  renderEmptyState={() => isAsync && (
177
- <span>
178
- {formatMessage('noResults')}
184
+ <span className={classNames(searchAutocompleteStyles, 'no-results')}>
185
+ {stringFormatter.format('noResults')}
179
186
  </span>
180
187
  )} />
181
- <DismissButton onDismiss={() => state.close()} />
182
188
  </Popover>
183
189
  </>
184
190
  );
185
- });
191
+ }
186
192
 
187
- interface SearchAutocompleteInputProps extends SpectrumSearchAutocompleteProps<unknown> {
193
+ let SearchAutocompleteBase = React.forwardRef(_SearchAutocompleteBase) as <T>(props: SpectrumSearchAutocompleteProps<T> & {ref?: FocusableRef<HTMLElement>}) => ReactElement;
194
+
195
+
196
+ interface SearchAutocompleteInputProps<T> extends SpectrumSearchAutocompleteProps<T> {
188
197
  inputProps: InputHTMLAttributes<HTMLInputElement>,
189
- inputRef: RefObject<HTMLInputElement | HTMLTextAreaElement>,
198
+ inputRef: RefObject<HTMLInputElement>,
190
199
  style?: React.CSSProperties,
191
200
  className?: string,
192
201
  isOpen?: boolean,
193
202
  clearButtonProps: AriaButtonProps
194
203
  }
195
204
 
196
- const SearchAutocompleteInput = React.forwardRef(function SearchAutocompleteInput(props: SearchAutocompleteInputProps, ref: RefObject<HTMLElement>) {
205
+ // any type is because we don't want to call useObjectRef because this is an internal component and we know
206
+ // we are always passing an object ref
207
+ function _SearchAutocompleteInput<T>(props: SearchAutocompleteInputProps<T>, ref: any) {
208
+ let searchIcon = (
209
+ <Magnifier data-testid="searchicon" />
210
+ );
211
+
197
212
  let {
213
+ icon = searchIcon,
198
214
  isQuiet,
199
215
  isDisabled,
200
216
  isReadOnly,
@@ -210,13 +226,14 @@ const SearchAutocompleteInput = React.forwardRef(function SearchAutocompleteInpu
210
226
  clearButtonProps
211
227
  } = props;
212
228
  let {hoverProps, isHovered} = useHover({});
213
- let formatMessage = useMessageFormatter(intlMessages);
214
- let timeout = useRef(null);
229
+ let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/autocomplete');
230
+ let domProps = filterDOMProps(props);
231
+ let timeout = useRef<ReturnType<typeof setTimeout> | null>(null);
215
232
  let [showLoading, setShowLoading] = useState(false);
216
233
 
217
234
  let loadingCircle = (
218
235
  <ProgressCircle
219
- aria-label={formatMessage('loading')}
236
+ aria-label={stringFormatter.format('loading')}
220
237
  size="S"
221
238
  isIndeterminate
222
239
  UNSAFE_className={classNames(
@@ -225,14 +242,14 @@ const SearchAutocompleteInput = React.forwardRef(function SearchAutocompleteInpu
225
242
  classNames(
226
243
  styles,
227
244
  'spectrum-InputGroup-input-circleLoader'
245
+ ),
246
+ classNames(
247
+ searchStyles,
248
+ 'spectrum-Search-circleLoader'
228
249
  )
229
250
  )} />
230
251
  );
231
252
 
232
- let searchIcon = (
233
- <Magnifier data-testid="searchicon" />
234
- );
235
-
236
253
  let clearButton = (
237
254
  <ClearButton
238
255
  {...clearButtonProps}
@@ -267,8 +284,10 @@ const SearchAutocompleteInput = React.forwardRef(function SearchAutocompleteInpu
267
284
  } else if (!isLoading) {
268
285
  // If loading is no longer happening, clear any timers and hide the loading circle
269
286
  setShowLoading(false);
270
- clearTimeout(timeout.current);
271
- timeout.current = null;
287
+ if (timeout.current != null) {
288
+ clearTimeout(timeout.current);
289
+ timeout.current = null;
290
+ }
272
291
  }
273
292
 
274
293
  lastInputValue.current = inputValue;
@@ -292,44 +311,63 @@ const SearchAutocompleteInput = React.forwardRef(function SearchAutocompleteInpu
292
311
  {
293
312
  'spectrum-InputGroup--quiet': isQuiet,
294
313
  'is-disabled': isDisabled,
295
- 'spectrum-InputGroup--invalid': validationState === 'invalid',
314
+ 'spectrum-InputGroup--invalid': validationState === 'invalid' && !isDisabled,
296
315
  'is-hovered': isHovered
297
316
  },
317
+ classNames(
318
+ searchAutocompleteStyles,
319
+ 'searchautocomplete'
320
+ ),
298
321
  className
299
322
  )
300
323
  }>
301
324
  <TextFieldBase
325
+ {...domProps}
302
326
  inputProps={inputProps}
303
327
  inputRef={inputRef}
304
328
  UNSAFE_className={
305
329
  classNames(
306
330
  searchStyles,
307
331
  'spectrum-Search',
332
+ 'spectrum-Search--loadable',
308
333
  'spectrum-Textfield',
309
334
  {
310
335
  'is-disabled': isDisabled,
311
336
  'is-quiet': isQuiet,
312
- 'spectrum-Search--invalid': validationState === 'invalid',
313
- 'spectrum-Search--valid': validationState === 'valid'
314
- }
337
+ 'spectrum-Search--invalid': validationState === 'invalid' && !isDisabled,
338
+ 'spectrum-Search--valid': validationState === 'valid' && !isDisabled
339
+ },
340
+ classNames(
341
+ styles,
342
+ 'spectrum-InputGroup-field'
343
+ )
315
344
  )
316
345
  }
317
346
  inputClassName={classNames(searchStyles, 'spectrum-Search-input')}
347
+ validationIconClassName={
348
+ classNames(
349
+ searchStyles,
350
+ 'spectrum-Search-validationIcon'
351
+ )
352
+ }
318
353
  isDisabled={isDisabled}
319
354
  isQuiet={isQuiet}
320
355
  validationState={validationState}
321
356
  isLoading={showLoading && (isOpen || menuTrigger === 'manual' || loadingState === 'loading')}
322
- loadingIndicator={loadingState != null && loadingCircle}
323
- icon={searchIcon}
324
- wrapperChildren={(inputValue !== '' && !isReadOnly) && clearButton} />
357
+ loadingIndicator={loadingState != null ? loadingCircle : undefined}
358
+ icon={icon}
359
+ wrapperChildren={(inputValue !== '' || loadingState === 'filtering' || validationState != null) && !isReadOnly ? clearButton : undefined}
360
+ disableFocusRing />
325
361
  </div>
326
362
  </FocusRing>
327
363
  );
328
- });
364
+ }
365
+
366
+ let SearchAutocompleteInput = React.forwardRef(_SearchAutocompleteInput) as <T>(props: SearchAutocompleteInputProps<T> & {ref?: any}) => ReactElement;
329
367
 
330
368
 
331
369
  /**
332
370
  * A SearchAutocomplete is a searchfield that supports a dynamic list of suggestions.
333
371
  */
334
- let _SearchAutocomplete = forwardRef(SearchAutocomplete);
372
+ let _SearchAutocomplete = forwardRef(SearchAutocomplete) as <T>(props: SpectrumSearchAutocompleteProps<T> & {ref?: FocusableRef<HTMLElement>}) => ReactElement;
335
373
  export {_SearchAutocomplete as SearchAutocomplete};
package/src/index.ts CHANGED
@@ -9,8 +9,7 @@
9
9
  * OF ANY KIND, either express or implied. See the License for the specific language
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
-
13
12
  /// <reference types="css-module-types" />
14
-
15
- export * from './SearchAutocomplete';
13
+ export {SearchAutocomplete} from './SearchAutocomplete';
16
14
  export {Item, Section} from '@react-stately/collections';
15
+ export type {SpectrumSearchAutocompleteProps} from '@react-types/autocomplete';
@@ -23,18 +23,25 @@
23
23
  font-style: italic;
24
24
  }
25
25
 
26
+ /* override .spectrum-InputGroup */
27
+ .searchautocomplete.searchautocomplete {
28
+ border-radius: var(--spectrum-search-border-radius);
29
+ --spectrum-focus-ring-border-radius: var(--spectrum-search-border-radius);
30
+ }
31
+
26
32
  .mobile-searchautocomplete {
27
33
  outline: none;
28
34
  }
29
35
 
30
36
  .mobile-input {
31
- white-space: nowrap;
32
- overflow: hidden;
33
- text-overflow: ellipsis;
37
+ display: flex;
38
+ align-items: center;
34
39
  }
35
40
 
36
41
  .mobile-value {
37
- vertical-align: middle;
42
+ white-space: nowrap;
43
+ overflow: hidden;
44
+ text-overflow: ellipsis;
38
45
  }
39
46
 
40
47
  .tray-dialog {