This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import * as AsyncData from "@typed/async-data"
|
||||
import { Array, Duration, Effect, Equal, Exit, flow, identity, Option, ParseResult, pipe, Pipeable, Ref, Schema, Scope, Stream, Subscribable, SubscriptionRef } from "effect"
|
||||
import { Array, Cause, Chunk, Duration, Effect, Equal, Exit, Fiber, flow, identity, Option, ParseResult, pipe, Pipeable, Ref, Schema, Scope, Stream, Subscribable, SubscriptionRef } from "effect"
|
||||
import type { NoSuchElementException } from "effect/Cause"
|
||||
import * as React from "react"
|
||||
import { Hooks } from "./hooks/index.js"
|
||||
@@ -19,7 +19,7 @@ extends Pipeable.Pipeable {
|
||||
readonly valueRef: SubscriptionRef.SubscriptionRef<Option.Option<A>>,
|
||||
readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>,
|
||||
readonly errorRef: SubscriptionRef.SubscriptionRef<Option.Option<ParseResult.ParseError>>,
|
||||
readonly isValidatingRef: SubscriptionRef.SubscriptionRef<boolean>
|
||||
readonly validationFiberRef: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<void, never>>>
|
||||
readonly submitStateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<SA, SE>>,
|
||||
|
||||
readonly canSubmitSubscribable: Subscribable.Subscribable<boolean>
|
||||
@@ -36,7 +36,7 @@ extends Pipeable.Class() implements Form<A, I, R, SA, SE, SR> {
|
||||
readonly valueRef: SubscriptionRef.SubscriptionRef<Option.Option<A>>,
|
||||
readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>,
|
||||
readonly errorRef: SubscriptionRef.SubscriptionRef<Option.Option<ParseResult.ParseError>>,
|
||||
readonly isValidatingRef: SubscriptionRef.SubscriptionRef<boolean>,
|
||||
readonly validationFiberRef: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<void, never>>>,
|
||||
readonly submitStateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<SA, SE>>,
|
||||
|
||||
readonly canSubmitSubscribable: Subscribable.Subscribable<boolean>,
|
||||
@@ -62,7 +62,7 @@ export const make: {
|
||||
) {
|
||||
const valueRef = yield* SubscriptionRef.make(Option.none<A>())
|
||||
const errorRef = yield* SubscriptionRef.make(Option.none<ParseResult.ParseError>())
|
||||
const isValidatingRef = yield* SubscriptionRef.make(false)
|
||||
const validationFiberRef = yield* SubscriptionRef.make(Option.none<Fiber.Fiber<void, never>>())
|
||||
const submitStateRef = yield* SubscriptionRef.make(AsyncData.noData<SA, SE>())
|
||||
|
||||
return new FormImpl(
|
||||
@@ -72,25 +72,25 @@ export const make: {
|
||||
valueRef,
|
||||
yield* SubscriptionRef.make(options.initialEncodedValue),
|
||||
errorRef,
|
||||
isValidatingRef,
|
||||
validationFiberRef,
|
||||
submitStateRef,
|
||||
|
||||
pipe(
|
||||
<A>([value, error, isValidating, submitState]: readonly [
|
||||
<A>([value, error, validationFiber, submitState]: readonly [
|
||||
Option.Option<A>,
|
||||
Option.Option<ParseResult.ParseError>,
|
||||
boolean,
|
||||
Option.Option<Fiber.Fiber<void, never>>,
|
||||
AsyncData.AsyncData<SA, SE>,
|
||||
]) => Option.isSome(value) && Option.isNone(error) && !isValidating && !AsyncData.isLoading(submitState),
|
||||
]) => Option.isSome(value) && Option.isNone(error) && Option.isNone(validationFiber) && !AsyncData.isLoading(submitState),
|
||||
|
||||
filter => SubscribableInternal.make({
|
||||
get: Effect.map(Effect.all([valueRef, errorRef, isValidatingRef, submitStateRef]), filter),
|
||||
get: Effect.map(Effect.all([valueRef, errorRef, validationFiberRef, submitStateRef]), filter),
|
||||
get changes() {
|
||||
return Stream.map(
|
||||
Stream.zipLatestAll(
|
||||
valueRef.changes,
|
||||
errorRef.changes,
|
||||
isValidatingRef.changes,
|
||||
validationFiberRef.changes,
|
||||
submitStateRef.changes,
|
||||
),
|
||||
filter,
|
||||
@@ -103,14 +103,38 @@ export const make: {
|
||||
|
||||
export const run = <A, I, R, SA, SE, SR>(
|
||||
self: Form<A, I, R, SA, SE, SR>
|
||||
): Effect.Effect<void, never, R> => Stream.runForEach(
|
||||
): Effect.Effect<void, never, Scope.Scope | R> => Stream.runForEach(
|
||||
self.encodedValueRef.changes,
|
||||
encodedValue => SubscriptionRef.set(self.isValidatingRef, true).pipe(
|
||||
encodedValue => self.validationFiberRef.pipe(
|
||||
Effect.andThen(Option.match({
|
||||
onSome: Fiber.interrupt,
|
||||
onNone: () => Effect.void,
|
||||
})),
|
||||
Effect.andThen(
|
||||
Effect.addFinalizer(() => SubscriptionRef.set(self.validationFiberRef, Option.none())).pipe(
|
||||
Effect.andThen(Schema.decode(self.schema, { errors: "all" })(encodedValue)),
|
||||
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(SubscriptionRef.set(self.isValidatingRef, false)),
|
||||
Effect.exit,
|
||||
Effect.andThen(flow(
|
||||
Exit.matchEffect({
|
||||
onSuccess: v => Effect.andThen(
|
||||
SubscriptionRef.set(self.valueRef, Option.some(v)),
|
||||
SubscriptionRef.set(self.errorRef, Option.none()),
|
||||
),
|
||||
onFailure: c => Option.match(
|
||||
Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError"),
|
||||
{
|
||||
onSome: e => SubscriptionRef.set(self.errorRef, Option.some(e)),
|
||||
onNone: () => Effect.void,
|
||||
},
|
||||
),
|
||||
}),
|
||||
Effect.uninterruptible,
|
||||
)),
|
||||
Effect.scoped,
|
||||
Effect.forkScoped,
|
||||
)
|
||||
),
|
||||
Effect.andThen(fiber => SubscriptionRef.set(self.validationFiberRef, Option.some(fiber)))
|
||||
),
|
||||
)
|
||||
|
||||
@@ -177,7 +201,13 @@ export const field = <A, I, R, SA, SE, SR, const P extends PropertyPath.Paths<No
|
||||
}),
|
||||
),
|
||||
|
||||
self.isValidatingRef,
|
||||
pipe(
|
||||
Option.isSome,
|
||||
filter => SubscribableInternal.make({
|
||||
get: Effect.map(self.validationFiberRef.get, filter),
|
||||
get changes() { return Stream.map(self.validationFiberRef.changes, filter) },
|
||||
}),
|
||||
),
|
||||
|
||||
pipe(
|
||||
AsyncData.isLoading,
|
||||
|
||||
Reference in New Issue
Block a user