@@ -7,19 +7,105 @@ 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
+ size,
30
+ html_size,
31
+ setProps,
32
+ debounce,
33
+ loading_state,
34
+ className,
35
+ class_name,
36
+ autoComplete,
37
+ autocomplete,
38
+ autoFocus,
39
+ autofocus,
40
+ inputMode,
41
+ inputmode,
42
+ maxLength,
43
+ maxlength,
44
+ minLength,
45
+ minlength,
46
+ tabIndex,
47
+ tabindex,
21
48
...otherProps
22
49
} = props ;
50
+ const inputRef = useRef ( null ) ;
51
+
52
+ const formControlClass = plaintext
53
+ ? 'form-control-plaintext'
54
+ : 'form-control' ;
55
+
56
+ const classes = classNames (
57
+ class_name || className ,
58
+ invalid && 'is-invalid' ,
59
+ valid && 'is-valid' ,
60
+ size ? `form-control-${ size } ` : false ,
61
+ formControlClass
62
+ ) ;
63
+
64
+ const onChange = ( ) => {
65
+ if ( ! debounce ) {
66
+ onEvent ( ) ;
67
+ }
68
+ } ;
69
+
70
+ useEffect ( ( ) => {
71
+ if ( type === 'number' ) {
72
+ const inputValue = inputRef . current . value ;
73
+ const inputValueAsNumber = inputRef . current . checkValidity ( )
74
+ ? convert ( inputValue )
75
+ : NaN ;
76
+ const valueAsNumber = convert ( value ) ;
77
+
78
+ if ( ! isEquivalent ( valueAsNumber , inputValueAsNumber ) ) {
79
+ inputRef . current . value = isNil ( valueAsNumber ) ? valueAsNumber : value ;
80
+ }
81
+ } else {
82
+ const inputValue = inputRef . current . value ;
83
+
84
+ if ( value !== inputValue ) {
85
+ inputRef . current . value =
86
+ value !== null && value !== undefined ? value : '' ;
87
+ }
88
+ }
89
+ } , [ value ] ) ;
90
+
91
+ const onEvent = ( payload = { } ) => {
92
+ if ( type === 'number' ) {
93
+ const inputValue = inputRef . current . value ;
94
+ const inputValueAsNumber = inputRef . current . checkValidity ( )
95
+ ? convert ( inputValue )
96
+ : NaN ;
97
+ const valueAsNumber = convert ( value ) ;
98
+
99
+ if ( ! isEquivalent ( valueAsNumber , inputValueAsNumber ) ) {
100
+ setProps ( { ...payload , value : inputValueAsNumber } ) ;
101
+ } else if ( Object . keys ( payload ) . length ) {
102
+ setProps ( payload ) ;
103
+ }
104
+ } else {
105
+ payload . value = inputRef . current . value ;
106
+ setProps ( payload ) ;
107
+ }
108
+ } ;
23
109
24
110
const onBlur = ( ) => {
25
111
if ( setProps ) {
@@ -51,7 +137,9 @@ const BaseInput = forwardRef((props, ref) => {
51
137
52
138
return (
53
139
< input
54
- ref = { ref }
140
+ ref = { inputRef }
141
+ type = { type }
142
+ className = { classes }
55
143
onChange = { onChange }
56
144
onBlur = { onBlur }
57
145
onKeyPress = { onKeyPress }
@@ -70,162 +158,6 @@ const BaseInput = forwardRef((props, ref) => {
70
158
data-dash-is-loading = {
71
159
( loading_state && loading_state . is_loading ) || undefined
72
160
}
73
- />
74
- ) ;
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 {
174
- plaintext,
175
- className,
176
- class_name,
177
- autoComplete,
178
- autocomplete,
179
- autoFocus,
180
- autofocus,
181
- inputMode,
182
- inputmode,
183
- maxLength,
184
- maxlength,
185
- minLength,
186
- minlength,
187
- tabIndex,
188
- tabindex,
189
- size,
190
- html_size,
191
- ...otherProps
192
- } = props ;
193
- const inputRef = useRef ( null ) ;
194
-
195
- const formControlClass = plaintext
196
- ? 'form-control-plaintext'
197
- : 'form-control' ;
198
-
199
- const classes = classNames (
200
- class_name || className ,
201
- props . invalid && 'is-invalid' ,
202
- props . valid && 'is-valid' ,
203
- size ? `form-control-${ size } ` : false ,
204
- formControlClass
205
- ) ;
206
-
207
- if ( props . type === 'number' ) {
208
- return (
209
- < NumberInput
210
- ref = { inputRef }
211
- { ...otherProps }
212
- className = { classes }
213
- autoComplete = { autocomplete || autoComplete }
214
- autoFocus = { autofocus || autoFocus }
215
- inputMode = { inputmode || inputMode }
216
- maxLength = { maxlength || maxLength }
217
- minLength = { minlength || minLength }
218
- tabIndex = { tabindex || tabIndex }
219
- size = { html_size }
220
- />
221
- ) ;
222
- }
223
-
224
- return (
225
- < NonNumberInput
226
- ref = { inputRef }
227
- { ...otherProps }
228
- className = { classes }
229
161
autoComplete = { autocomplete || autoComplete }
230
162
autoFocus = { autofocus || autoFocus }
231
163
inputMode = { inputmode || inputMode }
0 commit comments