import { Effect, Equivalence, Option, PubSub, Ref, type Scope, Stream } from "effect"
import * as React from "react"
import * as Component from "./Component.js"
export const useStream: {
(
stream: Stream.Stream
): Effect.Effect, never, R>
, E, R>(
stream: Stream.Stream,
initialValue: A,
): Effect.Effect, never, R>
} = Effect.fnUntraced(function* , E, R>(
stream: Stream.Stream,
initialValue?: A,
) {
const [reactStateValue, setReactStateValue] = React.useState(() => initialValue
? Option.some(initialValue)
: Option.none()
)
yield* Component.useReactEffect(() => Effect.forkScoped(
Stream.runForEach(
Stream.changesWith(stream, Equivalence.strict()),
v => Effect.sync(() => setReactStateValue(Option.some(v))),
)
), [stream])
return reactStateValue as Option.Some
})
export const useStreamFromReactiveValues: {
(
values: A
): Effect.Effect, never, Scope.Scope>
} = Effect.fnUntraced(function* (values: A) {
const { latest, pubsub, stream } = yield* Component.useOnMount(() => Effect.Do.pipe(
Effect.bind("latest", () => Ref.make(values)),
Effect.bind("pubsub", () => Effect.acquireRelease(PubSub.unbounded(), PubSub.shutdown)),
Effect.let("stream", ({ latest, pubsub }) => latest.pipe(
Effect.flatMap(a => Effect.map(
Stream.fromPubSub(pubsub, { scoped: true }),
s => Stream.concat(Stream.make(a), s),
)),
Stream.unwrapScoped,
)),
))
yield* Component.useReactEffect(() => Ref.set(latest, values).pipe(
Effect.andThen(PubSub.publish(pubsub, values)),
Effect.unlessEffect(PubSub.isShutdown(pubsub)),
), values)
return stream
})
export * from "effect/Stream"