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 type { NoSuchElementException } from "effect/Cause"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { Hooks } from "./hooks/index.js"
|
import { Hooks } from "./hooks/index.js"
|
||||||
@@ -53,7 +53,7 @@ extends Pipeable.Class() implements Form<A, I, R> {
|
|||||||
|
|
||||||
|
|
||||||
export namespace make {
|
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 schema: Schema.Schema<A, I, R>
|
||||||
readonly initialEncodedValue: NoInfer<I>
|
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 namespace useInput {
|
||||||
export interface Options {
|
export interface Options {
|
||||||
@@ -114,13 +147,7 @@ export const useInput: {
|
|||||||
|
|
||||||
internalValue => self.encodedValueRef.pipe(
|
internalValue => self.encodedValueRef.pipe(
|
||||||
Effect.andThen(encodedValue => PropertyPath.immutableSet(encodedValue, path, internalValue)),
|
Effect.andThen(encodedValue => PropertyPath.immutableSet(encodedValue, path, internalValue)),
|
||||||
Effect.tap(encodedValue => SubscriptionRef.set(self.encodedValueRef, encodedValue)),
|
Effect.andThen(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)))
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
), [internalValueRef, self, ...path])
|
), [internalValueRef, self, ...path])
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const RegisterFormSchema = Schema.Struct({
|
|||||||
})
|
})
|
||||||
|
|
||||||
class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", {
|
class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", {
|
||||||
scoped: Form.make({
|
scoped: Form.service({
|
||||||
schema: RegisterFormSchema,
|
schema: RegisterFormSchema,
|
||||||
initialEncodedValue: { email: "", password: "" },
|
initialEncodedValue: { email: "", password: "" },
|
||||||
})
|
})
|
||||||
@@ -64,7 +64,7 @@ class RegisterPage extends Component.makeUntraced(function* RegisterPage() {
|
|||||||
|
|
||||||
|
|
||||||
const RegisterRoute = Component.makeUntraced(function* RegisterRoute() {
|
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)
|
const RegisterRouteFC = yield* Effect.provide(RegisterPage, context)
|
||||||
|
|
||||||
return <RegisterRouteFC />
|
return <RegisterRouteFC />
|
||||||
|
|||||||
Reference in New Issue
Block a user