Skip to content

Commit 4243727

Browse files
authored
Merge pull request #40 from dsnjunior/feat/generate-min-and-max
`min` and `max` number input props
2 parents 8e993bb + 23cb93c commit 4243727

File tree

3 files changed

+35
-6
lines changed

3 files changed

+35
-6
lines changed

.changeset/unlucky-gorillas-learn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"simple-stack-form": patch
3+
---
4+
5+
Add `min` and `max` input props to number input if present on schema

examples/playground/src/components/react/Signup.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const signup = createForm({
1414
return s !== "admin";
1515
}),
1616
email: z.string().email().optional(),
17+
coffees: z.number().lt(10).min(2),
1718
optIn: z.boolean().optional(),
1819
});
1920

@@ -35,6 +36,10 @@ export default function Signup({
3536
<label htmlFor={scope("email")}>Email</label>
3637
<Input id={scope("email")} {...signup.inputProps.email} />
3738
</FormGroup>
39+
<FormGroup>
40+
<label htmlFor={scope("coffees")}>Coffees taken</label>
41+
<Input id={scope("coffees")} {...signup.inputProps.coffees} />
42+
</FormGroup>
3843
<FormGroup>
3944
<label htmlFor={scope("optIn")}>Opt in</label>
4045
<Input id={scope("optIn")} {...signup.inputProps.optIn} />

packages/form/src/module.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ import {
33
ZodArray,
44
ZodBoolean,
55
type ZodError,
6-
ZodLiteral,
76
ZodNullable,
87
ZodNumber,
98
ZodObject,
109
ZodOptional,
1110
type ZodRawShape,
1211
ZodString,
1312
type ZodType,
14-
ZodUnion,
1513
z,
1614
} from "zod";
1715

@@ -23,8 +21,10 @@ export type FieldErrors<
2321
export type InputProp = {
2422
"aria-required": boolean;
2523
name: string;
26-
type: "text" | "number" | "checkbox" | "email";
27-
};
24+
} & (
25+
| { type: "text" | "checkbox" | "email" }
26+
| { type: "number"; min?: number; max?: number }
27+
);
2828

2929
export const formNameInputProps = {
3030
type: "hidden",
@@ -207,11 +207,15 @@ function getInputProp<T extends ZodType>(
207207
fieldValidator: T,
208208
name: string | number | symbol,
209209
) {
210+
const inputInfo = getInputInfo<T>(fieldValidator);
211+
210212
const inputProp: InputProp = {
211213
name: String(name),
212214
"aria-required":
213215
!fieldValidator.isOptional() && !fieldValidator.isNullable(),
214-
type: getInputInfo<T>(fieldValidator).type,
216+
type: inputInfo.type,
217+
min: inputInfo.min,
218+
max: inputInfo.max,
215219
};
216220

217221
return inputProp;
@@ -240,6 +244,8 @@ function getInputInfo<T extends ZodType>(fieldValidator: T): {
240244
type: InputProp["type"];
241245
isArray: boolean;
242246
isOptional: boolean;
247+
min?: number;
248+
max?: number;
243249
} {
244250
let resolvedType = fieldValidator;
245251
let isArray = false;
@@ -261,7 +267,20 @@ function getInputInfo<T extends ZodType>(fieldValidator: T): {
261267

262268
const type = getInputType(resolvedType);
263269

264-
return { type, isArray, isOptional };
270+
const result: ReturnType<typeof getInputInfo> = { type, isArray, isOptional };
271+
272+
if (type === "number" && resolvedType instanceof ZodNumber) {
273+
for (const check of resolvedType._def.checks) {
274+
if (check.kind === "min") {
275+
result.min = check.value + (check.inclusive ? 0 : 1);
276+
}
277+
if (check.kind === "max") {
278+
result.max = check.value - (check.inclusive ? 0 : 1);
279+
}
280+
}
281+
}
282+
283+
return result;
265284
}
266285

267286
export async function validateForm<T extends ZodRawShape>({

0 commit comments

Comments
 (0)