diff --git a/packages/effect-fc/src/Form.ts b/packages/effect-fc/src/Form.ts
index ccd02dc..e490bce 100644
--- a/packages/effect-fc/src/Form.ts
+++ b/packages/effect-fc/src/Form.ts
@@ -155,54 +155,55 @@ const run = (self: Form) => Stream.run
)
-export const field: {
- >>(
- self: Form,
- path: P,
- ): Effect.Effect, PropertyPath.ValueFromPath>>
-} = Effect.fnUntraced(function* >>(
+export const field = >>(
self: Form,
path: P,
-) {
- return new FormFieldImpl(
- pipe(
- (v: Option.Option) => Option.match(v, {
- onSome: PropertyPath.get(path),
- onNone: () => Option.none(),
- }),
- filter => SubscribableInternal.make({
- get: Effect.flatMap(self.valueRef, filter),
- get changes() { return Stream.flatMap(self.valueRef.changes, filter) },
- }),
- ),
+): FormField, PropertyPath.ValueFromPath> => new FormFieldImpl(
+ pipe(
+ Option.match({
+ onSome: (v: A) => Option.map(PropertyPath.get(v, path), Option.some),
+ onNone: () => Option.some(Option.none()),
+ }),
+ filter => SubscribableInternal.make({
+ get: Effect.flatMap(self.valueRef, filter),
+ get changes() { return Stream.flatMap(self.valueRef.changes, filter) },
+ }),
+ ),
- SubscriptionSubRef.makeFromPath(self.encodedValueRef, path),
+ SubscriptionSubRef.makeFromPath(self.encodedValueRef, path),
- pipe(
- Option.match({
- onSome: (v: ParseResult.ParseError) => Effect.andThen(
- ParseResult.ArrayFormatter.formatError(v),
- Array.filter(issue => PropertyPath.equivalence(issue.path, path)),
- ),
- onNone: () => Effect.succeed([]),
- }),
- filter => SubscribableInternal.make({
- get: Effect.flatMap(self.errorRef.get, filter),
- get changes() { return Stream.flatMap(self.errorRef.changes, filter) },
- }),
- ),
+ pipe(
+ Option.match({
+ onSome: (v: ParseResult.ParseError) => Effect.andThen(
+ ParseResult.ArrayFormatter.formatError(v),
+ Array.filter(issue => PropertyPath.equivalence(issue.path, path)),
+ ),
+ onNone: () => Effect.succeed([]),
+ }),
+ filter => SubscribableInternal.make({
+ get: Effect.flatMap(self.errorRef.get, filter),
+ get changes() { return Stream.flatMap(self.errorRef.changes, filter) },
+ }),
+ ),
- self.isValidatingRef,
+ self.isValidatingRef,
- pipe(
- AsyncData.isLoading,
- filter => SubscribableInternal.make({
- get: Effect.map(self.submitStateRef, filter),
- get changes() { return Stream.map(self.submitStateRef.changes, filter) },
- }),
- ),
- )
-})
+ pipe(
+ AsyncData.isLoading,
+ filter => SubscribableInternal.make({
+ get: Effect.map(self.submitStateRef, filter),
+ get changes() { return Stream.map(self.submitStateRef.changes, filter) },
+ }),
+ ),
+)
+
+export const useField = >>(
+ self: Form,
+ path: P,
+): FormField, PropertyPath.ValueFromPath> => React.useMemo(
+ () => field(self, path),
+ [self, ...path],
+)
export namespace useInput {
diff --git a/packages/example/src/routes/form.tsx b/packages/example/src/routes/form.tsx
index 569d26c..127019f 100644
--- a/packages/example/src/routes/form.tsx
+++ b/packages/example/src/routes/form.tsx
@@ -25,13 +25,16 @@ class RegisterForm extends Effect.Service()("RegisterForm", {
scoped: Form.service({
schema: RegisterFormSchema,
initialEncodedValue: { email: "", password: "" },
+ submit: () => Effect.void,
})
}) {}
class RegisterPage extends Component.makeUntraced("RegisterPage")(function*() {
const form = yield* RegisterForm
- const emailInput = yield* Form.useInput(form, ["email"], { debounce: "200 millis" })
- const passwordInput = yield* Form.useInput(form, ["password"], { debounce: "200 millis" })
+ const emailField = Form.useField(form, ["email"])
+ const passwordField = Form.useField(form, ["password"])
+ const emailInput = yield* Form.useInput(emailField, { debounce: "200 millis" })
+ const passwordInput = yield* Form.useInput(passwordField, { debounce: "200 millis" })
const [canSubmit] = yield* useSubscribables(form.canSubmitSubscribable)