This commit is contained in:
@@ -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<ReffuseReactContext.Value<RuntimeR, ContextR>>(null!)
|
||||
readonly Provider: ReffuseReactContext.Provider<RuntimeR, OwnContextR, ParentContextR>
|
||||
export class Reffuse<R> {
|
||||
|
||||
constructor(
|
||||
private readonly runtime: Runtime.Runtime<RuntimeR>,
|
||||
parent?: Reffuse<RuntimeR, ParentContextR, unknown, unknown>,
|
||||
) {
|
||||
this.Provider = parent
|
||||
? ReffuseReactContext.makeNestedProvider(runtime, this.Context, parent)
|
||||
: ReffuseReactContext.makeRootProvider(runtime, this.Context)
|
||||
}
|
||||
|
||||
extend<OwnContextR = never>() {
|
||||
return new Reffuse<
|
||||
RuntimeR,
|
||||
ContextR | OwnContextR,
|
||||
OwnContextR,
|
||||
ContextR
|
||||
>(this.runtime, this)
|
||||
}
|
||||
readonly contexts: readonly ReffuseContext.ReffuseContext<R>[]
|
||||
) {}
|
||||
|
||||
|
||||
useRuntime(): Runtime.Runtime<RuntimeR> {
|
||||
return React.useContext(this.Context).runtime
|
||||
}
|
||||
|
||||
useContext(): Context.Context<ContextR> {
|
||||
return React.useContext(this.Context).context
|
||||
useContext(): Context.Context<R> {
|
||||
return ReffuseContext.useMergeAll(...this.contexts)
|
||||
}
|
||||
|
||||
|
||||
useRunSync() {
|
||||
const { runtime, context } = React.useContext(this.Context)
|
||||
const runtime = ReffuseRuntime.useRuntime()
|
||||
const context = this.useContext()
|
||||
|
||||
return React.useCallback(<A, E>(
|
||||
effect: Effect.Effect<A, E, RuntimeR | ContextR>
|
||||
effect: Effect.Effect<A, E, R>
|
||||
): 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(<A, E>(
|
||||
effect: Effect.Effect<A, E, RuntimeR | ContextR>,
|
||||
effect: Effect.Effect<A, E, R>,
|
||||
options?: { readonly signal?: AbortSignal },
|
||||
): Promise<A> => 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(<A, E>(
|
||||
effect: Effect.Effect<A, E, RuntimeR | ContextR>,
|
||||
effect: Effect.Effect<A, E, R>,
|
||||
options?: Runtime.RunForkOptions,
|
||||
): Fiber.RuntimeFiber<A, E> => effect.pipe(
|
||||
Effect.provide(context),
|
||||
@@ -78,7 +56,7 @@ export class Reffuse<
|
||||
|
||||
|
||||
useMemo<A, E>(
|
||||
effect: Effect.Effect<A, E, RuntimeR | ContextR>,
|
||||
effect: Effect.Effect<A, E, R>,
|
||||
deps?: React.DependencyList,
|
||||
options?: RenderOptions,
|
||||
): A {
|
||||
@@ -104,7 +82,7 @@ export class Reffuse<
|
||||
// }
|
||||
|
||||
useSuspense<A, E>(
|
||||
effect: Effect.Effect<A, E, RuntimeR | ContextR>,
|
||||
effect: Effect.Effect<A, E, R>,
|
||||
options?: { readonly signal?: AbortSignal },
|
||||
): A {
|
||||
const runPromise = this.useRunPromise()
|
||||
@@ -112,7 +90,7 @@ export class Reffuse<
|
||||
}
|
||||
|
||||
useFork<A, E>(
|
||||
effect: Effect.Effect<A, E, RuntimeR | ContextR | Scope.Scope>,
|
||||
effect: Effect.Effect<A, E, R | Scope.Scope>,
|
||||
deps?: React.DependencyList,
|
||||
options?: Runtime.RunForkOptions & RenderOptions,
|
||||
): void {
|
||||
@@ -136,7 +114,7 @@ export class Reffuse<
|
||||
)
|
||||
}
|
||||
|
||||
useRefFromEffect<A, E>(effect: Effect.Effect<A, E, RuntimeR | ContextR>): SubscriptionRef.SubscriptionRef<A> {
|
||||
useRefFromEffect<A, E>(effect: Effect.Effect<A, E, R>): SubscriptionRef.SubscriptionRef<A> {
|
||||
return this.useMemo(
|
||||
effect.pipe(Effect.flatMap(SubscriptionRef.make)),
|
||||
[],
|
||||
@@ -174,9 +152,9 @@ export interface RenderOptions {
|
||||
}
|
||||
|
||||
|
||||
export const make = <R = never>(): Reffuse<never, R, R> =>
|
||||
new Reffuse(Runtime.defaultRuntime)
|
||||
|
||||
export const makeWithRuntime = <R = never>() =>
|
||||
<RuntimeR>(runtime: Runtime.Runtime<RuntimeR>): Reffuse<RuntimeR, R, R> =>
|
||||
new Reffuse(runtime)
|
||||
export const make = <
|
||||
const Contexts extends readonly ReffuseContext.ReffuseContext<any>[]
|
||||
>(
|
||||
contexts: Contexts
|
||||
): Reffuse<{ [K in keyof Contexts]: ReffuseContext.R<Contexts[K]> }[number]> =>
|
||||
new Reffuse(contexts)
|
||||
|
||||
@@ -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<RuntimeR, ContextR> {
|
||||
readonly runtime: Runtime.Runtime<RuntimeR>
|
||||
readonly context: Context.Context<ContextR>
|
||||
}
|
||||
|
||||
|
||||
export type Provider<
|
||||
RuntimeR,
|
||||
OwnContextR,
|
||||
ParentContextR,
|
||||
> = React.FC<ProviderProps<RuntimeR, OwnContextR, ParentContextR>>
|
||||
|
||||
export interface ProviderProps<
|
||||
RuntimeR,
|
||||
OwnContextR,
|
||||
ParentContextR,
|
||||
> {
|
||||
readonly layer: Layer.Layer<OwnContextR, unknown, RuntimeR | ParentContextR>
|
||||
readonly children?: React.ReactNode
|
||||
}
|
||||
|
||||
export function makeRootProvider<
|
||||
RuntimeR,
|
||||
ContextR extends ParentContextR | OwnContextR,
|
||||
OwnContextR,
|
||||
ParentContextR,
|
||||
>(
|
||||
runtime: Runtime.Runtime<RuntimeR>,
|
||||
ReactContext: React.Context<Value<RuntimeR, ContextR>>,
|
||||
): Provider<RuntimeR, OwnContextR, ParentContextR> {
|
||||
return function ReffuseRootReactContextProvider(props) {
|
||||
const value = React.useMemo(() => ({
|
||||
runtime,
|
||||
context: Effect.context<ContextR>().pipe(
|
||||
Effect.provide(props.layer),
|
||||
Effect.provide(Context.empty() as Context.Context<ParentContextR>), // Just there for type safety. ParentContextR is always never here anyway
|
||||
Runtime.runSync(runtime),
|
||||
),
|
||||
}), [props.layer])
|
||||
|
||||
return (
|
||||
<ReactContext
|
||||
{...props}
|
||||
value={value}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function makeNestedProvider<
|
||||
RuntimeR,
|
||||
ContextR extends ParentContextR | OwnContextR,
|
||||
OwnContextR,
|
||||
ParentContextR,
|
||||
>(
|
||||
runtime: Runtime.Runtime<RuntimeR>,
|
||||
ReactContext: React.Context<Value<RuntimeR, ContextR>>,
|
||||
parent: Reffuse.Reffuse<RuntimeR, ParentContextR, unknown, unknown>,
|
||||
): Provider<RuntimeR, OwnContextR, ParentContextR> {
|
||||
return function ReffuseNestedReactContextProvider(props) {
|
||||
const parentContext = parent.useContext()
|
||||
|
||||
const value = React.useMemo(() => ({
|
||||
runtime,
|
||||
context: Effect.context<ContextR>().pipe(
|
||||
Effect.provide(props.layer),
|
||||
Effect.provide(parentContext),
|
||||
Runtime.runSync(runtime),
|
||||
),
|
||||
}), [props.layer, parentContext])
|
||||
|
||||
return (
|
||||
<ReactContext
|
||||
{...props}
|
||||
value={value}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user