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"