/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ import { Effect, Function, Predicate, Runtime, Scope } from "effect" import * as React from "react" import * as Component from "./Component.js" export const TypeId: unique symbol = Symbol.for("@effect-fc/Async/Async") export type TypeId = typeof TypeId export interface Async extends AsyncOptions { readonly [TypeId]: TypeId } export interface AsyncOptions { readonly defaultFallback?: React.ReactNode } export type AsyncProps = Omit export const AsyncPrototype = Object.freeze({ [TypeId]: TypeId, asFunctionComponent

( this: Component.Component & Async, runtimeRef: React.RefObject>>, ) { const SuspenseInner = (props: { readonly promise: Promise }) => React.use(props.promise) return ({ fallback, name, ...props }: AsyncProps) => { const promise = Runtime.runPromise(runtimeRef.current)( Effect.andThen( Component.useScope([], this), scope => Effect.provideService(this.body(props as P), Scope.Scope, scope), ) ) return React.createElement( React.Suspense, { fallback: fallback ?? this.defaultFallback, name }, React.createElement(SuspenseInner, { promise }), ) } }, } as const) export const isAsync = (u: unknown): u is Async => Predicate.hasProperty(u, TypeId) export const async = >( self: T ): ( & Omit> & Component.Component< Component.Component.Props & AsyncProps, Component.Component.Success, Component.Component.Error, Component.Component.Context > & Async ) => Object.setPrototypeOf( Object.assign(function() {}, self), Object.freeze(Object.setPrototypeOf( Object.assign({}, AsyncPrototype), Object.getPrototypeOf(self), )), ) export const withOptions: { & Async>( options: Partial ): (self: T) => T & Async>( self: T, options: Partial, ): T } = Function.dual(2, & Async>( self: T, options: Partial, ): T => Object.setPrototypeOf( Object.assign(function() {}, self, options), Object.getPrototypeOf(self), ))