1
- import { handleRef } from '@fluentui/react-component-ref'
2
1
import cx from 'clsx'
3
2
import _ from 'lodash'
4
3
import PropTypes from 'prop-types'
5
- import React , { Children , cloneElement , Component , createRef } from 'react'
4
+ import React from 'react'
6
5
7
6
import {
8
7
childrenUtils ,
@@ -14,6 +13,7 @@ import {
14
13
partitionHTMLProps ,
15
14
useKeyOnly ,
16
15
useValueAndKey ,
16
+ setRef ,
17
17
} from '../../lib'
18
18
import Button from '../Button'
19
19
import Icon from '../Icon'
@@ -26,146 +26,144 @@ import Label from '../Label'
26
26
* @see Icon
27
27
* @see Label
28
28
*/
29
- class Input extends Component {
30
- inputRef = createRef ( )
31
-
32
- computeIcon = ( ) => {
33
- const { loading, icon } = this . props
29
+ const Input = React . forwardRef ( function ( props , ref ) {
30
+ const {
31
+ action,
32
+ actionPosition,
33
+ children,
34
+ className,
35
+ disabled,
36
+ error,
37
+ fluid,
38
+ focus,
39
+ icon,
40
+ iconPosition,
41
+ input,
42
+ inverted,
43
+ label,
44
+ labelPosition,
45
+ loading,
46
+ size,
47
+ tabIndex,
48
+ transparent,
49
+ type,
50
+ } = props
51
+
52
+ const computeIcon = ( ) => {
53
+ if ( ! _ . isNil ( icon ) ) {
54
+ return icon
55
+ }
34
56
35
- if ( ! _ . isNil ( icon ) ) return icon
36
- if ( loading ) return 'spinner'
57
+ if ( loading ) {
58
+ return 'spinner'
59
+ }
37
60
}
38
61
39
- computeTabIndex = ( ) => {
40
- const { disabled, tabIndex } = this . props
62
+ const computeTabIndex = ( ) => {
63
+ if ( ! _ . isNil ( tabIndex ) ) {
64
+ return tabIndex
65
+ }
41
66
42
- if ( ! _ . isNil ( tabIndex ) ) return tabIndex
43
- if ( disabled ) return - 1
67
+ if ( disabled ) {
68
+ return - 1
69
+ }
44
70
}
45
71
46
- focus = ( ) => this . inputRef . current . focus ( )
72
+ const handleChange = ( e ) => {
73
+ const newValue = _ . get ( e , 'target.value' )
47
74
48
- select = ( ) => this . inputRef . current . select ( )
49
-
50
- handleChange = ( e ) => {
51
- const value = _ . get ( e , 'target.value' )
52
-
53
- _ . invoke ( this . props , 'onChange' , e , { ...this . props , value } )
75
+ _ . invoke ( props , 'onChange' , e , { ...props , value : newValue } )
54
76
}
55
77
56
- handleChildOverrides = ( child , defaultProps ) => ( {
57
- ...defaultProps ,
58
- ...child . props ,
59
- ref : ( c ) => {
60
- handleRef ( child . ref , c )
61
- this . inputRef . current = c
62
- } ,
63
- } )
64
-
65
- partitionProps = ( ) => {
66
- const { disabled, type } = this . props
67
-
68
- const tabIndex = this . computeTabIndex ( )
69
- const unhandled = getUnhandledProps ( Input , this . props )
70
- const [ htmlInputProps , rest ] = partitionHTMLProps ( unhandled )
78
+ const partitionProps = ( ) => {
79
+ const unhandledProps = getUnhandledProps ( Input , props )
80
+ const [ htmlInputProps , rest ] = partitionHTMLProps ( unhandledProps )
71
81
72
82
return [
73
83
{
74
84
...htmlInputProps ,
75
85
disabled,
76
86
type,
77
- tabIndex,
78
- onChange : this . handleChange ,
79
- ref : this . inputRef ,
87
+ tabIndex : computeTabIndex ( ) ,
88
+ onChange : handleChange ,
89
+ ref,
80
90
} ,
81
91
rest ,
82
92
]
83
93
}
84
94
85
- render ( ) {
86
- const {
87
- action,
88
- actionPosition,
89
- children,
90
- className,
91
- disabled,
92
- error,
93
- fluid,
94
- focus,
95
- icon,
96
- iconPosition,
97
- input,
98
- inverted,
99
- label,
100
- labelPosition,
101
- loading,
102
- size,
103
- transparent,
104
- type,
105
- } = this . props
106
-
107
- const classes = cx (
108
- 'ui' ,
109
- size ,
110
- useKeyOnly ( disabled , 'disabled' ) ,
111
- useKeyOnly ( error , 'error' ) ,
112
- useKeyOnly ( fluid , 'fluid' ) ,
113
- useKeyOnly ( focus , 'focus' ) ,
114
- useKeyOnly ( inverted , 'inverted' ) ,
115
- useKeyOnly ( loading , 'loading' ) ,
116
- useKeyOnly ( transparent , 'transparent' ) ,
117
- useValueAndKey ( actionPosition , 'action' ) || useKeyOnly ( action , 'action' ) ,
118
- useValueAndKey ( iconPosition , 'icon' ) || useKeyOnly ( icon || loading , 'icon' ) ,
119
- useValueAndKey ( labelPosition , 'labeled' ) || useKeyOnly ( label , 'labeled' ) ,
120
- 'input' ,
121
- className ,
122
- )
123
- const ElementType = getElementType ( Input , this . props )
124
- const [ htmlInputProps , rest ] = this . partitionProps ( )
125
-
126
- // Render with children
127
- // ----------------------------------------
128
- if ( ! childrenUtils . isNil ( children ) ) {
129
- // add htmlInputProps to the `<input />` child
130
- const childElements = _ . map ( Children . toArray ( children ) , ( child ) => {
131
- if ( child . type !== 'input' ) return child
132
- return cloneElement ( child , this . handleChildOverrides ( child , htmlInputProps ) )
133
- } )
134
-
135
- return (
136
- < ElementType { ...rest } className = { classes } >
137
- { childElements }
138
- </ ElementType >
139
- )
140
- }
141
-
142
- // Render Shorthand
143
- // ----------------------------------------
144
- const actionElement = Button . create ( action , { autoGenerateKey : false } )
145
- const labelElement = Label . create ( label , {
146
- defaultProps : {
147
- className : cx (
148
- 'label' ,
149
- // add 'left|right corner'
150
- _ . includes ( labelPosition , 'corner' ) && labelPosition ,
151
- ) ,
152
- } ,
153
- autoGenerateKey : false ,
95
+ const classes = cx (
96
+ 'ui' ,
97
+ size ,
98
+ useKeyOnly ( disabled , 'disabled' ) ,
99
+ useKeyOnly ( error , 'error' ) ,
100
+ useKeyOnly ( fluid , 'fluid' ) ,
101
+ useKeyOnly ( focus , 'focus' ) ,
102
+ useKeyOnly ( inverted , 'inverted' ) ,
103
+ useKeyOnly ( loading , 'loading' ) ,
104
+ useKeyOnly ( transparent , 'transparent' ) ,
105
+ useValueAndKey ( actionPosition , 'action' ) || useKeyOnly ( action , 'action' ) ,
106
+ useValueAndKey ( iconPosition , 'icon' ) || useKeyOnly ( icon || loading , 'icon' ) ,
107
+ useValueAndKey ( labelPosition , 'labeled' ) || useKeyOnly ( label , 'labeled' ) ,
108
+ 'input' ,
109
+ className ,
110
+ )
111
+ const ElementType = getElementType ( Input , props )
112
+ const [ htmlInputProps , rest ] = partitionProps ( )
113
+
114
+ // Render with children
115
+ // ----------------------------------------
116
+ if ( ! childrenUtils . isNil ( children ) ) {
117
+ // add htmlInputProps to the `<input />` child
118
+ const childElements = _ . map ( React . Children . toArray ( children ) , ( child ) => {
119
+ if ( child . type === 'input' ) {
120
+ return React . cloneElement ( child , {
121
+ ...htmlInputProps ,
122
+ ...child . props ,
123
+ ref : ( c ) => {
124
+ setRef ( child . ref , c )
125
+ setRef ( ref , c )
126
+ } ,
127
+ } )
128
+ }
129
+
130
+ return child
154
131
} )
155
132
156
133
return (
157
134
< ElementType { ...rest } className = { classes } >
158
- { actionPosition === 'left' && actionElement }
159
- { labelPosition !== 'right' && labelElement }
160
- { createHTMLInput ( input || type , { defaultProps : htmlInputProps , autoGenerateKey : false } ) }
161
- { Icon . create ( this . computeIcon ( ) , { autoGenerateKey : false } ) }
162
- { actionPosition !== 'left' && actionElement }
163
- { labelPosition === 'right' && labelElement }
135
+ { childElements }
164
136
</ ElementType >
165
137
)
166
138
}
167
- }
168
139
140
+ // Render Shorthand
141
+ // ----------------------------------------
142
+ const actionElement = Button . create ( action , { autoGenerateKey : false } )
143
+ const labelElement = Label . create ( label , {
144
+ defaultProps : {
145
+ className : cx (
146
+ 'label' ,
147
+ // add 'left|right corner'
148
+ _ . includes ( labelPosition , 'corner' ) && labelPosition ,
149
+ ) ,
150
+ } ,
151
+ autoGenerateKey : false ,
152
+ } )
153
+
154
+ return (
155
+ < ElementType { ...rest } className = { classes } >
156
+ { actionPosition === 'left' && actionElement }
157
+ { labelPosition !== 'right' && labelElement }
158
+ { createHTMLInput ( input || type , { defaultProps : htmlInputProps , autoGenerateKey : false } ) }
159
+ { Icon . create ( computeIcon ( ) , { autoGenerateKey : false } ) }
160
+ { actionPosition !== 'left' && actionElement }
161
+ { labelPosition === 'right' && labelElement }
162
+ </ ElementType >
163
+ )
164
+ } )
165
+
166
+ Input . displayName = 'Input'
169
167
Input . propTypes = {
170
168
/** An element type to render as (string or function). */
171
169
as : PropTypes . elementType ,
0 commit comments