@@ -7,19 +7,91 @@ import classNames from 'classnames';
77const convert = val => ( isNumeric ( val ) ? + val : NaN ) ;
88const isEquivalent = ( v1 , v2 ) => v1 === v2 || ( isNaN ( v1 ) && isNaN ( v2 ) ) ;
99
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 => {
1121 const {
12- debounce,
22+ type,
23+ value,
1324 n_blur,
1425 n_submit,
15- loading_state,
16- setProps,
17- onEvent,
18- onChange,
1926 valid,
2027 invalid,
28+ plaintext,
29+ bs_size,
30+ setProps,
31+ debounce,
32+ loading_state,
33+ className,
2134 ...otherProps
2235 } = 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+ } ;
2395
2496 const onBlur = ( ) => {
2597 if ( setProps ) {
@@ -51,7 +123,9 @@ const BaseInput = forwardRef((props, ref) => {
51123
52124 return (
53125 < input
54- ref = { ref }
126+ ref = { inputRef }
127+ type = { type }
128+ className = { classes }
55129 onChange = { onChange }
56130 onBlur = { onBlur }
57131 onKeyPress = { onKeyPress }
@@ -72,124 +146,6 @@ const BaseInput = forwardRef((props, ref) => {
72146 }
73147 />
74148 ) ;
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 } /> ;
193149} ;
194150
195151Input . propTypes = {
0 commit comments