@@ -18,6 +18,29 @@ const convert = (val: unknown) => (isNumeric(val) ? +val : NaN);
18
18
const isEquivalent = ( v1 : number , v2 : number ) =>
19
19
v1 === v2 || ( isNaN ( v1 ) && isNaN ( v2 ) ) ;
20
20
21
+ enum PersistenceTypes {
22
+ 'local' = 'local' ,
23
+ 'session' = 'session' ,
24
+ 'memory' = 'memory' ,
25
+ }
26
+
27
+ enum PersistedProps {
28
+ 'value' = 'value' ,
29
+ }
30
+
31
+ enum HTMLInputTypes {
32
+ // Only allowing the input types with wide browser compatibility
33
+ 'text' = 'text' ,
34
+ 'number' = 'number' ,
35
+ 'password' = 'password' ,
36
+ 'email' = 'email' ,
37
+ 'range' = 'range' ,
38
+ 'search' = 'search' ,
39
+ 'tel' = 'tel' ,
40
+ 'url' = 'url' ,
41
+ 'hidden' = 'hidden' ,
42
+ }
43
+
21
44
type InputProps = {
22
45
/**
23
46
* The value of the input
@@ -222,28 +245,19 @@ type InputProps = {
222
245
* component or the page. Since only `value` is allowed this prop can
223
246
* normally be ignored.
224
247
*/
225
- persisted_props ?: [ 'value' ] ;
248
+ persisted_props ?: PersistedProps [ ] ;
226
249
/**
227
250
* Where persisted user changes will be stored:
228
251
* memory: only kept in memory, reset on page refresh.
229
252
* local: window.localStorage, data is kept after the browser quit.
230
253
* session: window.sessionStorage, data is cleared once the browser quit.
231
254
*/
232
- persistence_type ?: 'local' | 'session' | 'memory' ;
255
+ persistence_type ?: PersistenceTypes ;
233
256
234
257
/**
235
258
* The type of control to render.
236
259
*/
237
- type ?: // Only allowing the input types with wide browser compatibility
238
- | 'text'
239
- | 'number'
240
- | 'password'
241
- | 'email'
242
- | 'range'
243
- | 'search'
244
- | 'tel'
245
- | 'url'
246
- | 'hidden' ;
260
+ type ?: HTMLInputTypes ;
247
261
} ;
248
262
249
263
const inputProps : ( keyof InputProps ) [ ] = [
@@ -268,15 +282,16 @@ const inputProps: (keyof InputProps)[] = [
268
282
] ;
269
283
270
284
const defaultProps : Partial < InputProps > = {
271
- type : 'text' ,
285
+ type : HTMLInputTypes . text ,
286
+ inputMode : 'verbatim' ,
272
287
n_blur : 0 ,
273
288
n_blur_timestamp : - 1 ,
274
289
n_submit : 0 ,
275
290
n_submit_timestamp : - 1 ,
276
291
debounce : false ,
277
292
step : 'any' ,
278
- persisted_props : [ ' value' ] ,
279
- persistence_type : ' local' ,
293
+ persisted_props : [ PersistedProps . value ] ,
294
+ persistence_type : PersistenceTypes . local ,
280
295
} ;
281
296
282
297
/**
@@ -286,14 +301,39 @@ const defaultProps: Partial<InputProps> = {
286
301
* the Checklist and RadioItems component. Dates, times, and file uploads
287
302
* are also supported through separate components.
288
303
*/
289
- function Input ( props : InputProps ) {
290
- props = { ...defaultProps , ...props } ;
304
+ function Input ( {
305
+ type = defaultProps . type ,
306
+ inputMode = defaultProps . inputMode ,
307
+ n_blur = defaultProps . n_blur ,
308
+ n_blur_timestamp = defaultProps . n_blur_timestamp ,
309
+ n_submit = defaultProps . n_submit ,
310
+ n_submit_timestamp = defaultProps . n_submit_timestamp ,
311
+ debounce = defaultProps . debounce ,
312
+ step = defaultProps . step ,
313
+ persisted_props = defaultProps . persisted_props ,
314
+ persistence_type = defaultProps . persistence_type ,
315
+ ...rest
316
+ } : InputProps ) {
317
+ const props = {
318
+ type,
319
+ inputMode,
320
+ n_blur,
321
+ n_blur_timestamp,
322
+ n_submit,
323
+ n_submit_timestamp,
324
+ debounce,
325
+ step,
326
+ persisted_props,
327
+ persistence_type,
328
+ ...rest ,
329
+ } ;
291
330
const input = useRef ( document . createElement ( 'input' ) ) ;
292
331
const [ value , setValue ] = useState < InputProps [ 'value' ] > ( props . value ) ;
293
332
const [ pendingEvent , setPendingEvent ] = useState < number > ( ) ;
294
333
const inputId = useId ( ) ;
295
334
296
- const valprops = props . type === 'number' ? { } : { value : value ?? '' } ;
335
+ const valprops =
336
+ props . type === HTMLInputTypes . number ? { } : { value : value ?? '' } ;
297
337
let { className} = props ;
298
338
className = 'dash-input' + ( className ? ` ${ className } ` : '' ) ;
299
339
@@ -314,7 +354,7 @@ function Input(props: InputProps) {
314
354
const { value : inputValue } = input . current ;
315
355
const { setProps} = props ;
316
356
const valueAsNumber = convert ( inputValue ) ;
317
- if ( props . type === ' number' ) {
357
+ if ( props . type === HTMLInputTypes . number ) {
318
358
setPropValue ( props . value , valueAsNumber ?? value ) ;
319
359
} else {
320
360
const propValue =
@@ -420,7 +460,7 @@ function Input(props: InputProps) {
420
460
}
421
461
const valueAsNumber = convert ( value ) ;
422
462
setInputValue ( valueAsNumber ?? value , props . value ) ;
423
- if ( props . type !== ' number' ) {
463
+ if ( props . type !== HTMLInputTypes . number ) {
424
464
setValue ( props . value ) ;
425
465
}
426
466
} , [ props . value , props . type , pendingEvent ] ) ;
@@ -437,7 +477,7 @@ function Input(props: InputProps) {
437
477
if ( typeof debounce === 'number' && Number . isFinite ( debounce ) ) {
438
478
debounceEvent ( debounce ) ;
439
479
}
440
- if ( type !== ' number' ) {
480
+ if ( type !== HTMLInputTypes . number ) {
441
481
setTimeout ( ( ) => {
442
482
input . current . setSelectionRange (
443
483
cursorPosition ,
@@ -452,7 +492,7 @@ function Input(props: InputProps) {
452
492
453
493
const pickedInputs = pick ( inputProps , props ) ;
454
494
455
- const isNumberInput = props . type === ' number' ;
495
+ const isNumberInput = props . type === HTMLInputTypes . number ;
456
496
const currentNumericValue = convert ( input . current . value || '0' ) ;
457
497
const minValue = convert ( props . min ) ;
458
498
const maxValue = convert ( props . max ) ;
@@ -467,7 +507,9 @@ function Input(props: InputProps) {
467
507
{ loadingProps => (
468
508
< div
469
509
className = { `dash-input-container ${ className } ${
470
- props . type === 'hidden' ? ' dash-input-hidden' : ''
510
+ props . type === HTMLInputTypes . hidden
511
+ ? ' dash-input-hidden'
512
+ : ''
471
513
} `. trim ( ) }
472
514
style = { props . style }
473
515
>
0 commit comments