@@ -32,7 +32,22 @@ export type FormInputType =
3232 | "tel"
3333 | "range" ;
3434
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 {
3651 switch ( props . type ) {
3752 case "datetime-local" :
3853 case "date" : {
@@ -69,7 +84,12 @@ function defaultSerializer(currentValue: any, props: FormInputProps<any>): boole
6984 }
7085}
7186
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+ ) {
7393 switch ( props . type ) {
7494 case "number" : {
7595 return parseFloat ( inputValue ) as any ;
@@ -101,8 +121,8 @@ function defaultDeserializer(inputValue: string, inputChecked: boolean, currentV
101121 } else if ( props . value !== undefined ) {
102122 // Primitive array field
103123 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 ) ;
106126 return arr as any ;
107127 } else {
108128 // Boolean field
@@ -116,17 +136,13 @@ function defaultDeserializer(inputValue: string, inputChecked: boolean, currentV
116136 }
117137}
118138
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 & {
126140 form : FormState < T , State , Error > ;
127141 name : K ;
128142 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 > ;
130146 errorClassName ?: string ;
131147 errorStyle ?: React . CSSProperties ;
132148 dirtyClassName ?: string ;
@@ -143,15 +159,11 @@ export type FormInputProps<
143159 *
144160 * **FormSelect**, **FormTextArea** and **FormError** are also available.
145161 *
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).
147163 */
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+ ) {
155167 const {
156168 value : inputValue ,
157169 checked : inputChecked ,
@@ -165,14 +177,16 @@ export function FormInput<
165177 setUndefinedOnUncheck,
166178 className,
167179 disableOnSubmitting,
180+ serializer,
181+ deserializer,
168182 style,
169183 name,
170184 type,
171185 ...rest
172186 } = props ;
173187 const { value : currentValue , error, dirty, state, setValue } = useListener ( form , name ) ;
174188
175- let valueChecked = defaultSerializer ( currentValue , props ) ;
189+ let valueChecked = ( serializer ?? defaultSerializer ) ( currentValue , props ) ;
176190
177191 if ( process . env . NODE_ENV === "development" ) {
178192 if ( ( setNullOnUncheck || setUndefinedOnUncheck ) && type !== "checkbox" )
@@ -190,13 +204,10 @@ export function FormInput<
190204 } }
191205 className = { getClassName ( className , dirty && ( dirtyClassName ?? DEFAULT_DIRTY_CLASS ) , error && ( errorClassName ?? DEFAULT_ERROR_CLASS ) ) }
192206 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 }
195209 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 ) ) ;
200211 } }
201212 name = { name + "" }
202213 type = { type }
0 commit comments