0.1.0 #1

Merged
Thilawyn merged 81 commits from next into master 2025-07-17 21:17:57 +02:00
2 changed files with 27 additions and 21 deletions
Showing only changes of commit 68bf55fa74 - Show all commits

View File

@@ -1,10 +1,11 @@
import { Context, Effect, ExecutionStrategy, Function, Pipeable, Runtime, Scope, String, Tracer, type Types, type Utils } from "effect"
import { Context, Effect, ExecutionStrategy, Function, Pipeable, Runtime, Scope, String, Tracer, type Utils } from "effect"
import * as React from "react"
import * as Hook from "./Hook.js"
import type { ExcludeKeys } from "./utils.js"
export interface Component<E, R, P extends {}> extends Pipeable.Pipeable {
(props: P): Effect.Effect<React.ReactNode, E, R>
readonly body: (props: P) => Effect.Effect<React.ReactNode, E, R>
readonly displayName?: string
readonly options: Options
}
@@ -18,7 +19,12 @@ export type Error<T> = T extends Component<infer E, infer _R, infer _P> ? E : ne
export type Context<T> = T extends Component<infer _E, infer R, infer _P> ? R : never
export type Props<T> = T extends Component<infer _E, infer _R, infer P> ? P : never
export const nonReactiveTags = [Tracer.ParentSpan] as const
const ComponentProto = {
pipe() { return Pipeable.pipeArguments(this, arguments) }
} as const
const nonReactiveTags = [Tracer.ParentSpan] as const
export interface MakeOptions {
@@ -40,21 +46,18 @@ export const make = <
> => {
const displayName = !String.isEmpty(body.name) ? body.name : undefined
const f = ((options?.traced ?? true)
return Object.setPrototypeOf({
body: (options?.traced ?? true)
? displayName
? Effect.fn(displayName)(body)
: Effect.fn(body)
: Effect.fnUntraced(body)
) as Component<any, any, any>
f.pipe = function pipe() { return Pipeable.pipeArguments(this, arguments) };
(f as Types.Mutable<typeof f>).displayName = displayName;
(f as Types.Mutable<typeof f>).options = {
: Effect.fnUntraced(body),
displayName,
options: {
finalizerExecutionMode: options?.finalizerExecutionMode ?? "sync",
finalizerExecutionStrategy: options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential,
}
return f
},
}, ComponentProto)
}
@@ -78,7 +81,7 @@ export const useFC: {
const FC = React.useMemo(() => {
const f = (props: P) => Runtime.runSync(runtimeRef.current)(
Effect.provideService(self(props), Scope.Scope, scope)
Effect.provideService(self.body(props), Scope.Scope, scope)
)
f.displayName = self.displayName ?? "Anonymous"
return f
@@ -89,7 +92,7 @@ export const useFC: {
})
export const useSuspenseFC: {
<E, R, P extends {}>(
<E, R, P extends ExcludeKeys<{}, "suspenseProps">>(
self: Component<E, R, P>
): Effect.Effect<
React.FC<P & { readonly suspenseProps: React.SuspenseProps }>,
@@ -115,7 +118,7 @@ export const useSuspenseFC: {
const f = ({ suspenseProps, ...props }: P & { readonly suspenseProps: React.SuspenseProps }) => {
const promise = Runtime.runPromise(runtimeRef.current)(
Effect.provideService(self(props), Scope.Scope, scope)
Effect.provideService(self.body(props as P), Scope.Scope, scope)
)
return React.createElement(

View File

@@ -0,0 +1,3 @@
export type ExcludeKeys<T, K extends PropertyKey> = K extends keyof T ? (
{ [P in K]?: never } & Omit<T, K>
) : T