Skip to content

Commit 4e9cf96

Browse files
author
Luke Bowerman
authored
Re-introduce forwardRef for InputSearch (#948)
* Re-introduce forwardRef for InputSearch * Add test to validate ref support
1 parent 328d8d9 commit 4e9cf96

File tree

2 files changed

+75
-53
lines changed

2 files changed

+75
-53
lines changed

packages/components/src/Form/Inputs/InputSearch/InputSearch.test.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
*/
2626

2727
import 'jest-styled-components'
28-
import React from 'react'
28+
import React, { createRef } from 'react'
2929
import {
3030
mountWithTheme,
3131
assertSnapshot,
@@ -47,6 +47,13 @@ test('InputSearch displays placeholder', () => {
4747
expect(wrapper.props().children.props.placeholder).toEqual('Type your search')
4848
})
4949

50+
test('InputSearch supports ref assignment', () => {
51+
const inputRef = createRef<HTMLInputElement>()
52+
53+
const wrapper = mountWithTheme(<InputSearch ref={inputRef} />)
54+
expect(wrapper.find('input')).toBeDefined()
55+
})
56+
5057
test('InputSearch displays value', () => {
5158
const wrapper = mountWithTheme(<InputSearch value="start value" />)
5259
expect(wrapper.props().children.props.value).toEqual('start value')

packages/components/src/Form/Inputs/InputSearch/InputSearch.tsx

Lines changed: 67 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@
2424
2525
*/
2626

27-
import React, { FC, useEffect, useState, FormEvent, MouseEvent } from 'react'
27+
import React, {
28+
forwardRef,
29+
Ref,
30+
useEffect,
31+
useState,
32+
FormEvent,
33+
MouseEvent,
34+
} from 'react'
2835
import styled from 'styled-components'
2936
import { Icon } from '../../../Icon'
3037
import { InputSearchBase, InputSearchBaseProps } from './InputSearchBase'
@@ -46,58 +53,66 @@ export const SearchIcon = styled(Icon)`
4653
padding-left: ${(props) => props.theme.space.small};
4754
`
4855

49-
export const InputSearch: FC<InputSearchProps> = ({
50-
summary,
51-
value: valueProp,
52-
disabled,
53-
hideControls = false,
54-
hideSearchIcon = false,
55-
onChange,
56-
onClear,
57-
defaultValue,
58-
...props
59-
}) => {
60-
const [value, setValue] = useState<string | undefined>()
56+
export const InputSearch = forwardRef(
57+
(
58+
{
59+
summary,
60+
value: valueProp,
61+
disabled,
62+
hideControls = false,
63+
hideSearchIcon = false,
64+
onChange,
65+
onClear,
66+
defaultValue,
67+
...props
68+
}: InputSearchProps,
69+
ref: Ref<HTMLInputElement>
70+
) => {
71+
const [value, setValue] = useState<string | undefined>()
6172

62-
const handleClear = (e: MouseEvent<HTMLButtonElement>) => {
63-
setValue('')
64-
onClear && onClear(e)
65-
onChange &&
66-
onChange({
67-
currentTarget: { value: '' },
68-
} as FormEvent<HTMLInputElement>)
69-
}
73+
const handleClear = (e: MouseEvent<HTMLButtonElement>) => {
74+
setValue('')
75+
onClear && onClear(e)
76+
onChange &&
77+
onChange({
78+
currentTarget: { value: '' },
79+
} as FormEvent<HTMLInputElement>)
80+
}
7081

71-
const handleChange = (e: FormEvent<HTMLInputElement>) => {
72-
const newValue = (e.target as HTMLInputElement).value
73-
setValue(newValue)
74-
onChange && onChange(e)
75-
}
82+
const handleChange = (e: FormEvent<HTMLInputElement>) => {
83+
const newValue = (e.target as HTMLInputElement).value
84+
setValue(newValue)
85+
onChange && onChange(e)
86+
}
7687

77-
// only update when valueProp changes, but not defaultValue
78-
useEffect(() => {
79-
setValue(valueProp || defaultValue)
80-
// eslint-disable-next-line react-hooks/exhaustive-deps
81-
}, [valueProp])
88+
// only update when valueProp changes, but not defaultValue
89+
useEffect(() => {
90+
setValue(valueProp || defaultValue)
91+
// eslint-disable-next-line react-hooks/exhaustive-deps
92+
}, [valueProp])
8293

83-
return (
84-
<InputSearchBase
85-
{...props}
86-
value={value}
87-
onChange={handleChange}
88-
searchIcon={
89-
hideSearchIcon ? undefined : <SearchIcon name="Search" size={30} />
90-
}
91-
searchControls={
92-
!hideControls ? (
93-
<InputSearchControls
94-
onClear={handleClear}
95-
disabled={disabled}
96-
summary={summary}
97-
showClear={!!(value && value.length >= 0)}
98-
/>
99-
) : undefined
100-
}
101-
/>
102-
)
103-
}
94+
return (
95+
<InputSearchBase
96+
{...props}
97+
value={value}
98+
ref={ref}
99+
onChange={handleChange}
100+
searchIcon={
101+
hideSearchIcon ? undefined : <SearchIcon name="Search" size={30} />
102+
}
103+
searchControls={
104+
!hideControls ? (
105+
<InputSearchControls
106+
onClear={handleClear}
107+
disabled={disabled}
108+
summary={summary}
109+
showClear={!!(value && value.length >= 0)}
110+
/>
111+
) : undefined
112+
}
113+
/>
114+
)
115+
}
116+
)
117+
118+
InputSearch.displayName = 'InputSearch'

0 commit comments

Comments
 (0)