From 51f01ce402e1237dc1f7656226a25c92b3dcb6ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 27 Apr 2026 17:38:55 +0200 Subject: [PATCH] Fix --- packages/effect-fc/src/Form.ts | 28 +++++++++++++++------------- packages/effect-fc/src/Result.ts | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/effect-fc/src/Form.ts b/packages/effect-fc/src/Form.ts index 7a7a77b..f36ff90 100644 --- a/packages/effect-fc/src/Form.ts +++ b/packages/effect-fc/src/Form.ts @@ -209,7 +209,7 @@ export class SynchronizedFormImpl< readonly isValidating: Subscribable.Subscribable, readonly canCommit: Subscribable.Subscribable, - readonly isCommitting: Subscribable.Subscribable, + readonly isCommitting: Lens.Lens, readonly runSemaphore: Effect.Semaphore, ) { @@ -248,7 +248,13 @@ export class SynchronizedFormImpl< )).pipe( Effect.tap(fiber => Lens.set(this.validationFiber, Option.some(fiber))), Effect.andThen(Fiber.join), - Effect.tap(value => Lens.set(this.target, value)), + Effect.tap(value => Effect.onExit( + Effect.andThen( + Lens.set(this.isCommitting, true), + Lens.set(this.target, value), + ), + () => Lens.set(this.isCommitting, false), + )), Effect.forkScoped, ) ), @@ -280,12 +286,6 @@ export const isForm = (u: unknown): u is Form => Predicate.hasProperty(u, SubmittableFormTypeId) export const isSynchronizedForm = (u: unknown): u is SynchronizedForm => Predicate.hasProperty(u, SynchronizedFormTypeId) -const falseSubscribable: Subscribable.Subscribable = Subscribable.make({ - get: Effect.succeed(false), - changes: Stream.make(false), -}) - - export declare namespace makeSubmittable { export interface Options extends Mutation.make.Options< @@ -369,6 +369,7 @@ export const makeSynchronized = Effect.fnUntraced(function* ())) const issuesLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Array.empty())) const validationFiberLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none>())) + const isCommittingLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(false)) const initialEncodedValue = yield* Lens.get(options.target).pipe( Effect.flatMap(Schema.encode(options.schema, { errors: "all" })), ) @@ -385,14 +386,15 @@ export const makeSynchronized = Effect.fnUntraced(function* ( + Subscribable.zipLatestAll(valueLens, issuesLens, validationFiberLens, isCommittingLens), + ([value, issues, validationFiber, isCommitting]) => ( Option.isSome(value) && Array.isEmptyReadonlyArray(issues) && - Option.isNone(validationFiber) + Option.isNone(validationFiber) && + !isCommitting ), ), - falseSubscribable, + isCommittingLens, yield* Effect.makeSemaphore(1), ) @@ -565,7 +567,7 @@ export const useInput = Effect.fnUntraced(function*

Lens.set(form.encodedValue, internalValue), ), - ], { concurrency: "unbounded" })) + ], { concurrency: "unbounded", discard: true })) return internalValueLens }), [form, options?.debounce]) diff --git a/packages/effect-fc/src/Result.ts b/packages/effect-fc/src/Result.ts index 123e747..42b0c1a 100644 --- a/packages/effect-fc/src/Result.ts +++ b/packages/effect-fc/src/Result.ts @@ -1,4 +1,4 @@ -import { Cause, Context, Data, Effect, Equal, Exit, type Fiber, Hash, Layer, Match, pipe, Pipeable, Predicate, PubSub, Ref, type Scope, Stream, type Subscribable, SynchronizedRef } from "effect" +import { Cause, Context, Data, Effect, Equal, Exit, type Fiber, Hash, Layer, Match, Pipeable, Predicate, PubSub, pipe, Ref, type Scope, Stream, type Subscribable, SynchronizedRef } from "effect" import { Lens } from "effect-lens"