@@ -32,7 +32,22 @@ export type FormInputType =
32
32
| "tel"
33
33
| "range" ;
34
34
35
- function defaultSerializer ( currentValue : any , props : FormInputProps < any > ) : boolean | string {
35
+ export type Serializer < T extends object , K extends keyof T , State = DefaultState , Error extends string = string > = (
36
+ currentValue : T [ K ] | T [ K ] [ keyof T [ K ] ] ,
37
+ props : FormInputProps < T , K , State , Error >
38
+ ) => boolean | string ;
39
+
40
+ export type Deserializer < T extends object , K extends keyof T , State = DefaultState , Error extends string = string > = (
41
+ inputValue : string ,
42
+ inputChecked : boolean ,
43
+ currentValue : T [ K ] | T [ K ] [ keyof T [ K ] ] ,
44
+ props : FormInputProps < T , K , State , Error >
45
+ ) => T [ K ] | T [ K ] [ keyof T [ K ] ] ;
46
+
47
+ function defaultSerializer < T extends object , K extends keyof T , State = DefaultState , Error extends string = string > (
48
+ currentValue : T [ K ] | T [ K ] [ keyof T [ K ] ] ,
49
+ props : FormInputProps < T , K , State , Error >
50
+ ) : boolean | string {
36
51
switch ( props . type ) {
37
52
case "datetime-local" :
38
53
case "date" : {
@@ -69,7 +84,12 @@ function defaultSerializer(currentValue: any, props: FormInputProps<any>): boole
69
84
}
70
85
}
71
86
72
- function defaultDeserializer ( inputValue : string , inputChecked : boolean , currentValue : any , props : FormInputProps < any > ) {
87
+ function defaultDeserializer < T extends object , K extends keyof T , State = DefaultState , Error extends string = string > (
88
+ inputValue : string ,
89
+ inputChecked : boolean ,
90
+ currentValue : any ,
91
+ props : FormInputProps < T , K , State , Error >
92
+ ) {
73
93
switch ( props . type ) {
74
94
case "number" : {
75
95
return parseFloat ( inputValue ) as any ;
@@ -101,8 +121,8 @@ function defaultDeserializer(inputValue: string, inputChecked: boolean, currentV
101
121
} else if ( props . value !== undefined ) {
102
122
// Primitive array field
103
123
let arr = Array . isArray ( currentValue ) ? [ ...currentValue ] : [ ] ;
104
- if ( inputChecked ) arr . push ( inputValue ) ;
105
- else arr . splice ( arr . indexOf ( inputValue ) , 1 ) ;
124
+ if ( inputChecked ) arr . push ( props . value ) ;
125
+ else arr . splice ( arr . indexOf ( props . value ) , 1 ) ;
106
126
return arr as any ;
107
127
} else {
108
128
// Boolean field
@@ -116,17 +136,13 @@ function defaultDeserializer(inputValue: string, inputChecked: boolean, currentV
116
136
}
117
137
}
118
138
119
- export type FormInputProps <
120
- T extends object ,
121
- K extends keyof T = keyof T ,
122
- Value extends T [ K ] | T [ K ] [ keyof T [ K ] ] = any ,
123
- State = DefaultState ,
124
- Error extends string = string
125
- > = BaldInputProps & {
139
+ export type FormInputProps < T extends object , K extends keyof T = keyof T , State = DefaultState , Error extends string = string > = BaldInputProps & {
126
140
form : FormState < T , State , Error > ;
127
141
name : K ;
128
142
type ?: FormInputType ;
129
- value ?: Value ;
143
+ value ?: T [ K ] | T [ K ] [ keyof T [ K ] ] ;
144
+ serializer ?: Serializer < T , K , State , Error > ;
145
+ deserializer ?: Deserializer < T , K , State , Error > ;
130
146
errorClassName ?: string ;
131
147
errorStyle ?: React . CSSProperties ;
132
148
dirtyClassName ?: string ;
@@ -143,15 +159,11 @@ export type FormInputProps<
143
159
*
144
160
* **FormSelect**, **FormTextArea** and **FormError** are also available.
145
161
*
146
- * When this component does not satisfy your needs, you can always [implement your own](https://typed-react-form.codestix.nl/docs/Custom-inputs #example-custom-input).
162
+ * When this component does not satisfy your needs, you can always [implement your own](https://typed-react-form.codestix.nl/docs/Custom-input #example-custom-input).
147
163
*/
148
- export function FormInput <
149
- T extends object ,
150
- K extends keyof T ,
151
- Value extends T [ K ] | T [ K ] [ keyof T [ K ] ] ,
152
- State extends DefaultState = DefaultState ,
153
- Error extends string = DefaultError
154
- > ( props : FormInputProps < T , K , Value , State , Error > ) {
164
+ export function FormInput < T extends object , K extends keyof T , State extends DefaultState = DefaultState , Error extends string = DefaultError > (
165
+ props : FormInputProps < T , K , State , Error >
166
+ ) {
155
167
const {
156
168
value : inputValue ,
157
169
checked : inputChecked ,
@@ -165,14 +177,16 @@ export function FormInput<
165
177
setUndefinedOnUncheck,
166
178
className,
167
179
disableOnSubmitting,
180
+ serializer,
181
+ deserializer,
168
182
style,
169
183
name,
170
184
type,
171
185
...rest
172
186
} = props ;
173
187
const { value : currentValue , error, dirty, state, setValue } = useListener ( form , name ) ;
174
188
175
- let valueChecked = defaultSerializer ( currentValue , props ) ;
189
+ let valueChecked = ( serializer ?? defaultSerializer ) ( currentValue , props ) ;
176
190
177
191
if ( process . env . NODE_ENV === "development" ) {
178
192
if ( ( setNullOnUncheck || setUndefinedOnUncheck ) && type !== "checkbox" )
@@ -190,13 +204,10 @@ export function FormInput<
190
204
} }
191
205
className = { getClassName ( className , dirty && ( dirtyClassName ?? DEFAULT_DIRTY_CLASS ) , error && ( errorClassName ?? DEFAULT_ERROR_CLASS ) ) }
192
206
disabled = { ( disableOnSubmitting ?? true ) && state . isSubmitting }
193
- value = { typeof valueChecked === "string" ? valueChecked : ( inputValue as any ) }
194
- checked = { typeof valueChecked === "boolean" ? valueChecked : inputChecked }
207
+ value = { typeof valueChecked === "string" ? valueChecked : undefined }
208
+ checked = { typeof valueChecked === "boolean" ? valueChecked : undefined }
195
209
onChange = { ( ev ) => {
196
- console . log ( "deserializing" , inputValue , ev . target . value , ev . target . checked , currentValue ) ;
197
- let dse = defaultDeserializer ( ev . target . value , ev . target . checked , currentValue , props ) ;
198
- console . log ( "deserialize" , JSON . stringify ( dse ) ) ;
199
- setValue ( dse ) ;
210
+ setValue ( ( deserializer ?? defaultDeserializer ) ( ev . target . value , ev . target . checked , currentValue , props ) ) ;
200
211
} }
201
212
name = { name + "" }
202
213
type = { type }
0 commit comments