diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 801f7bb..acdf0e3 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -1,51 +1,27 @@ import { Context, Effect, Fiber, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" import React from "react" -import * as ReffuseReactContext from "./ReffuseReactContext.js" +import * as ReffuseContext from "./ReffuseContext.js" +import * as ReffuseRuntime from "./ReffuseRuntime.js" -export class Reffuse< - RuntimeR, - ContextR extends ParentContextR | OwnContextR, - OwnContextR, - ParentContextR = never, -> { - - readonly Context = React.createContext>(null!) - readonly Provider: ReffuseReactContext.Provider +export class Reffuse { constructor( - private readonly runtime: Runtime.Runtime, - parent?: Reffuse, - ) { - this.Provider = parent - ? ReffuseReactContext.makeNestedProvider(runtime, this.Context, parent) - : ReffuseReactContext.makeRootProvider(runtime, this.Context) - } - - extend() { - return new Reffuse< - RuntimeR, - ContextR | OwnContextR, - OwnContextR, - ContextR - >(this.runtime, this) - } + readonly contexts: readonly ReffuseContext.ReffuseContext[] + ) {} - useRuntime(): Runtime.Runtime { - return React.useContext(this.Context).runtime - } - - useContext(): Context.Context { - return React.useContext(this.Context).context + useContext(): Context.Context { + return ReffuseContext.useMergeAll(...this.contexts) } useRunSync() { - const { runtime, context } = React.useContext(this.Context) + const runtime = ReffuseRuntime.useRuntime() + const context = this.useContext() return React.useCallback(( - effect: Effect.Effect + effect: Effect.Effect ): A => effect.pipe( Effect.provide(context), Runtime.runSync(runtime), @@ -53,10 +29,11 @@ export class Reffuse< } useRunPromise() { - const { runtime, context } = React.useContext(this.Context) + const runtime = ReffuseRuntime.useRuntime() + const context = this.useContext() return React.useCallback(( - effect: Effect.Effect, + effect: Effect.Effect, options?: { readonly signal?: AbortSignal }, ): Promise => effect.pipe( Effect.provide(context), @@ -65,10 +42,11 @@ export class Reffuse< } useRunFork() { - const { runtime, context } = React.useContext(this.Context) + const runtime = ReffuseRuntime.useRuntime() + const context = this.useContext() return React.useCallback(( - effect: Effect.Effect, + effect: Effect.Effect, options?: Runtime.RunForkOptions, ): Fiber.RuntimeFiber => effect.pipe( Effect.provide(context), @@ -78,7 +56,7 @@ export class Reffuse< useMemo( - effect: Effect.Effect, + effect: Effect.Effect, deps?: React.DependencyList, options?: RenderOptions, ): A { @@ -104,7 +82,7 @@ export class Reffuse< // } useSuspense( - effect: Effect.Effect, + effect: Effect.Effect, options?: { readonly signal?: AbortSignal }, ): A { const runPromise = this.useRunPromise() @@ -112,7 +90,7 @@ export class Reffuse< } useFork( - effect: Effect.Effect, + effect: Effect.Effect, deps?: React.DependencyList, options?: Runtime.RunForkOptions & RenderOptions, ): void { @@ -136,7 +114,7 @@ export class Reffuse< ) } - useRefFromEffect(effect: Effect.Effect): SubscriptionRef.SubscriptionRef { + useRefFromEffect(effect: Effect.Effect): SubscriptionRef.SubscriptionRef { return this.useMemo( effect.pipe(Effect.flatMap(SubscriptionRef.make)), [], @@ -174,9 +152,9 @@ export interface RenderOptions { } -export const make = (): Reffuse => - new Reffuse(Runtime.defaultRuntime) - -export const makeWithRuntime = () => - (runtime: Runtime.Runtime): Reffuse => - new Reffuse(runtime) +export const make = < + const Contexts extends readonly ReffuseContext.ReffuseContext[] +>( + contexts: Contexts +): Reffuse<{ [K in keyof Contexts]: ReffuseContext.R }[number]> => + new Reffuse(contexts) diff --git a/packages/reffuse/src/ReffuseReactContext.tsx b/packages/reffuse/src/ReffuseReactContext.tsx deleted file mode 100644 index d1bcf0e..0000000 --- a/packages/reffuse/src/ReffuseReactContext.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { Context, Effect, Runtime, type Layer } from "effect" -import React from "react" -import type * as Reffuse from "./Reffuse.js" - - -export interface Value { - readonly runtime: Runtime.Runtime - readonly context: Context.Context -} - - -export type Provider< - RuntimeR, - OwnContextR, - ParentContextR, -> = React.FC> - -export interface ProviderProps< - RuntimeR, - OwnContextR, - ParentContextR, -> { - readonly layer: Layer.Layer - readonly children?: React.ReactNode -} - -export function makeRootProvider< - RuntimeR, - ContextR extends ParentContextR | OwnContextR, - OwnContextR, - ParentContextR, ->( - runtime: Runtime.Runtime, - ReactContext: React.Context>, -): Provider { - return function ReffuseRootReactContextProvider(props) { - const value = React.useMemo(() => ({ - runtime, - context: Effect.context().pipe( - Effect.provide(props.layer), - Effect.provide(Context.empty() as Context.Context), // Just there for type safety. ParentContextR is always never here anyway - Runtime.runSync(runtime), - ), - }), [props.layer]) - - return ( - - ) - } -} - -export function makeNestedProvider< - RuntimeR, - ContextR extends ParentContextR | OwnContextR, - OwnContextR, - ParentContextR, ->( - runtime: Runtime.Runtime, - ReactContext: React.Context>, - parent: Reffuse.Reffuse, -): Provider { - return function ReffuseNestedReactContextProvider(props) { - const parentContext = parent.useContext() - - const value = React.useMemo(() => ({ - runtime, - context: Effect.context().pipe( - Effect.provide(props.layer), - Effect.provide(parentContext), - Runtime.runSync(runtime), - ), - }), [props.layer, parentContext]) - - return ( - - ) - } -}