diff --git a/packages/effect-fc/src/ReactManagedRuntime.ts b/packages/effect-fc/src/ReactManagedRuntime.ts deleted file mode 100644 index f41286f..0000000 --- a/packages/effect-fc/src/ReactManagedRuntime.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Effect, type Layer, ManagedRuntime, type Runtime } from "effect" -import * as React from "react" - - -export interface ReactManagedRuntime { - readonly runtime: ManagedRuntime.ManagedRuntime - readonly context: React.Context> -} - -export const make = ( - layer: Layer.Layer, - memoMap?: Layer.MemoMap, -): ReactManagedRuntime => ({ - runtime: ManagedRuntime.make(layer, memoMap), - context: React.createContext>(null!), -}) - - -export interface ProviderProps extends React.SuspenseProps { - readonly runtime: ReactManagedRuntime - readonly children?: React.ReactNode -} - -export function Provider( - { runtime, children, ...suspenseProps }: ProviderProps -): React.ReactNode { - const promise = React.useMemo(() => Effect.runPromise(runtime.runtime.runtimeEffect), [runtime]) - - return React.createElement( - React.Suspense, - suspenseProps, - React.createElement(ProviderInner, { runtime, promise, children }), - ) -} - -interface ProviderInnerProps { - readonly runtime: ReactManagedRuntime - readonly promise: Promise> - readonly children?: React.ReactNode -} - -function ProviderInner( - { runtime, promise, children }: ProviderInnerProps -): React.ReactNode { - const value = React.use(promise) - return React.createElement(runtime.context, { value }, children) -} diff --git a/packages/effect-fc/src/ReactRuntime.ts b/packages/effect-fc/src/ReactRuntime.ts new file mode 100644 index 0000000..fa45591 --- /dev/null +++ b/packages/effect-fc/src/ReactRuntime.ts @@ -0,0 +1,64 @@ +import { Effect, type Layer, ManagedRuntime, Predicate, type Runtime } from "effect" +import * as React from "react" + + +export const TypeId: unique symbol = Symbol.for("effect-fc/ReactRuntime") +export type TypeId = typeof TypeId + +export interface ReactRuntime { + new(_: never): {} + readonly [TypeId]: TypeId + readonly runtime: ManagedRuntime.ManagedRuntime + readonly context: React.Context> +} + +const ReactRuntimeProto = Object.freeze({ [TypeId]: TypeId } as const) + + +export const isReactRuntime = (u: unknown): u is ReactRuntime => Predicate.hasProperty(u, TypeId) + +export const make = ( + layer: Layer.Layer, + memoMap?: Layer.MemoMap, +): ReactRuntime => Object.setPrototypeOf( + Object.assign(function() {}, { + runtime: ManagedRuntime.make(layer, memoMap), + context: React.createContext>(null!), + }), + ReactRuntimeProto, +) + + +export namespace Provider { + export interface Props extends React.SuspenseProps { + readonly runtime: ReactRuntime + readonly children?: React.ReactNode + } +} + +export const Provider = ( + { runtime, children, ...suspenseProps }: Provider.Props +): React.ReactNode => { + const promise = React.useMemo(() => Effect.runPromise(runtime.runtime.runtimeEffect), [runtime]) + + return React.createElement( + React.Suspense, + suspenseProps, + React.createElement(ProviderInner, { runtime, promise, children }), + ) +} + +namespace ProviderInner { + export interface Props { + readonly runtime: ReactRuntime + readonly promise: Promise> + readonly children?: React.ReactNode + } +} + +const ProviderInner = ( + { runtime, promise, children }: ProviderInner.Props +): React.ReactNode => { + const value = React.use(promise) + return React.createElement(runtime.context, { value }, children) +} diff --git a/packages/effect-fc/src/index.ts b/packages/effect-fc/src/index.ts index a9be6ce..2545011 100644 --- a/packages/effect-fc/src/index.ts +++ b/packages/effect-fc/src/index.ts @@ -1,4 +1,4 @@ export * as Component from "./Component.js" export * as Memo from "./Memo.js" -export * as ReactManagedRuntime from "./ReactManagedRuntime.js" +export * as ReactRuntime from "./ReactRuntime.js" export * as Suspense from "./Suspense.js" diff --git a/packages/example/src/main.tsx b/packages/example/src/main.tsx index d983376..bcf65ab 100644 --- a/packages/example/src/main.tsx +++ b/packages/example/src/main.tsx @@ -1,5 +1,5 @@ import { createRouter, RouterProvider } from "@tanstack/react-router" -import { ReactManagedRuntime } from "effect-fc" +import { ReactRuntime } from "effect-fc" import { StrictMode } from "react" import { createRoot } from "react-dom/client" import { routeTree } from "./routeTree.gen" @@ -16,8 +16,8 @@ declare module "@tanstack/react-router" { createRoot(document.getElementById("root")!).render( - + - + ) diff --git a/packages/example/src/runtime.ts b/packages/example/src/runtime.ts index 5524d5f..3467529 100644 --- a/packages/example/src/runtime.ts +++ b/packages/example/src/runtime.ts @@ -1,7 +1,7 @@ import { FetchHttpClient } from "@effect/platform" import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser" import { DateTime, Layer } from "effect" -import { ReactManagedRuntime } from "effect-fc" +import { ReactRuntime } from "effect-fc" export const AppLive = Layer.empty.pipe( @@ -12,4 +12,4 @@ export const AppLive = Layer.empty.pipe( Layer.provideMerge(FetchHttpClient.layer), ) -export const runtime = ReactManagedRuntime.make(AppLive) +export const runtime = ReactRuntime.make(AppLive)