Skip to content

Commit c23b762

Browse files
committed
Simpler SerializeProps
1 parent 38afd47 commit c23b762

File tree

2 files changed

+39
-33
lines changed

2 files changed

+39
-33
lines changed

example/src/ExampleForm.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ const FormDataSchema = tv.object({
1111
number: tv.number(),
1212
boolean: tv.boolean(),
1313
date: tv.date(),
14+
tags: tv.array(tv.value("food").or(tv.value("tech").or(tv.value("sports")))),
1415
object: tv.object({
1516
childText: tv.string(),
1617
childNumber: tv.number()
1718
}),
1819
array: tv.array(tv.string()),
20+
customText: tv.string(),
1921
objectArray: tv.array(
2022
tv.object({
2123
text: tv.string(),
@@ -72,6 +74,11 @@ export function ExampleForm() {
7274
<FormInput form={form} name="text" />
7375
<pre>{`<FormInput form={form} name="fieldName" />`}</pre>
7476

77+
{/* A simple text input */}
78+
<label>Deserializer text</label>
79+
<FormInput form={form} name="customText" serializer={(e) => e?.toLowerCase()} deserializer={(e) => e.toUpperCase()} />
80+
<pre>{`<FormInput form={form} name="fieldName" />`}</pre>
81+
7582
{/* A textarea */}
7683
<label>Long text</label>
7784
<FormTextArea form={form} name="longText" />
@@ -102,6 +109,23 @@ export function ExampleForm() {
102109
<FormInput form={form} type="checkbox" name="boolean" />
103110
<pre>{`<FormInput form={form} type="checkbox" name="fieldName" />`}</pre>
104111

112+
<label>Tags</label>
113+
<div>
114+
<label>
115+
Food
116+
<FormInput form={form} type="checkbox" name="tags" value="food" />
117+
</label>
118+
<label>
119+
Sports
120+
<FormInput form={form} type="checkbox" name="tags" value="sports" />
121+
</label>
122+
<label>
123+
Tech
124+
<FormInput form={form} type="checkbox" name="tags" value="tech" />
125+
</label>
126+
</div>
127+
<pre>{`<FormInput form={form} type="checkbox" name="fieldName" />`}</pre>
128+
105129
{/* A radio input */}
106130
<label>Enum</label>
107131
<div>

src/elements/FormInput.tsx

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ export function getClassName(...args: any) {
1212
return [...args].filter((e) => !!e).join(" ");
1313
}
1414

15-
export type FormInputCheckMode = "normal" | "setNull" | "setUndefined";
16-
17-
export type FormInputType =
15+
export type SerializeType =
1816
| "number"
1917
| "text"
2018
| "password"
@@ -32,30 +30,21 @@ export type FormInputType =
3230
| "tel"
3331
| "range";
3432

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;
33+
export type Serializer<T> = (currentValue: T, props: SerializeProps<T>) => boolean | string;
3934

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]];
35+
export type Deserializer<T> = (inputValue: string, inputChecked: boolean, currentValue: T, props: SerializeProps<T>) => T;
4636

47-
export type SerializeProps<T extends object, K extends keyof T> = {
37+
export type SerializeProps<V> = {
4838
dateAsNumber?: boolean;
4939
setUndefinedOnUncheck?: boolean;
5040
setNullOnUncheck?: boolean;
51-
type?: FormInputType;
52-
value?: T[K] | T[K][keyof T[K]];
41+
type?: SerializeType;
42+
value?: V;
5343
};
5444

55-
export function defaultSerializer<T extends object, K extends keyof T>(
56-
currentValue: T[K] | T[K][keyof T[K]],
57-
props: SerializeProps<T, K>
58-
): boolean | string {
45+
export type FormInputValue<T extends object, K extends keyof T> = T[K] extends any[] ? T[K][keyof T[K]] : T[K];
46+
47+
export function defaultSerializer<T>(currentValue: T, props: SerializeProps<T>): boolean | string {
5948
switch (props.type) {
6049
case "datetime-local":
6150
case "date": {
@@ -92,12 +81,7 @@ export function defaultSerializer<T extends object, K extends keyof T>(
9281
}
9382
}
9483

95-
export function defaultDeserializer<T extends object, K extends keyof T>(
96-
inputValue: string,
97-
inputChecked: boolean,
98-
currentValue: T[K],
99-
props: SerializeProps<T, K>
100-
) {
84+
export function defaultDeserializer<T>(inputValue: string, inputChecked: boolean, currentValue: T, props: SerializeProps<T>) {
10185
switch (props.type) {
10286
case "number": {
10387
return parseFloat(inputValue) as any;
@@ -147,17 +131,15 @@ export function defaultDeserializer<T extends object, K extends keyof T>(
147131
export type FormInputProps<T extends object, K extends keyof T = keyof T, State = DefaultState, Error extends string = string> = BaldInputProps & {
148132
form: FormState<T, State, Error>;
149133
name: K;
150-
type?: FormInputType;
151-
value?: T[K] | T[K][keyof T[K]];
152-
serializer?: Serializer<T, K, State, Error>;
153-
deserializer?: Deserializer<T, K, State, Error>;
134+
serializer?: Serializer<FormInputValue<T, K>>;
135+
deserializer?: Deserializer<FormInputValue<T, K>>;
154136
errorClassName?: string;
155137
errorStyle?: React.CSSProperties;
156138
dirtyClassName?: string;
157139
dirtyStyle?: React.CSSProperties;
158140
disableOnSubmitting?: boolean;
159141
hideWhenNull?: boolean;
160-
} & SerializeProps<T, K>;
142+
} & SerializeProps<FormInputValue<T, K>>;
161143

162144
/**
163145
* The builtin form input. You must always specify **form** and **name**. Use the **type** prop to specify what type of field it represents.
@@ -191,7 +173,7 @@ export function FormInput<T extends object, K extends keyof T, State extends Def
191173
} = props;
192174
const { value: currentValue, error, dirty, state, setValue } = useListener(form, name);
193175

194-
let valueChecked = (serializer ?? defaultSerializer)(currentValue, props);
176+
let valueChecked = (serializer ?? defaultSerializer)(currentValue as FormInputValue<T, K>, props);
195177

196178
if (process.env.NODE_ENV === "development") {
197179
if ((setNullOnUncheck || setUndefinedOnUncheck) && type !== "checkbox")
@@ -212,7 +194,7 @@ export function FormInput<T extends object, K extends keyof T, State extends Def
212194
value={typeof valueChecked === "string" ? valueChecked : undefined}
213195
checked={typeof valueChecked === "boolean" ? valueChecked : undefined}
214196
onChange={(ev) => {
215-
setValue((deserializer ?? defaultDeserializer)(ev.target.value, ev.target.checked, currentValue, props));
197+
setValue((deserializer ?? defaultDeserializer)(ev.target.value, ev.target.checked, currentValue as FormInputValue<T, K>, props));
216198
}}
217199
name={name as string}
218200
type={type}

0 commit comments

Comments
 (0)