0.1.4 #5
@@ -1,5 +1,5 @@
|
|||||||
import * as AsyncData from "@typed/async-data"
|
import * as AsyncData from "@typed/async-data"
|
||||||
import { Array, Duration, Effect, Equal, Equivalence, Exit, flow, identity, Option, ParseResult, pipe, Pipeable, Ref, Schema, Scope, Stream, Subscribable, SubscriptionRef } from "effect"
|
import { Array, Duration, Effect, Equal, Exit, flow, identity, Option, ParseResult, pipe, Pipeable, Ref, 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"
|
||||||
@@ -289,40 +289,45 @@ export const useInput: {
|
|||||||
Stream.runForEach(
|
Stream.runForEach(
|
||||||
internalValueRef.changes.pipe(
|
internalValueRef.changes.pipe(
|
||||||
Stream.drop(1),
|
Stream.drop(1),
|
||||||
Stream.changesWith(Equivalence.strict()),
|
Stream.changesWith(Equal.equivalence()),
|
||||||
options?.debounce ? Stream.debounce(options.debounce) : identity,
|
options?.debounce ? Stream.debounce(options.debounce) : identity,
|
||||||
),
|
),
|
||||||
internalValue => Ref.set(field.encodedValueRef, internalValue),
|
internalValue => Ref.set(field.encodedValueRef, internalValue),
|
||||||
),
|
),
|
||||||
], { concurrency: "unbounded" }), [field, internalValueRef])
|
], { concurrency: "unbounded" }), [field, internalValueRef, options?.debounce])
|
||||||
|
|
||||||
return { value, setValue, issues }
|
return { value, setValue, issues }
|
||||||
})
|
})
|
||||||
|
|
||||||
export namespace useOptionalInput {
|
export namespace useOptionalInput {
|
||||||
export interface Options<I extends Option.Option<any>> extends useInput.Options {
|
export interface Options<I> extends useInput.Options {
|
||||||
readonly defaultValue: Option.Option.Value<I>
|
readonly defaultValue: I
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Result<T> extends useInput.Result<T> {}
|
export interface Result<T> extends useInput.Result<T> {
|
||||||
|
readonly enabled: boolean
|
||||||
|
readonly setEnabled: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useOptionalInput: {
|
export const useOptionalInput: {
|
||||||
<A, I extends Option.Option<any>>(
|
<A, I>(
|
||||||
field: FormField<A, I>,
|
field: FormField<A, Option.Option<I>>,
|
||||||
options: useOptionalInput.Options<I>,
|
options: useOptionalInput.Options<I>,
|
||||||
): Effect.Effect<useOptionalInput.Result<Option.Option.Value<I>>, NoSuchElementException>
|
): Effect.Effect<useOptionalInput.Result<I>, NoSuchElementException>
|
||||||
} = Effect.fnUntraced(function* <A, I extends Option.Option<any>>(
|
} = Effect.fnUntraced(function* <A, I>(
|
||||||
field: FormField<A, I>,
|
field: FormField<A, Option.Option<I>>,
|
||||||
options: useOptionalInput.Options<I>,
|
options: useOptionalInput.Options<I>,
|
||||||
) {
|
) {
|
||||||
const internalValueRef = yield* Hooks.useMemo(() => field.encodedValueRef.pipe(
|
const [enabledRef, internalValueRef] = yield* Hooks.useMemo(() => Effect.andThen(
|
||||||
Effect.map(Option.match({
|
field.encodedValueRef,
|
||||||
onSome: identity,
|
Option.match({
|
||||||
onNone: () => options.defaultValue,
|
onSome: v => Effect.all([SubscriptionRef.make(true), SubscriptionRef.make(v)]),
|
||||||
})),
|
onNone: () => Effect.all([SubscriptionRef.make(false), SubscriptionRef.make(options.defaultValue)]),
|
||||||
Effect.andThen(SubscriptionRef.make),
|
}),
|
||||||
), [field])
|
), [field])
|
||||||
|
|
||||||
|
const [enabled, setEnabled] = yield* Hooks.useRefState(enabledRef)
|
||||||
const [value, setValue] = yield* Hooks.useRefState(internalValueRef)
|
const [value, setValue] = yield* Hooks.useRefState(internalValueRef)
|
||||||
const [issues] = yield* Hooks.useSubscribables(field.issuesSubscribable)
|
const [issues] = yield* Hooks.useSubscribables(field.issuesSubscribable)
|
||||||
|
|
||||||
@@ -336,14 +341,15 @@ export const useOptionalInput: {
|
|||||||
),
|
),
|
||||||
|
|
||||||
Stream.runForEach(
|
Stream.runForEach(
|
||||||
internalValueRef.changes.pipe(
|
enabledRef.changes.pipe(
|
||||||
|
Stream.zipLatest(internalValueRef.changes),
|
||||||
Stream.drop(1),
|
Stream.drop(1),
|
||||||
Stream.changesWith(Equivalence.strict()),
|
Stream.changesWith(Equal.equivalence()),
|
||||||
options?.debounce ? Stream.debounce(options.debounce) : identity,
|
options?.debounce ? Stream.debounce(options.debounce) : identity,
|
||||||
),
|
),
|
||||||
internalValue => Ref.set(field.encodedValueRef, internalValue),
|
([enabled, internalValue]) => Ref.set(field.encodedValueRef, enabled ? Option.some(internalValue) : Option.none()),
|
||||||
),
|
),
|
||||||
], { concurrency: "unbounded" }), [field, internalValueRef])
|
], { concurrency: "unbounded" }), [field, enabledRef, internalValueRef, options.debounce])
|
||||||
|
|
||||||
return { value, setValue, issues }
|
return { enabled, setEnabled, value, setValue, issues }
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user