From a11180d03eb288c69c3976dd303a4d4ebed6b804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 27 Aug 2025 06:11:15 +0200 Subject: [PATCH] Form tests --- packages/effect-fc/src/Form.ts | 1 + packages/example/src/routes/form.tsx | 28 ++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/effect-fc/src/Form.ts b/packages/effect-fc/src/Form.ts index 52542cc..e0ab185 100644 --- a/packages/effect-fc/src/Form.ts +++ b/packages/effect-fc/src/Form.ts @@ -34,6 +34,7 @@ export namespace Form { export interface Result { readonly value: I readonly setValue: React.Dispatch> + readonly issues: readonly ParseResult.ArrayFormatterIssue[] } } } diff --git a/packages/example/src/routes/form.tsx b/packages/example/src/routes/form.tsx index 5a2880a..2cfb956 100644 --- a/packages/example/src/routes/form.tsx +++ b/packages/example/src/routes/form.tsx @@ -1,20 +1,20 @@ import { runtime } from "@/runtime" -import { Container, Flex, TextField } from "@radix-ui/themes" +import { Callout, Container, Flex, TextField } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" -import { Console, Effect, Schema, Stream } from "effect" +import { Array, Console, Effect, Option, Schema, Stream } from "effect" import { Component, Form } from "effect-fc" import { useContext, useFork } from "effect-fc/hooks" const LoginFormSchema = Schema.Struct({ email: Schema.String, - password: Schema.String, + password: Schema.String.pipe(Schema.minLength(3)), }) class LoginForm extends Effect.Service()("LoginForm", { scoped: Form.make({ schema: LoginFormSchema, - initialValue: { email: "", password: "" }, + initialValue: { email: "", password: "xxx" }, }) }) {} @@ -33,10 +33,30 @@ class LoginFormComponent extends Component.makeUntraced(function* LoginFormCompo onChange={e => emailInput.setValue(e.target.value)} /> + {Option.match(Array.head(emailInput.issues), { + onSome: issue => ( + + {issue.message} + + ), + + onNone: () => <>, + })} + passwordInput.setValue(e.target.value)} /> + + {Option.match(Array.head(passwordInput.issues), { + onSome: issue => ( + + {issue.message} + + ), + + onNone: () => <>, + })} )