chore: add Storybook stories for MyForm component
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
import React from "react";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
|
||||
export function MyForm() {
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
username: "",
|
||||
age: "",
|
||||
password: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
console.log("Form submitted successfully:", value);
|
||||
alert(JSON.stringify(value, null, 2));
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
maxWidth: "400px",
|
||||
margin: "20px auto",
|
||||
fontFamily: "sans-serif",
|
||||
}}
|
||||
>
|
||||
<h2>Registration Form (TanStack Form)</h2>
|
||||
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<form.Field
|
||||
name="username"
|
||||
validators={{
|
||||
onChange: ({ value }) => {
|
||||
if (!value) return "Full name is required";
|
||||
if (!/^[a-zA-Za-z\s]+$/.test(value)) {
|
||||
return "Please enter letters only";
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
}}
|
||||
>
|
||||
{(field) => (
|
||||
<div style={{ marginBottom: "15px" }}>
|
||||
<label
|
||||
htmlFor={field.name}
|
||||
style={{ display: "block", marginBottom: "5px" }}
|
||||
>
|
||||
Full Name (Letters only):
|
||||
</label>
|
||||
<input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
style={{
|
||||
width: "100%",
|
||||
padding: "8px",
|
||||
boxSizing: "border-box",
|
||||
}}
|
||||
/>
|
||||
{field.state.meta.errors.length > 0 && (
|
||||
<span style={{ color: "red", fontSize: "12px" }}>
|
||||
{field.state.meta.errors.join(", ")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</form.Field>
|
||||
|
||||
<form.Field
|
||||
name="age"
|
||||
validators={{
|
||||
onChange: ({ value }) => {
|
||||
if (!value) return "Age is required";
|
||||
if (isNaN(Number(value))) {
|
||||
return "Please enter numbers only";
|
||||
}
|
||||
if (Number(value) < 18) {
|
||||
return "Age must be at least 18";
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
}}
|
||||
>
|
||||
{(field) => (
|
||||
<div style={{ marginBottom: "15px" }}>
|
||||
<label
|
||||
htmlFor={field.name}
|
||||
style={{ display: "block", marginBottom: "5px" }}
|
||||
>
|
||||
Age (Numbers only):
|
||||
</label>
|
||||
<input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
type="number"
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
style={{
|
||||
width: "100%",
|
||||
padding: "8px",
|
||||
boxSizing: "border-box",
|
||||
}}
|
||||
/>
|
||||
{field.state.meta.errors.length > 0 && (
|
||||
<span style={{ color: "red", fontSize: "12px" }}>
|
||||
{field.state.meta.errors.join(", ")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</form.Field>
|
||||
|
||||
<form.Field
|
||||
name="password"
|
||||
validators={{
|
||||
onChange: ({ value }) => {
|
||||
if (!value) return "Password is required";
|
||||
if (value.length < 8) {
|
||||
return "Password must be at least 8 characters long";
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
}}
|
||||
>
|
||||
{(field) => (
|
||||
<div style={{ marginBottom: "15px" }}>
|
||||
<label
|
||||
htmlFor={field.name}
|
||||
style={{ display: "block", marginBottom: "5px" }}
|
||||
>
|
||||
Password:
|
||||
</label>
|
||||
<input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
type="password"
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
style={{
|
||||
width: "100%",
|
||||
padding: "8px",
|
||||
boxSizing: "border-box",
|
||||
}}
|
||||
/>
|
||||
{field.state.meta.errors.length > 0 && (
|
||||
<span style={{ color: "red", fontSize: "12px" }}>
|
||||
{field.state.meta.errors.join(", ")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</form.Field>
|
||||
|
||||
<form.Subscribe
|
||||
selector={(state) => [state.canSubmit, state.isSubmitting]}
|
||||
>
|
||||
{([canSubmit, isSubmitting]) => (
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!canSubmit}
|
||||
style={{
|
||||
width: "100%",
|
||||
padding: "10px",
|
||||
backgroundColor: canSubmit ? "#007bff" : "#ccc",
|
||||
color: "white",
|
||||
border: "none",
|
||||
borderRadius: "4px",
|
||||
cursor: canSubmit ? "pointer" : "not-allowed",
|
||||
}}
|
||||
>
|
||||
{isSubmitting ? "Submitting..." : "Sign Up"}
|
||||
</button>
|
||||
)}
|
||||
</form.Subscribe>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user