diff --git a/.changeset/unlucky-gorillas-learn.md b/.changeset/unlucky-gorillas-learn.md new file mode 100644 index 0000000..c1bdde6 --- /dev/null +++ b/.changeset/unlucky-gorillas-learn.md @@ -0,0 +1,5 @@ +--- +"simple-stack-form": patch +--- + +Add `min` and `max` input props to number input if present on schema diff --git a/examples/playground/src/components/react/Signup.tsx b/examples/playground/src/components/react/Signup.tsx index e0bf8a2..091da02 100644 --- a/examples/playground/src/components/react/Signup.tsx +++ b/examples/playground/src/components/react/Signup.tsx @@ -14,6 +14,7 @@ export const signup = createForm({ return s !== "admin"; }), email: z.string().email().optional(), + coffees: z.number().lt(10).min(2), optIn: z.boolean().optional(), }); @@ -35,6 +36,10 @@ export default function Signup({ + + + + diff --git a/packages/form/src/module.ts b/packages/form/src/module.ts index 2dbf6dc..77b51fe 100644 --- a/packages/form/src/module.ts +++ b/packages/form/src/module.ts @@ -3,7 +3,6 @@ import { ZodArray, ZodBoolean, type ZodError, - ZodLiteral, ZodNullable, ZodNumber, ZodObject, @@ -11,7 +10,6 @@ import { type ZodRawShape, ZodString, type ZodType, - ZodUnion, z, } from "zod"; @@ -23,8 +21,10 @@ export type FieldErrors< export type InputProp = { "aria-required": boolean; name: string; - type: "text" | "number" | "checkbox" | "email"; -}; +} & ( + | { type: "text" | "checkbox" | "email" } + | { type: "number"; min?: number; max?: number } +); export const formNameInputProps = { type: "hidden", @@ -207,11 +207,15 @@ function getInputProp( fieldValidator: T, name: string | number | symbol, ) { + const inputInfo = getInputInfo(fieldValidator); + const inputProp: InputProp = { name: String(name), "aria-required": !fieldValidator.isOptional() && !fieldValidator.isNullable(), - type: getInputInfo(fieldValidator).type, + type: inputInfo.type, + min: inputInfo.min, + max: inputInfo.max, }; return inputProp; @@ -240,6 +244,8 @@ function getInputInfo(fieldValidator: T): { type: InputProp["type"]; isArray: boolean; isOptional: boolean; + min?: number; + max?: number; } { let resolvedType = fieldValidator; let isArray = false; @@ -261,7 +267,20 @@ function getInputInfo(fieldValidator: T): { const type = getInputType(resolvedType); - return { type, isArray, isOptional }; + const result: ReturnType = { type, isArray, isOptional }; + + if (type === "number" && resolvedType instanceof ZodNumber) { + for (const check of resolvedType._def.checks) { + if (check.kind === "min") { + result.min = check.value + (check.inclusive ? 0 : 1); + } + if (check.kind === "max") { + result.max = check.value - (check.inclusive ? 0 : 1); + } + } + } + + return result; } export async function validateForm({