|
|
|
|
@@ -1,4 +1,4 @@
|
|
|
|
|
import { Context, Effect, ExecutionStrategy, Function, Pipeable, Predicate, Runtime, Scope, String, Tracer, type Utils } from "effect"
|
|
|
|
|
import { Context, Effect, Effectable, ExecutionStrategy, Function, Predicate, Runtime, Scope, String, Tracer, type Utils } from "effect"
|
|
|
|
|
import * as React from "react"
|
|
|
|
|
import * as Hook from "./Hook.js"
|
|
|
|
|
import * as Memoized from "./Memoized.js"
|
|
|
|
|
@@ -7,7 +7,7 @@ import * as Memoized from "./Memoized.js"
|
|
|
|
|
export const TypeId: unique symbol = Symbol.for("effect-fc/Component")
|
|
|
|
|
export type TypeId = typeof TypeId
|
|
|
|
|
|
|
|
|
|
export interface Component<E, R, P extends {}> extends Pipeable.Pipeable, Component.Options {
|
|
|
|
|
export interface Component<E, R, P extends {}> extends Effect.Effect<React.FC<P>, never, R>, Component.Options {
|
|
|
|
|
new(_: never): {}
|
|
|
|
|
readonly [TypeId]: TypeId
|
|
|
|
|
/** @internal */
|
|
|
|
|
@@ -30,8 +30,34 @@ export namespace Component {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ComponentProto = Object.freeze({
|
|
|
|
|
...Effectable.CommitPrototype,
|
|
|
|
|
[TypeId]: TypeId,
|
|
|
|
|
pipe() { return Pipeable.pipeArguments(this, arguments) },
|
|
|
|
|
|
|
|
|
|
commit: Effect.fnUntraced(function* <E, R, P extends {}>(this: Component<E, R, P>) {
|
|
|
|
|
const self = this
|
|
|
|
|
|
|
|
|
|
const runtimeRef = React.useRef<Runtime.Runtime<Exclude<R, Scope.Scope>>>(null!)
|
|
|
|
|
runtimeRef.current = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
|
|
|
|
|
|
|
|
|
|
return React.useCallback(function ScopeProvider(props: P) {
|
|
|
|
|
const scope = Runtime.runSync(runtimeRef.current)(Hook.useScope(
|
|
|
|
|
Array.from(
|
|
|
|
|
Context.omit(...nonReactiveTags)(runtimeRef.current.context).unsafeMap.values()
|
|
|
|
|
),
|
|
|
|
|
self,
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
const FC = React.useMemo(() => {
|
|
|
|
|
const f = self.makeFunctionComponent(runtimeRef, scope)
|
|
|
|
|
f.displayName = self.displayName ?? "Anonymous"
|
|
|
|
|
return Memoized.isMemoized(self)
|
|
|
|
|
? React.memo(f, self.propsAreEqual)
|
|
|
|
|
: f
|
|
|
|
|
}, [scope])
|
|
|
|
|
|
|
|
|
|
return React.createElement(FC, props)
|
|
|
|
|
}, [])
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
makeFunctionComponent(
|
|
|
|
|
this: Component<any, any, any>,
|
|
|
|
|
@@ -52,7 +78,7 @@ const defaultOptions = {
|
|
|
|
|
const nonReactiveTags = [Tracer.ParentSpan] as const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const isComponent = (u: unknown): u is Component<any, any, any> => Predicate.hasProperty(u, TypeId)
|
|
|
|
|
export const isComponent = (u: unknown): u is Component<unknown, unknown, {}> => Predicate.hasProperty(u, TypeId)
|
|
|
|
|
|
|
|
|
|
export namespace make {
|
|
|
|
|
export type Gen = {
|
|
|
|
|
|