This commit is contained in:
@@ -1,23 +1,30 @@
|
||||
import { Context, Effect, Runtime, Tracer } from "effect"
|
||||
import { Context, Effect, Function, Runtime, Tracer } from "effect"
|
||||
import type { Mutable } from "effect/Types"
|
||||
import * as React from "react"
|
||||
import * as ReactHook from "./ReactHook.js"
|
||||
|
||||
|
||||
export interface ReactComponent<P, E, R> {
|
||||
export interface ReactComponent<E, R, P> {
|
||||
(props: P): Effect.Effect<React.ReactNode, E, R>
|
||||
readonly displayName?: string
|
||||
}
|
||||
|
||||
export const nonReactiveTags = [Tracer.ParentSpan] as const
|
||||
|
||||
export const withDisplayName: {
|
||||
<C extends ReactComponent<any, any, any>>(displayName: string): (self: C) => C
|
||||
<C extends ReactComponent<any, any, any>>(self: C, displayName: string): C
|
||||
} = Function.dual(2, <C extends ReactComponent<any, any, any>>(
|
||||
self: C,
|
||||
displayName: string,
|
||||
): C => {
|
||||
(self as Mutable<C>).displayName = displayName
|
||||
return self
|
||||
})
|
||||
|
||||
export const useFC: {
|
||||
<P, E, R>(
|
||||
self: ReactComponent<P, E, R>,
|
||||
options?: ReactHook.ScopeOptions,
|
||||
): Effect.Effect<React.FC<P>, never, R>
|
||||
} = Effect.fnUntraced(function* useFC<P, E, R>(
|
||||
self: ReactComponent<P, E, R>
|
||||
<E, R, P = {}>(self: ReactComponent<E, R, P>): Effect.Effect<React.FC<P>, never, R>
|
||||
} = Effect.fnUntraced(function* <E, R, P>(
|
||||
self: ReactComponent<E, R, P>
|
||||
) {
|
||||
const runtime = yield* Effect.runtime<R>()
|
||||
|
||||
@@ -31,14 +38,24 @@ export const useFC: {
|
||||
})
|
||||
|
||||
export const use: {
|
||||
<P, E, R>(
|
||||
self: ReactComponent<P, E, R>,
|
||||
<E, R, P = {}>(
|
||||
self: ReactComponent<E, R, P>,
|
||||
fn: (Component: React.FC<P>) => React.ReactNode,
|
||||
): Effect.Effect<React.ReactNode, never, R>
|
||||
} = Effect.fnUntraced(function* use(self, fn) {
|
||||
} = Effect.fnUntraced(function*(self, fn) {
|
||||
return fn(yield* useFC(self))
|
||||
})
|
||||
|
||||
export const withRuntime: {
|
||||
<E, R, P = {}>(context: React.Context<Runtime.Runtime<R>>): (self: ReactComponent<E, R, P>) => React.FC<P>
|
||||
<E, R, P = {}>(self: ReactComponent<E, R, P>, context: React.Context<Runtime.Runtime<R>>): React.FC<P>
|
||||
} = Function.dual(2, <E, R, P extends {}>(
|
||||
self: ReactComponent<E, R, P>,
|
||||
context: React.Context<Runtime.Runtime<R>>,
|
||||
): React.FC<P> => function WithRuntime(props) {
|
||||
const runtime = React.useContext(context)
|
||||
return React.createElement(Runtime.runSync(runtime)(useFC(self)), props)
|
||||
})
|
||||
|
||||
// export const useFC: {
|
||||
// <P, E, R>(
|
||||
|
||||
@@ -13,7 +13,7 @@ export const useMemo: {
|
||||
factory: () => Effect.Effect<A, E, R>,
|
||||
deps: React.DependencyList,
|
||||
): Effect.Effect<A, never, R>
|
||||
} = Effect.fnUntraced(function* useMemo<A, E, R>(
|
||||
} = Effect.fnUntraced(function* <A, E, R>(
|
||||
factory: () => Effect.Effect<A, E, R>,
|
||||
deps: React.DependencyList,
|
||||
) {
|
||||
@@ -23,7 +23,7 @@ export const useMemo: {
|
||||
|
||||
export const useOnce: {
|
||||
<A, E, R>(factory: () => Effect.Effect<A, E, R>): Effect.Effect<A, never, R>
|
||||
} = Effect.fnUntraced(function* useOnce<A, E, R>(
|
||||
} = Effect.fnUntraced(function* <A, E, R>(
|
||||
factory: () => Effect.Effect<A, E, R>
|
||||
) {
|
||||
return yield* useMemo(factory, [])
|
||||
@@ -31,16 +31,16 @@ export const useOnce: {
|
||||
|
||||
export const useEffect: {
|
||||
<E, R>(
|
||||
effect: () => Effect.Effect<void, E, R | Scope.Scope>,
|
||||
effect: () => Effect.Effect<void, E, R>,
|
||||
deps?: React.DependencyList,
|
||||
options?: ScopeOptions,
|
||||
): Effect.Effect<void, never, R>
|
||||
} = Effect.fnUntraced(function* useEffect<E, R>(
|
||||
effect: () => Effect.Effect<void, E, R | Scope.Scope>,
|
||||
): Effect.Effect<void, never, Exclude<R, Scope.Scope>>
|
||||
} = Effect.fnUntraced(function* <E, R>(
|
||||
effect: () => Effect.Effect<void, E, R>,
|
||||
deps?: React.DependencyList,
|
||||
options?: ScopeOptions,
|
||||
) {
|
||||
const runtime = yield* Effect.runtime<R>()
|
||||
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
|
||||
|
||||
React.useEffect(() => {
|
||||
const { scope, exit } = Effect.Do.pipe(
|
||||
@@ -64,16 +64,16 @@ export const useEffect: {
|
||||
|
||||
export const useLayoutEffect: {
|
||||
<E, R>(
|
||||
effect: () => Effect.Effect<void, E, R | Scope.Scope>,
|
||||
effect: () => Effect.Effect<void, E, R>,
|
||||
deps?: React.DependencyList,
|
||||
options?: ScopeOptions,
|
||||
): Effect.Effect<void, never, R>
|
||||
} = Effect.fnUntraced(function* useLayoutEffect<E, R>(
|
||||
effect: () => Effect.Effect<void, E, R | Scope.Scope>,
|
||||
): Effect.Effect<void, never, Exclude<R, Scope.Scope>>
|
||||
} = Effect.fnUntraced(function* <E, R>(
|
||||
effect: () => Effect.Effect<void, E, R>,
|
||||
deps?: React.DependencyList,
|
||||
options?: ScopeOptions,
|
||||
) {
|
||||
const runtime = yield* Effect.runtime<R>()
|
||||
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
const { scope, exit } = Effect.Do.pipe(
|
||||
|
||||
29
packages/effect-components/src/ReactManagedRuntime.ts
Normal file
29
packages/effect-components/src/ReactManagedRuntime.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Effect, type Layer, ManagedRuntime, Runtime } from "effect"
|
||||
import * as React from "react"
|
||||
|
||||
|
||||
export interface ReactManagedRuntime<R, ER> {
|
||||
readonly runtime: ManagedRuntime.ManagedRuntime<R, ER>
|
||||
readonly context: React.Context<Runtime.Runtime<R>>
|
||||
}
|
||||
|
||||
export const make = <R, ER>(
|
||||
layer: Layer.Layer<R, ER>,
|
||||
memoMap?: Layer.MemoMap,
|
||||
): ReactManagedRuntime<R, ER> => ({
|
||||
runtime: ManagedRuntime.make(layer, memoMap),
|
||||
context: React.createContext<Runtime.Runtime<R>>(null!),
|
||||
})
|
||||
|
||||
export interface SyncProviderProps<R, ER> {
|
||||
readonly runtime: ReactManagedRuntime<R, ER>
|
||||
readonly children?: React.ReactNode
|
||||
}
|
||||
|
||||
export const SyncProvider = <R, ER>(
|
||||
props: SyncProviderProps<R, ER>
|
||||
): React.ReactNode => React.createElement(props.runtime.context, {
|
||||
value: React.useMemo(() => Effect.runSync(props.runtime.runtime.runtimeEffect), [props.runtime]),
|
||||
children: props.children,
|
||||
})
|
||||
SyncProvider.displayName = "ReactManagedRuntimeSyncProvider"
|
||||
@@ -1,2 +1,3 @@
|
||||
export * as ReactComponent from "./ReactComponent.js"
|
||||
export * as ReactHook from "./ReactHook.js"
|
||||
export * as ReactManagedRuntime from "./ReactManagedRuntime.js"
|
||||
|
||||
Reference in New Issue
Block a user