@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.
- package/dist/ar-AE.main.js +9 -0
- package/dist/ar-AE.main.js.map +1 -0
- package/dist/ar-AE.mjs +11 -0
- package/dist/ar-AE.module.js +11 -0
- package/dist/ar-AE.module.js.map +1 -0
- package/dist/bg-BG.main.js +9 -0
- package/dist/bg-BG.main.js.map +1 -0
- package/dist/bg-BG.mjs +11 -0
- package/dist/bg-BG.module.js +11 -0
- package/dist/bg-BG.module.js.map +1 -0
- package/dist/cs-CZ.main.js +9 -0
- package/dist/cs-CZ.main.js.map +1 -0
- package/dist/cs-CZ.mjs +11 -0
- package/dist/cs-CZ.module.js +11 -0
- package/dist/cs-CZ.module.js.map +1 -0
- package/dist/da-DK.main.js +9 -0
- package/dist/da-DK.main.js.map +1 -0
- package/dist/da-DK.mjs +11 -0
- package/dist/da-DK.module.js +11 -0
- package/dist/da-DK.module.js.map +1 -0
- package/dist/de-DE.main.js +9 -0
- package/dist/de-DE.main.js.map +1 -0
- package/dist/de-DE.mjs +11 -0
- package/dist/de-DE.module.js +11 -0
- package/dist/de-DE.module.js.map +1 -0
- package/dist/el-GR.main.js +9 -0
- package/dist/el-GR.main.js.map +1 -0
- package/dist/el-GR.mjs +11 -0
- package/dist/el-GR.module.js +11 -0
- package/dist/el-GR.module.js.map +1 -0
- package/dist/en-US.main.js +9 -0
- package/dist/en-US.main.js.map +1 -0
- package/dist/en-US.mjs +11 -0
- package/dist/en-US.module.js +11 -0
- package/dist/en-US.module.js.map +1 -0
- package/dist/es-ES.main.js +9 -0
- package/dist/es-ES.main.js.map +1 -0
- package/dist/es-ES.mjs +11 -0
- package/dist/es-ES.module.js +11 -0
- package/dist/es-ES.module.js.map +1 -0
- package/dist/et-EE.main.js +9 -0
- package/dist/et-EE.main.js.map +1 -0
- package/dist/et-EE.mjs +11 -0
- package/dist/et-EE.module.js +11 -0
- package/dist/et-EE.module.js.map +1 -0
- package/dist/fi-FI.main.js +9 -0
- package/dist/fi-FI.main.js.map +1 -0
- package/dist/fi-FI.mjs +11 -0
- package/dist/fi-FI.module.js +11 -0
- package/dist/fi-FI.module.js.map +1 -0
- package/dist/fr-FR.main.js +9 -0
- package/dist/fr-FR.main.js.map +1 -0
- package/dist/fr-FR.mjs +11 -0
- package/dist/fr-FR.module.js +11 -0
- package/dist/fr-FR.module.js.map +1 -0
- package/dist/he-IL.main.js +9 -0
- package/dist/he-IL.main.js.map +1 -0
- package/dist/he-IL.mjs +11 -0
- package/dist/he-IL.module.js +11 -0
- package/dist/he-IL.module.js.map +1 -0
- package/dist/hr-HR.main.js +9 -0
- package/dist/hr-HR.main.js.map +1 -0
- package/dist/hr-HR.mjs +11 -0
- package/dist/hr-HR.module.js +11 -0
- package/dist/hr-HR.module.js.map +1 -0
- package/dist/hu-HU.main.js +9 -0
- package/dist/hu-HU.main.js.map +1 -0
- package/dist/hu-HU.mjs +11 -0
- package/dist/hu-HU.module.js +11 -0
- package/dist/hu-HU.module.js.map +1 -0
- package/dist/import.mjs +1044 -0
- package/dist/it-IT.main.js +9 -0
- package/dist/it-IT.main.js.map +1 -0
- package/dist/it-IT.mjs +11 -0
- package/dist/it-IT.module.js +11 -0
- package/dist/it-IT.module.js.map +1 -0
- package/dist/ja-JP.main.js +9 -0
- package/dist/ja-JP.main.js.map +1 -0
- package/dist/ja-JP.mjs +11 -0
- package/dist/ja-JP.module.js +11 -0
- package/dist/ja-JP.module.js.map +1 -0
- package/dist/ko-KR.main.js +9 -0
- package/dist/ko-KR.main.js.map +1 -0
- package/dist/ko-KR.mjs +11 -0
- package/dist/ko-KR.module.js +11 -0
- package/dist/ko-KR.module.js.map +1 -0
- package/dist/lt-LT.main.js +9 -0
- package/dist/lt-LT.main.js.map +1 -0
- package/dist/lt-LT.mjs +11 -0
- package/dist/lt-LT.module.js +11 -0
- package/dist/lt-LT.module.js.map +1 -0
- package/dist/lv-LV.main.js +9 -0
- package/dist/lv-LV.main.js.map +1 -0
- package/dist/lv-LV.mjs +11 -0
- package/dist/lv-LV.module.js +11 -0
- package/dist/lv-LV.module.js.map +1 -0
- package/dist/main.css +1700 -1
- package/dist/main.css.map +1 -0
- package/dist/main.js +716 -679
- package/dist/main.js.map +1 -1
- package/dist/module.js +715 -662
- package/dist/module.js.map +1 -1
- package/dist/nb-NO.main.js +9 -0
- package/dist/nb-NO.main.js.map +1 -0
- package/dist/nb-NO.mjs +11 -0
- package/dist/nb-NO.module.js +11 -0
- package/dist/nb-NO.module.js.map +1 -0
- package/dist/nl-NL.main.js +9 -0
- package/dist/nl-NL.main.js.map +1 -0
- package/dist/nl-NL.mjs +11 -0
- package/dist/nl-NL.module.js +11 -0
- package/dist/nl-NL.module.js.map +1 -0
- package/dist/pl-PL.main.js +9 -0
- package/dist/pl-PL.main.js.map +1 -0
- package/dist/pl-PL.mjs +11 -0
- package/dist/pl-PL.module.js +11 -0
- package/dist/pl-PL.module.js.map +1 -0
- package/dist/pt-BR.main.js +9 -0
- package/dist/pt-BR.main.js.map +1 -0
- package/dist/pt-BR.mjs +11 -0
- package/dist/pt-BR.module.js +11 -0
- package/dist/pt-BR.module.js.map +1 -0
- package/dist/pt-PT.main.js +9 -0
- package/dist/pt-PT.main.js.map +1 -0
- package/dist/pt-PT.mjs +11 -0
- package/dist/pt-PT.module.js +11 -0
- package/dist/pt-PT.module.js.map +1 -0
- package/dist/ro-RO.main.js +9 -0
- package/dist/ro-RO.main.js.map +1 -0
- package/dist/ro-RO.mjs +11 -0
- package/dist/ro-RO.module.js +11 -0
- package/dist/ro-RO.module.js.map +1 -0
- package/dist/ru-RU.main.js +9 -0
- package/dist/ru-RU.main.js.map +1 -0
- package/dist/ru-RU.mjs +11 -0
- package/dist/ru-RU.module.js +11 -0
- package/dist/ru-RU.module.js.map +1 -0
- package/dist/sk-SK.main.js +9 -0
- package/dist/sk-SK.main.js.map +1 -0
- package/dist/sk-SK.mjs +11 -0
- package/dist/sk-SK.module.js +11 -0
- package/dist/sk-SK.module.js.map +1 -0
- package/dist/sl-SI.main.js +9 -0
- package/dist/sl-SI.main.js.map +1 -0
- package/dist/sl-SI.mjs +11 -0
- package/dist/sl-SI.module.js +11 -0
- package/dist/sl-SI.module.js.map +1 -0
- package/dist/sr-SP.main.js +9 -0
- package/dist/sr-SP.main.js.map +1 -0
- package/dist/sr-SP.mjs +11 -0
- package/dist/sr-SP.module.js +11 -0
- package/dist/sr-SP.module.js.map +1 -0
- package/dist/sv-SE.main.js +9 -0
- package/dist/sv-SE.main.js.map +1 -0
- package/dist/sv-SE.mjs +11 -0
- package/dist/sv-SE.module.js +11 -0
- package/dist/sv-SE.module.js.map +1 -0
- package/dist/tr-TR.main.js +9 -0
- package/dist/tr-TR.main.js.map +1 -0
- package/dist/tr-TR.mjs +11 -0
- package/dist/tr-TR.module.js +11 -0
- package/dist/tr-TR.module.js.map +1 -0
- package/dist/types.d.ts +6 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/uk-UA.main.js +9 -0
- package/dist/uk-UA.main.js.map +1 -0
- package/dist/uk-UA.mjs +11 -0
- package/dist/uk-UA.module.js +11 -0
- package/dist/uk-UA.module.js.map +1 -0
- package/dist/zh-CN.main.js +9 -0
- package/dist/zh-CN.main.js.map +1 -0
- package/dist/zh-CN.mjs +11 -0
- package/dist/zh-CN.module.js +11 -0
- package/dist/zh-CN.module.js.map +1 -0
- package/dist/zh-TW.main.js +9 -0
- package/dist/zh-TW.main.js.map +1 -0
- package/dist/zh-TW.mjs +11 -0
- package/dist/zh-TW.module.js +11 -0
- package/dist/zh-TW.module.js.map +1 -0
- package/package.json +34 -29
- package/src/MobileSearchAutocomplete.tsx +226 -141
- package/src/SearchAutocomplete.tsx +109 -71
- package/src/index.ts +2 -3
- 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, {
|
|
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,
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
166
|
+
triggerRef={inputRef}
|
|
167
|
+
placement={`${direction} ${align}`}
|
|
161
168
|
hideArrow
|
|
162
169
|
isNonModal
|
|
163
|
-
|
|
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
|
-
{
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
214
|
-
let
|
|
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={
|
|
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
|
-
|
|
271
|
-
|
|
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
|
|
323
|
-
icon={
|
|
324
|
-
wrapperChildren={(inputValue !== '' && !isReadOnly
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
text-overflow: ellipsis;
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
.mobile-value {
|
|
37
|
-
|
|
42
|
+
white-space: nowrap;
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
text-overflow: ellipsis;
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
.tray-dialog {
|