Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

Commit 5e4dc81

Browse files
author
Silviu Avram
committed
refactored the Refs use in Dropdown
1 parent 1563a65 commit 5e4dc81

File tree

3 files changed

+35
-42
lines changed

3 files changed

+35
-42
lines changed

src/components/Dropdown/Dropdown.tsx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
RenderResultConfig,
2424
customPropTypes,
2525
commonPropTypes,
26+
handleRef,
2627
} from '../../lib'
2728
import keyboardKey from 'keyboard-key'
2829
import List from '../List/List'
@@ -133,9 +134,9 @@ export default class Dropdown extends AutoControlledComponent<
133134
Extendable<DropdownProps>,
134135
DropdownState
135136
> {
136-
private inputNode: HTMLElement
137-
private listNode: HTMLElement
138137
private buttonRef = React.createRef<HTMLElement>()
138+
private inputRef = React.createRef<HTMLElement>()
139+
private listRef = React.createRef<HTMLElement>()
139140

140141
static displayName = 'Dropdown'
141142

@@ -224,7 +225,7 @@ export default class Dropdown extends AutoControlledComponent<
224225
getA11yStatusMessage={getA11yStatusMessage}
225226
onStateChange={changes => {
226227
if (changes.isOpen && !search) {
227-
this.listNode.focus()
228+
this.listRef.current.focus()
228229
}
229230
}}
230231
>
@@ -330,9 +331,7 @@ export default class Dropdown extends AutoControlledComponent<
330331
placeholder: noPlaceholder ? '' : placeholder,
331332
hasToggleButton: !!toggleButton,
332333
variables,
333-
inputRef: (inputNode: HTMLElement) => {
334-
this.inputNode = inputNode
335-
},
334+
inputRef: this.inputRef,
336335
},
337336
overrideProps: (predefinedProps: DropdownSearchInputProps) =>
338337
this.handleSearchInputOverrides(
@@ -389,9 +388,9 @@ export default class Dropdown extends AutoControlledComponent<
389388
const { innerRef, ...accessibilityMenuPropsRest } = accessibilityMenuProps
390389
return (
391390
<Ref
392-
innerRef={(listNode: HTMLElement) => {
393-
this.listNode = listNode
394-
innerRef(listNode)
391+
innerRef={(listElement: HTMLElement) => {
392+
handleRef(this.listRef, listElement)
393+
handleRef(innerRef, listElement)
395394
}}
396395
>
397396
<List
@@ -485,7 +484,7 @@ export default class Dropdown extends AutoControlledComponent<
485484
case Downshift.stateChangeTypes.blurButton:
486485
// Downshift closes the list by default on trigger blur. It does not support the case when dropdown is
487486
// single selection and focuses list on trigger click/up/down/space/enter. Treating that here.
488-
if (state.isOpen && document.activeElement === this.listNode) {
487+
if (state.isOpen && document.activeElement === this.listRef.current) {
489488
return {} // won't change state in this case.
490489
}
491490
default:
@@ -645,7 +644,7 @@ export default class Dropdown extends AutoControlledComponent<
645644
}
646645

647646
private handleContainerClick = (isOpen: boolean) => {
648-
!isOpen && this.inputNode.focus()
647+
!isOpen && this.inputRef.current.focus()
649648
}
650649

651650
private handleListKeyDown = (
@@ -694,7 +693,7 @@ export default class Dropdown extends AutoControlledComponent<
694693

695694
private handleSelectedItemRemove(e: React.SyntheticEvent, item: ShorthandValue) {
696695
this.removeItemFromValue(item)
697-
this.inputNode.focus()
696+
this.inputRef.current.focus()
698697
e.stopPropagation()
699698
}
700699

src/components/Dropdown/DropdownSearchInput.tsx

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@ import Input from '../Input/Input'
1010
export interface DropdownSearchInputProps extends UIComponentProps<DropdownSearchInputProps> {
1111
/** Informs the search input about an existing toggle button. */
1212
hasToggleButton?: boolean
13-
/**
14-
* Ref callback with an input DOM node.
15-
*
16-
* @param {JSX.Element} node - input DOM node.
17-
*/
18-
inputRef?: (inputNode: HTMLElement) => void
13+
14+
/** Ref for input DOM node. */
15+
inputRef?: React.Ref<HTMLElement>
1916

2017
/**
2118
* Called on input element focus.
@@ -71,18 +68,14 @@ class DropdownSearchInput extends UIComponent<ReactProps<DropdownSearchInputProp
7168
accessibilityInputProps: PropTypes.object,
7269
accessibilityComboboxProps: PropTypes.object,
7370
hasToggleButton: PropTypes.bool,
74-
inputRef: PropTypes.func,
71+
inputRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
7572
onFocus: PropTypes.func,
7673
onInputBlur: PropTypes.func,
7774
onInputKeyDown: PropTypes.func,
7875
onKeyUp: PropTypes.func,
7976
placeholder: PropTypes.string,
8077
}
8178

82-
private handleInputRef = (inputNode: HTMLElement) => {
83-
_.invoke(this.props, 'inputRef', inputNode)
84-
}
85-
8679
private handleFocus = (e: React.SyntheticEvent) => {
8780
_.invoke(this.props, 'onFocus', e, this.props)
8881
}
@@ -100,10 +93,15 @@ class DropdownSearchInput extends UIComponent<ReactProps<DropdownSearchInputProp
10093
}
10194

10295
public renderComponent({ rest, styles }: RenderResultConfig<DropdownSearchInputProps>) {
103-
const { accessibilityComboboxProps, accessibilityInputProps, placeholder } = this.props
96+
const {
97+
accessibilityComboboxProps,
98+
accessibilityInputProps,
99+
inputRef,
100+
placeholder,
101+
} = this.props
104102
return (
105103
<Input
106-
inputRef={this.handleInputRef}
104+
inputRef={inputRef}
107105
onFocus={this.handleFocus}
108106
onKeyUp={this.handleKeyUp}
109107
wrapper={{

src/components/Input/Input.tsx

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
UIComponentProps,
1212
ChildrenComponentProps,
1313
commonPropTypes,
14+
handleRef,
1415
} from '../../lib'
1516
import { ReactProps, ShorthandValue, ComponentEventHandler } from '../../../types/utils'
1617
import Icon from '../Icon/Icon'
@@ -50,12 +51,8 @@ export interface InputProps extends UIComponentProps, ChildrenComponentProps {
5051
/** The HTML input type. */
5152
type?: string
5253

53-
/**
54-
* Ref callback with an input DOM node.
55-
*
56-
* @param {JSX.Element} node - input DOM node.
57-
*/
58-
inputRef?: (node: HTMLElement) => void
54+
/** Ref for input DOM node. */
55+
inputRef?: React.Ref<HTMLElement>
5956

6057
/** The value of the input. */
6158
value?: React.ReactText
@@ -77,7 +74,7 @@ export interface InputState {
7774
* - if input is search, then use "role='search'"
7875
*/
7976
class Input extends AutoControlledComponent<ReactProps<InputProps>, InputState> {
80-
private inputDomElement: HTMLInputElement
77+
private inputRef = React.createRef<HTMLElement>()
8178

8279
static className = 'ui-input'
8380

@@ -93,7 +90,7 @@ class Input extends AutoControlledComponent<ReactProps<InputProps>, InputState>
9390
icon: customPropTypes.itemShorthand,
9491
iconPosition: PropTypes.oneOf(['start', 'end']),
9592
input: customPropTypes.itemShorthand,
96-
inputRef: PropTypes.func,
93+
inputRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
9794
inline: PropTypes.bool,
9895
onChange: PropTypes.func,
9996
type: PropTypes.string,
@@ -116,7 +113,7 @@ class Input extends AutoControlledComponent<ReactProps<InputProps>, InputState>
116113
styles,
117114
variables,
118115
}: RenderResultConfig<InputProps>) {
119-
const { className, input, type, wrapper } = this.props
116+
const { className, input, inputRef, type, wrapper } = this.props
120117
const { value = '' } = this.state
121118
const [htmlInputProps, rest] = partitionHTMLProps(restProps)
122119

@@ -125,7 +122,12 @@ class Input extends AutoControlledComponent<ReactProps<InputProps>, InputState>
125122
className: cx(Input.className, className),
126123
children: (
127124
<>
128-
<Ref innerRef={this.handleInputRef}>
125+
<Ref
126+
innerRef={(inputElement: HTMLElement) => {
127+
handleRef(this.inputRef, inputElement)
128+
handleRef(inputRef, inputElement)
129+
}}
130+
>
129131
{Slot.create(input || type, {
130132
defaultProps: {
131133
...htmlInputProps,
@@ -155,16 +157,10 @@ class Input extends AutoControlledComponent<ReactProps<InputProps>, InputState>
155157
})
156158
}
157159

158-
private handleInputRef = (inputNode: HTMLElement) => {
159-
this.inputDomElement = inputNode as HTMLInputElement
160-
161-
_.invoke(this.props, 'inputRef', inputNode)
162-
}
163-
164160
private handleIconOverrides = predefinedProps => ({
165161
onClick: (e: React.SyntheticEvent) => {
166162
this.handleOnClear()
167-
this.inputDomElement.focus()
163+
this.inputRef.current.focus()
168164
_.invoke(predefinedProps, 'onClick', e, this.props)
169165
},
170166
...(predefinedProps.onClick && { tabIndex: '0' }),

0 commit comments

Comments
 (0)