0.1.0 #1

Merged
Thilawyn merged 87 commits from next into master 2025-01-18 00:54:42 +01:00
3 changed files with 74 additions and 70 deletions
Showing only changes of commit 12849d37da - Show all commits

View File

@@ -1,23 +1,24 @@
import { Context, Effect, Fiber, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect"
import React from "react"
import type * as ReffuseReactContext from "./ReffuseReactContext.js"
import * as ReffuseReactContextProvider from "./ReffuseReactContextProvider.js"
import * as ReffuseReactContext from "./ReffuseReactContext.js"
export class Reffuse<
R extends RuntimeR | ContextR,
RuntimeR,
ContextR,
Parent extends Reffuse<any, any, any, any>,
ContextR extends ParentContextR | OwnContextR,
OwnContextR,
ParentContextR = never,
> {
readonly Context = React.createContext<ReffuseReactContext.Value<RuntimeR, ContextR>>(null!)
readonly Provider: ReffuseReactContextProvider.ReffuseReactContextProvider<R>
readonly Provider: ReffuseReactContext.Provider<RuntimeR, OwnContextR, ParentContextR>
constructor(
runtime: Runtime.Runtime<RuntimeR>
runtime: Runtime.Runtime<RuntimeR>,
parent?: Reffuse<RuntimeR, ParentContextR, unknown, unknown>,
) {
this.Provider = ReffuseReactContextProvider.make(runtime, this.Context)
// TODO: split into makeProvider and makeScopedProvider
this.Provider = ReffuseReactContext.makeProvider(runtime, this.Context, parent)
}
@@ -33,7 +34,9 @@ export class Reffuse<
useRunSync() {
const { runtime, context } = React.useContext(this.Context)
return React.useCallback(<A, E>(effect: Effect.Effect<A, E, R>): A => effect.pipe(
return React.useCallback(<A, E>(
effect: Effect.Effect<A, E, RuntimeR | ContextR>
): A => effect.pipe(
Effect.provide(context),
Runtime.runSync(runtime),
), [runtime, context])
@@ -43,7 +46,7 @@ export class Reffuse<
const { runtime, context } = React.useContext(this.Context)
return React.useCallback(<A, E>(
effect: Effect.Effect<A, E, R>,
effect: Effect.Effect<A, E, RuntimeR | ContextR>,
options?: { readonly signal?: AbortSignal },
): Promise<A> => effect.pipe(
Effect.provide(context),
@@ -55,7 +58,7 @@ export class Reffuse<
const { runtime, context } = React.useContext(this.Context)
return React.useCallback(<A, E>(
effect: Effect.Effect<A, E, R>,
effect: Effect.Effect<A, E, RuntimeR | ContextR>,
options?: Runtime.RunForkOptions,
): Fiber.RuntimeFiber<A, E> => effect.pipe(
Effect.provide(context),
@@ -65,7 +68,7 @@ export class Reffuse<
useFork<A, E>(
self: Effect.Effect<A, E, R | Scope.Scope>,
self: Effect.Effect<A, E, RuntimeR | ContextR | Scope.Scope>,
deps?: React.DependencyList,
options?: Runtime.RunForkOptions,
): void {
@@ -83,7 +86,7 @@ export class Reffuse<
return React.useMemo(() => runSync(SubscriptionRef.make(value)), [])
}
useRefFromEffect<A, E>(effect: Effect.Effect<A, E, R>): SubscriptionRef.SubscriptionRef<A> {
useRefFromEffect<A, E>(effect: Effect.Effect<A, E, RuntimeR | ContextR>): SubscriptionRef.SubscriptionRef<A> {
const runSync = this.useRunSync()
return React.useMemo(() => runSync(effect.pipe(

View File

@@ -1,5 +1,6 @@
import { Effect, Runtime, type Context, type Layer } from "effect"
import { Context, Effect, Runtime, type Layer } from "effect"
import React from "react"
import type * as Reffuse from "./Reffuse.js"
export interface Value<RuntimeR, ContextR> {
@@ -8,32 +9,66 @@ export interface Value<RuntimeR, ContextR> {
}
export interface ProviderProps<R> {
readonly layer: Layer.Layer<R, unknown>
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 type Provider<R> = React.FC<ProviderProps<R>>
export function makeProvider<
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 parent
? function ReffuseReactContextProvider(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])
export function makeProvider<R>(
runtime: Runtime.Runtime<never>,
Context: React.Context<Value<R>>,
) {
return function ReffuseReactContextProvider(props: ProviderProps<R>) {
const value = React.useMemo(() => ({
runtime,
context: Effect.context<R>().pipe(
Effect.provide(props.layer),
Runtime.runSync(runtime),
),
}), [props.layer])
return (
<ReactContext
{...props}
value={value}
/>
)
}
: function ReffuseReactContextProvider(props) {
const value = React.useMemo(() => ({
runtime,
context: Effect.context<ContextR>().pipe(
Effect.provide(props.layer),
Effect.provide(Context.empty() as Context.Context<ParentContextR>), // Required for type safety
Runtime.runSync(runtime),
),
}), [props.layer])
return (
<Context
{...props}
value={value}
/>
)
}
return (
<ReactContext
{...props}
value={value}
/>
)
}
}

View File

@@ -1,34 +0,0 @@
import { Effect, Runtime, type Layer } from "effect"
import React from "react"
import type * as ReffuseReactContext from "./ReffuseReactContext.js"
export interface Props<R> {
readonly layer: Layer.Layer<R, unknown>
readonly children?: React.ReactNode
}
export type ReffuseReactContextProvider<R> = React.FC<Props<R>>
export function make<R>(
runtime: Runtime.Runtime<never>,
Context: React.Context<ReffuseReactContext.ReffuseReactContext<R>>,
) {
return function ReffuseReactContextProvider(props: Props<R>) {
const value = React.useMemo(() => ({
runtime,
context: Effect.context<R>().pipe(
Effect.provide(props.layer),
Runtime.runSync(runtime),
),
}), [props.layer])
return (
<Context
{...props}
value={value}
/>
)
}
}