import { Effect, Function, Predicate, Runtime, Scope } from "effect" import * as React from "react" import type * as Component from "./Component.js" export const TypeId: unique symbol = Symbol.for("effect-fc/Suspense") export type TypeId = typeof TypeId export interface Suspense extends Suspense.Options { readonly [TypeId]: TypeId } export namespace Suspense { export interface Options { readonly defaultFallback?: React.ReactNode } export type Props = Omit } const SuspenseProto = Object.freeze({ [TypeId]: TypeId, makeFunctionComponent

( this: Component.Component & Suspense, runtimeRef: React.RefObject>>, scope: Scope.Scope, ) { const SuspenseInner = (props: { readonly promise: Promise }) => React.use(props.promise) return ({ fallback, name, ...props }: Suspense.Props) => { const promise = Runtime.runPromise(runtimeRef.current)( 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 isSuspense = (u: unknown): u is Suspense => Predicate.hasProperty(u, TypeId) export const suspense = >( self: T ): ( & Omit> & Component.Component< Component.Component.Props & Suspense.Props, Component.Component.Success, Component.Component.Error, Component.Component.Context > & Suspense ) => Object.setPrototypeOf( Object.assign(function() {}, self), Object.freeze(Object.setPrototypeOf( Object.assign({}, SuspenseProto), Object.getPrototypeOf(self), )), ) export const withOptions: { & Suspense>( options: Partial ): (self: T) => T & Suspense>( self: T, options: Partial, ): T } = Function.dual(2, & Suspense>( self: T, options: Partial, ): T => Object.setPrototypeOf( Object.assign(function() {}, self, options), Object.getPrototypeOf(self), ))