@@ -7,19 +7,91 @@ import classNames from 'classnames';
7
7
const convert = val => ( isNumeric ( val ) ? + val : NaN ) ;
8
8
const isEquivalent = ( v1 , v2 ) => v1 === v2 || ( isNaN ( v1 ) && isNaN ( v2 ) ) ;
9
9
10
- const BaseInput = forwardRef ( ( props , ref ) => {
10
+ /**
11
+ * A basic HTML input control for entering text, numbers, or passwords, with
12
+ * Bootstrap styles automatically applied. This component is much like its
13
+ * counterpart in dash_core_components, but with a few additions such as the
14
+ * `valid` and `invalid` props for providing user feedback.
15
+ *
16
+ * Note that checkbox and radio types are supported through
17
+ * the Checklist and RadioItems component. Dates, times, and file uploads
18
+ * are supported through separate components in other libraries.
19
+ */
20
+ const Input = props => {
11
21
const {
12
- debounce,
22
+ type,
23
+ value,
13
24
n_blur,
14
25
n_submit,
15
- loading_state,
16
- setProps,
17
- onEvent,
18
- onChange,
19
26
valid,
20
27
invalid,
28
+ plaintext,
29
+ bs_size,
30
+ setProps,
31
+ debounce,
32
+ loading_state,
33
+ className,
21
34
...otherProps
22
35
} = props ;
36
+ const inputRef = useRef ( null ) ;
37
+
38
+ const formControlClass = plaintext
39
+ ? 'form-control-plaintext'
40
+ : 'form-control' ;
41
+
42
+ const classes = classNames (
43
+ className ,
44
+ invalid && 'is-invalid' ,
45
+ valid && 'is-valid' ,
46
+ bs_size ? `form-control-${ bs_size } ` : false ,
47
+ formControlClass
48
+ ) ;
49
+
50
+ const onChange = ( ) => {
51
+ if ( ! debounce ) {
52
+ onEvent ( ) ;
53
+ }
54
+ } ;
55
+
56
+ useEffect ( ( ) => {
57
+ if ( type === 'number' ) {
58
+ const inputValue = inputRef . current . value ;
59
+ const inputValueAsNumber = inputRef . current . checkValidity ( )
60
+ ? convert ( inputValue )
61
+ : NaN ;
62
+ const valueAsNumber = convert ( value ) ;
63
+
64
+ if ( ! isEquivalent ( valueAsNumber , inputValueAsNumber ) ) {
65
+ inputRef . current . value = isNil ( valueAsNumber ) ? valueAsNumber : value ;
66
+ }
67
+ } else {
68
+ const inputValue = inputRef . current . value ;
69
+
70
+ if ( value !== inputValue ) {
71
+ inputRef . current . value =
72
+ value !== null && value !== undefined ? value : '' ;
73
+ }
74
+ }
75
+ } , [ value ] ) ;
76
+
77
+ const onEvent = ( payload = { } ) => {
78
+ if ( type === 'number' ) {
79
+ const inputValue = inputRef . current . value ;
80
+ const inputValueAsNumber = inputRef . current . checkValidity ( )
81
+ ? convert ( inputValue )
82
+ : NaN ;
83
+ const valueAsNumber = convert ( value ) ;
84
+
85
+ if ( ! isEquivalent ( valueAsNumber , inputValueAsNumber ) ) {
86
+ setProps ( { ...payload , value : inputValueAsNumber } ) ;
87
+ } else if ( Object . keys ( payload ) . length ) {
88
+ setProps ( payload ) ;
89
+ }
90
+ } else {
91
+ payload . value = inputRef . current . value ;
92
+ setProps ( payload ) ;
93
+ }
94
+ } ;
23
95
24
96
const onBlur = ( ) => {
25
97
if ( setProps ) {
@@ -51,7 +123,9 @@ const BaseInput = forwardRef((props, ref) => {
51
123
52
124
return (
53
125
< input
54
- ref = { ref }
126
+ ref = { inputRef }
127
+ type = { type }
128
+ className = { classes }
55
129
onChange = { onChange }
56
130
onBlur = { onBlur }
57
131
onKeyPress = { onKeyPress }
@@ -72,124 +146,6 @@ const BaseInput = forwardRef((props, ref) => {
72
146
}
73
147
/>
74
148
) ;
75
- } ) ;
76
-
77
- const NumberInput = forwardRef ( ( props , inputRef ) => {
78
- const { setProps, debounce, value, ...otherProps } = props ;
79
-
80
- const onChange = ( ) => {
81
- if ( ! debounce ) {
82
- onEvent ( ) ;
83
- }
84
- } ;
85
-
86
- useEffect ( ( ) => {
87
- const inputValue = inputRef . current . value ;
88
- const inputValueAsNumber = inputRef . current . checkValidity ( )
89
- ? convert ( inputValue )
90
- : NaN ;
91
- const valueAsNumber = convert ( value ) ;
92
-
93
- if ( ! isEquivalent ( valueAsNumber , inputValueAsNumber ) ) {
94
- inputRef . current . value = isNil ( valueAsNumber ) ? valueAsNumber : value ;
95
- }
96
- } , [ value ] ) ;
97
-
98
- const onEvent = ( payload = { } ) => {
99
- const inputValue = inputRef . current . value ;
100
- const inputValueAsNumber = inputRef . current . checkValidity ( )
101
- ? convert ( inputValue )
102
- : NaN ;
103
- const valueAsNumber = convert ( value ) ;
104
-
105
- if ( ! isEquivalent ( valueAsNumber , inputValueAsNumber ) ) {
106
- setProps ( { ...payload , value : inputValueAsNumber } ) ;
107
- } else if ( Object . keys ( payload ) . length ) {
108
- setProps ( payload ) ;
109
- }
110
- } ;
111
-
112
- return (
113
- < BaseInput
114
- ref = { inputRef }
115
- debounce = { debounce }
116
- onEvent = { onEvent }
117
- onChange = { onChange }
118
- setProps = { setProps }
119
- { ...otherProps }
120
- />
121
- ) ;
122
- } ) ;
123
-
124
- const NonNumberInput = forwardRef ( ( props , inputRef ) => {
125
- const { value, debounce, setProps, ...otherProps } = props ;
126
- const [ valueState , setValueState ] = useState ( value || '' ) ;
127
-
128
- const onChange = ( ) => {
129
- if ( ! debounce ) {
130
- onEvent ( ) ;
131
- } else {
132
- setValueState ( inputRef . current . value ) ;
133
- }
134
- } ;
135
-
136
- useEffect ( ( ) => {
137
- if ( value !== null && value !== undefined ) {
138
- setValueState ( value ) ;
139
- } else {
140
- setValueState ( '' ) ;
141
- }
142
- } , [ value ] ) ;
143
-
144
- const onEvent = ( payload = { } ) => {
145
- payload . value = inputRef . current . value ;
146
- setProps ( payload ) ;
147
- } ;
148
-
149
- return (
150
- < BaseInput
151
- ref = { inputRef }
152
- value = { valueState }
153
- debounce = { debounce }
154
- onEvent = { onEvent }
155
- onChange = { onChange }
156
- setProps = { setProps }
157
- { ...otherProps }
158
- />
159
- ) ;
160
- } ) ;
161
-
162
- /**
163
- * A basic HTML input control for entering text, numbers, or passwords, with
164
- * Bootstrap styles automatically applied. This component is much like its
165
- * counterpart in dash_core_components, but with a few additions such as the
166
- * `valid` and `invalid` props for providing user feedback.
167
- *
168
- * Note that checkbox and radio types are supported through
169
- * the Checklist and RadioItems component. Dates, times, and file uploads
170
- * are supported through separate components in other libraries.
171
- */
172
- const Input = props => {
173
- const { plaintext, className, bs_size, ...otherProps } = props ;
174
- const inputRef = useRef ( null ) ;
175
-
176
- const formControlClass = plaintext
177
- ? 'form-control-plaintext'
178
- : 'form-control' ;
179
-
180
- const classes = classNames (
181
- className ,
182
- props . invalid && 'is-invalid' ,
183
- props . valid && 'is-valid' ,
184
- bs_size ? `form-control-${ bs_size } ` : false ,
185
- formControlClass
186
- ) ;
187
-
188
- if ( props . type === 'number' ) {
189
- return < NumberInput ref = { inputRef } { ...otherProps } className = { classes } /> ;
190
- }
191
-
192
- return < NonNumberInput ref = { inputRef } { ...otherProps } className = { classes } /> ;
193
149
} ;
194
150
195
151
Input . propTypes = {
0 commit comments