Skip to content

Commit

Permalink
feat(form): email input type
Browse files Browse the repository at this point in the history
  • Loading branch information
dsnjunior committed Jan 16, 2024
1 parent a989559 commit f9699a6
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/stale-poems-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"simple-stack-form": patch
---

Set input type as email for inputs validating email values
5 changes: 5 additions & 0 deletions examples/playground/src/components/react/Signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const signup = createForm({
await sleep(400);
return s !== "admin";
}),
email: z.string().email().optional().or(z.literal("")),
optIn: z.boolean().optional(),
});

Expand All @@ -30,6 +31,10 @@ export default function Signup({
<label htmlFor={scope("name")}>Name</label>
<Input id={scope("name")} {...signup.inputProps.username} />
</FormGroup>
<FormGroup>
<label htmlFor={scope("email")}>Email</label>
<Input id={scope("email")} {...signup.inputProps.email} />
</FormGroup>
<FormGroup>
<label htmlFor={scope("optIn")}>Opt in</label>
<Input id={scope("optIn")} {...signup.inputProps.optIn} />
Expand Down
57 changes: 47 additions & 10 deletions packages/form/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ import {
ZodObject,
ZodOptional,
type ZodRawShape,
ZodString,
type ZodType,
z,
ZodUnion,
ZodLiteral,
} from "zod";

export type FormValidator = ZodRawShape;
Expand All @@ -20,7 +23,7 @@ export type FieldErrors<
export type InputProp = {
"aria-required": boolean;
name: string;
type: "text" | "number" | "checkbox";
type: "text" | "number" | "checkbox" | "email";
};

export const formNameInputProps = {
Expand Down Expand Up @@ -213,6 +216,48 @@ function getInputProp<T extends ZodType>(
return inputProp;
}

function getInputType<T extends ZodType>(fieldValidator: T): InputProp["type"] {
if (fieldValidator instanceof ZodBoolean) {
return "checkbox";
}

if (fieldValidator instanceof ZodNumber) {
return "number";
}

if (
fieldValidator instanceof ZodString &&
fieldValidator._def.checks.some((check) => check.kind === "email")
) {
return "email";
}

if (fieldValidator instanceof ZodOptional) {
return getInputType(fieldValidator._def.innerType);
}

if (fieldValidator instanceof ZodUnion) {
const types: InputProp["type"][] =
fieldValidator._def.options.map(getInputType);
if (!types[0]) {
return "text";
}
if (types.every((type) => type === types[0])) {
return types[0];
}
if (
types.length === 2 &&
fieldValidator._def.options[1] instanceof ZodLiteral &&
!fieldValidator._def.options[1].value
) {
// Handles specific case where email is optional. E.g.: `z.string().email().optional().or(z.literal(""))`
return types[0];
}
}

return "text";
}

function getInputInfo<T extends ZodType>(fieldValidator: T): {
type: InputProp["type"];
isArray: boolean;
Expand All @@ -236,15 +281,7 @@ function getInputInfo<T extends ZodType>(fieldValidator: T): {

// TODO: respect preprocess() wrappers

let type: InputProp["type"];

if (resolvedType instanceof ZodBoolean) {
type = "checkbox";
} else if (resolvedType instanceof ZodNumber) {
type = "number";
} else {
type = "text";
}
const type = getInputType(resolvedType);

return { type, isArray, isOptional };
}
Expand Down

0 comments on commit f9699a6

Please sign in to comment.