This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Array, Duration, Effect, Equivalence, flow, identity, Option, ParseResult, Pipeable, Schema, Stream, Subscribable, SubscriptionRef } from "effect"
|
||||
import { Array, Duration, Effect, Equivalence, flow, identity, Option, ParseResult, Pipeable, Schema, Scope, Stream, Subscribable, SubscriptionRef } from "effect"
|
||||
import type { NoSuchElementException } from "effect/Cause"
|
||||
import * as React from "react"
|
||||
import { Hooks } from "./hooks/index.js"
|
||||
@@ -53,7 +53,7 @@ extends Pipeable.Class() implements Form<A, I, R> {
|
||||
|
||||
|
||||
export namespace make {
|
||||
export interface Options<in out A, in out I = A, out R = never> {
|
||||
export interface Options<in out A, in out I, out R> {
|
||||
readonly schema: Schema.Schema<A, I, R>
|
||||
readonly initialEncodedValue: NoInfer<I>
|
||||
}
|
||||
@@ -70,6 +70,39 @@ export const make: {
|
||||
)
|
||||
})
|
||||
|
||||
const run = <A, I, R>(self: Form<A, I, R>) => Stream.runForEach(
|
||||
self.encodedValueRef.changes,
|
||||
flow(
|
||||
Schema.decode(self.schema),
|
||||
Effect.andThen(v => SubscriptionRef.set(self.valueRef, Option.some(v))),
|
||||
Effect.andThen(SubscriptionRef.set(self.errorRef, Option.none())),
|
||||
Effect.catchTag("ParseError", e => SubscriptionRef.set(self.errorRef, Option.some(e)))
|
||||
),
|
||||
)
|
||||
|
||||
export namespace service {
|
||||
export interface Options<in out A, in out I, out R> extends make.Options<A, I, R> {}
|
||||
}
|
||||
|
||||
export const service = <A, I = A, R = never>(
|
||||
options: service.Options<A, I, R>
|
||||
): Effect.Effect<Form<A, I, R>, never, R | Scope.Scope> => Effect.tap(
|
||||
make(options),
|
||||
form => Effect.forkScoped(run(form)),
|
||||
)
|
||||
|
||||
export namespace useForm {
|
||||
export interface Options<in out A, in out I, out R> extends make.Options<A, I, R> {}
|
||||
}
|
||||
|
||||
export const useForm: {
|
||||
<A, I = A, R = never>(options: service.Options<A, I, R>): Effect.Effect<Form<A, I, R>, never, R | Scope.Scope>
|
||||
} = Effect.fnUntraced(function* <A, I = A, R = never>(options: service.Options<A, I, R>) {
|
||||
const form = yield* Hooks.useOnce(() => make(options))
|
||||
yield* Hooks.useFork(() => run(form), [form])
|
||||
return form
|
||||
})
|
||||
|
||||
|
||||
export namespace useInput {
|
||||
export interface Options {
|
||||
@@ -114,13 +147,7 @@ export const useInput: {
|
||||
|
||||
internalValue => self.encodedValueRef.pipe(
|
||||
Effect.andThen(encodedValue => PropertyPath.immutableSet(encodedValue, path, internalValue)),
|
||||
Effect.tap(encodedValue => SubscriptionRef.set(self.encodedValueRef, encodedValue)),
|
||||
Effect.andThen(flow(
|
||||
Schema.decode(self.schema),
|
||||
Effect.andThen(v => SubscriptionRef.set(self.valueRef, Option.some(v))),
|
||||
Effect.andThen(SubscriptionRef.set(self.errorRef, Option.none())),
|
||||
Effect.catchTag("ParseError", e => SubscriptionRef.set(self.errorRef, Option.some(e)))
|
||||
)),
|
||||
Effect.andThen(encodedValue => SubscriptionRef.set(self.encodedValueRef, encodedValue)),
|
||||
),
|
||||
), [internalValueRef, self, ...path])
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ const RegisterFormSchema = Schema.Struct({
|
||||
})
|
||||
|
||||
class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", {
|
||||
scoped: Form.make({
|
||||
scoped: Form.service({
|
||||
schema: RegisterFormSchema,
|
||||
initialEncodedValue: { email: "", password: "" },
|
||||
})
|
||||
@@ -64,7 +64,7 @@ class RegisterPage extends Component.makeUntraced(function* RegisterPage() {
|
||||
|
||||
|
||||
const RegisterRoute = Component.makeUntraced(function* RegisterRoute() {
|
||||
const context = yield* useContext(RegisterForm.Default)
|
||||
const context = yield* useContext(RegisterForm.Default, { finalizerExecutionMode: "fork" })
|
||||
const RegisterRouteFC = yield* Effect.provide(RegisterPage, context)
|
||||
|
||||
return <RegisterRouteFC />
|
||||
|
||||
Reference in New Issue
Block a user