Skip to content

File tree

playroom/snippets.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,10 @@ const formSnippets: Array<Snippet> = [
498498
],
499499
['CvvField', '<CvvField name="cvv" label="CVV"/>'],
500500
['SearchField', '<SearchField name="search" label="Search"/>'],
501+
[
502+
'SearchField (with suggestions)',
503+
'<SearchField name="search2" label="Search" getSuggestions={() => ["aa", "bb", "cc", "dd"]}/>',
504+
],
501505
['Switch', '<Switch name="switch"/>'],
502506
['Checkbox', '<Checkbox name="checkbox">Checkbox</Checkbox>'],
503507
[
32.8 KB
Loading

src/__screenshot_tests__/input-fields-screenshot-test.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,21 @@ test('SearchField', async () => {
385385
expect(filledScreenshot).toMatchImageSnapshot();
386386
});
387387

388+
test('SearchField with suggestions', async () => {
389+
await openStoryPage({
390+
id: 'components-input-fields-searchfield--controlled',
391+
device: 'MOBILE_IOS',
392+
args: {suggestions: true},
393+
});
394+
395+
const field = await screen.findByLabelText('Label');
396+
await field.type('a');
397+
398+
const screenshot = await page.screenshot({fullPage: true});
399+
400+
expect(screenshot).toMatchImageSnapshot();
401+
});
402+
388403
test('DateField', async () => {
389404
await openStoryPage({
390405
id: 'components-input-fields-datefield--uncontrolled',

src/text-field-base.tsx

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ export const TextFieldBaseAutosuggest = React.forwardRef<any, TextFieldBaseProps
474474
({getSuggestions, id: idProp, ...props}, ref) => {
475475
const [suggestions, setSuggestions] = React.useState<ReadonlyArray<string>>([]);
476476
const inputRef = React.useRef<HTMLInputElement>(null);
477+
const containerRef = React.useRef<HTMLDivElement>(null);
477478
const {platformOverrides, texts, t} = useTheme();
478479
const reactId = React.useId();
479480
const id = idProp || reactId;
@@ -482,7 +483,6 @@ export const TextFieldBaseAutosuggest = React.forwardRef<any, TextFieldBaseProps
482483
if (getSuggestions && (props.value === undefined || props.defaultValue !== undefined)) {
483484
throw Error('Fields with suggestions must be used in controlled mode');
484485
}
485-
486486
return getSuggestions ? (
487487
<React.Suspense
488488
fallback={
@@ -512,12 +512,20 @@ export const TextFieldBaseAutosuggest = React.forwardRef<any, TextFieldBaseProps
512512
props.onChange?.(e);
513513
},
514514
}}
515-
renderInputComponent={(inputProps) => (
516-
<TextFieldBase
517-
{...(inputProps as TextFieldBaseProps)}
518-
inputRef={combineRefs(inputRef, props.inputRef, ref)}
519-
/>
520-
)}
515+
renderInputComponent={(inputProps) => {
516+
// The `Autosuggest.RenderInputComponentProps` type is missing the `key` property
517+
const {key, ...inputPropsWithoutKey} = inputProps as Record<string, any>;
518+
// extract key from inputProps to avoid React warning:
519+
// "A props object containing a "key" prop is being spread into JSX"
520+
return (
521+
<TextFieldBase
522+
key={key}
523+
{...(inputPropsWithoutKey as TextFieldBaseProps)}
524+
fieldRef={containerRef}
525+
inputRef={combineRefs(inputRef, props.inputRef, ref)}
526+
/>
527+
);
528+
}}
521529
suggestions={suggestions}
522530
onSuggestionsFetchRequested={({value}) => setSuggestions(getSuggestions(value))}
523531
onSuggestionsClearRequested={() => setSuggestions([])}
@@ -532,18 +540,24 @@ export const TextFieldBaseAutosuggest = React.forwardRef<any, TextFieldBaseProps
532540
<Text3 regular>{suggestion}</Text3>
533541
</div>
534542
)}
535-
renderSuggestionsContainer={(options) => (
536-
<div
537-
{...options.containerProps}
538-
style={{
539-
width: inputRef.current ? inputRef.current.clientWidth + 2 : 0, // +2 due to borders (input)
540-
}}
541-
className={styles.suggestionsContainer}
542-
aria-label={`${props.label} ${texts.menuLabelSuffix || t(tokens.menuLabelSuffix)}`}
543-
>
544-
{options.children}
545-
</div>
546-
)}
543+
renderSuggestionsContainer={(options) => {
544+
// extract key from containerProps to avoid React warning:
545+
// "A props object containing a "key" prop is being spread into JSX"
546+
const {key, ...containerPropsWithoutKey} = options.containerProps;
547+
return (
548+
<div
549+
{...containerPropsWithoutKey}
550+
key={key}
551+
style={{
552+
width: containerRef.current ? containerRef.current.clientWidth + 2 : 0, // +2 due to borders (input)
553+
}}
554+
className={styles.suggestionsContainer}
555+
aria-label={`${props.label} ${texts.menuLabelSuffix || t(tokens.menuLabelSuffix)}`}
556+
>
557+
{options.children}
558+
</div>
559+
);
560+
}}
547561
/>
548562
</React.Suspense>
549563
) : (

0 commit comments

Comments
 (0)