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 React from "react"
import * as Hook from "./Hook.js" import * as Hook from "./Hook.js"
import type { ExcludeKeys } from "./utils.js"
export interface Component<E, R, P extends {}> extends Pipeable.Pipeable { 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 displayName?: string
readonly options: Options 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 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 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 { export interface MakeOptions {
@@ -40,21 +46,18 @@ export const make = <
> => { > => {
const displayName = !String.isEmpty(body.name) ? body.name : undefined const displayName = !String.isEmpty(body.name) ? body.name : undefined
const f = ((options?.traced ?? true) return Object.setPrototypeOf({
body: (options?.traced ?? true)
? displayName ? displayName
? Effect.fn(displayName)(body) ? Effect.fn(displayName)(body)
: Effect.fn(body) : Effect.fn(body)
: Effect.fnUntraced(body) : Effect.fnUntraced(body),
) as Component<any, any, any> displayName,
options: {
f.pipe = function pipe() { return Pipeable.pipeArguments(this, arguments) };
(f as Types.Mutable<typeof f>).displayName = displayName;
(f as Types.Mutable<typeof f>).options = {
finalizerExecutionMode: options?.finalizerExecutionMode ?? "sync", finalizerExecutionMode: options?.finalizerExecutionMode ?? "sync",
finalizerExecutionStrategy: options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential, finalizerExecutionStrategy: options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential,
} },
}, ComponentProto)
return f
} }
@@ -78,7 +81,7 @@ export const useFC: {
const FC = React.useMemo(() => { const FC = React.useMemo(() => {
const f = (props: P) => Runtime.runSync(runtimeRef.current)( 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" f.displayName = self.displayName ?? "Anonymous"
return f return f
@@ -89,7 +92,7 @@ export const useFC: {
}) })
export const useSuspenseFC: { export const useSuspenseFC: {
<E, R, P extends {}>( <E, R, P extends ExcludeKeys<{}, "suspenseProps">>(
self: Component<E, R, P> self: Component<E, R, P>
): Effect.Effect< ): Effect.Effect<
React.FC<P & { readonly suspenseProps: React.SuspenseProps }>, React.FC<P & { readonly suspenseProps: React.SuspenseProps }>,
@@ -115,7 +118,7 @@ export const useSuspenseFC: {
const f = ({ suspenseProps, ...props }: P & { readonly suspenseProps: React.SuspenseProps }) => { const f = ({ suspenseProps, ...props }: P & { readonly suspenseProps: React.SuspenseProps }) => {
const promise = Runtime.runPromise(runtimeRef.current)( 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( 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