diff --git a/web/src/lib/optimistic.svelte.ts b/web/src/lib/optimistic.svelte.ts index 012c0725f..0ffabdac4 100644 --- a/web/src/lib/optimistic.svelte.ts +++ b/web/src/lib/optimistic.svelte.ts @@ -66,7 +66,8 @@ export interface OptimisticRelation { readonly active: boolean; readonly loading: boolean; readonly failed: boolean; - begin(): void; + /** `intent` shows the outcome straight away and holds it until the write settles */ + begin(intent?: boolean): void; created(rkey: string): void; deleted(): void; fail(): void; @@ -77,12 +78,13 @@ export const createOptimisticRelation = ( options: OptimisticRelationOptions ): OptimisticRelation => { let status = $state<"idle" | "loading" | "failed">("idle"); + let pending = $state(null); let committed = $state(null); const currentKey = $derived(options.key()); const loaded = $derived(options.loadedRkey()); const rkey = $derived(committed?.key === currentKey ? committed.rkey : (loaded ?? null)); const known = $derived(loaded !== undefined || committed?.key === currentKey); - const active = $derived(rkey !== null); + const active = $derived(pending ?? rkey !== null); $effect(() => { if (committed === null) return; @@ -94,6 +96,7 @@ export const createOptimisticRelation = ( const set = (next: string | null): void => { status = "idle"; + pending = null; committed = { key: currentKey, rkey: next }; }; @@ -113,13 +116,15 @@ export const createOptimisticRelation = ( get failed() { return status === "failed"; }, - begin() { + begin(intent) { status = "loading"; + pending = intent ?? null; }, created: set, deleted: () => set(null), fail() { status = "failed"; + pending = null; }, resetFailure() { status = "idle";