This commit is contained in:
@@ -8,6 +8,13 @@ import { Memoized } from "./index.js"
|
|||||||
export const TypeId: unique symbol = Symbol.for("@effect-fc/Component/Component")
|
export const TypeId: unique symbol = Symbol.for("@effect-fc/Component/Component")
|
||||||
export type TypeId = typeof TypeId
|
export type TypeId = typeof TypeId
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface representing an Effect-based React Component.
|
||||||
|
*
|
||||||
|
* This is both:
|
||||||
|
* - an Effect that produces a React function component
|
||||||
|
* - a constructor-like object with component metadata and options
|
||||||
|
*/
|
||||||
export interface Component<P extends {}, A extends React.ReactNode, E, R>
|
export interface Component<P extends {}, A extends React.ReactNode, E, R>
|
||||||
extends
|
extends
|
||||||
Effect.Effect<(props: P) => A, never, Exclude<R, Scope.Scope>>,
|
Effect.Effect<(props: P) => A, never, Exclude<R, Scope.Scope>>,
|
||||||
@@ -20,7 +27,6 @@ extends
|
|||||||
readonly "~Error": E
|
readonly "~Error": E
|
||||||
readonly "~Context": R
|
readonly "~Context": R
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
readonly body: (props: P) => Effect.Effect<A, E, R>
|
readonly body: (props: P) => Effect.Effect<A, E, R>
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@@ -37,9 +43,22 @@ export declare namespace Component {
|
|||||||
|
|
||||||
export type AsComponent<T extends Component<any, any, any, any>> = Component<Props<T>, Success<T>, Error<T>, Context<T>>
|
export type AsComponent<T extends Component<any, any, any, any>> = Component<Props<T>, Success<T>, Error<T>, Context<T>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options that can be set on the component
|
||||||
|
*/
|
||||||
export interface Options {
|
export interface Options {
|
||||||
|
/** Custom displayName for React DevTools and debugging */
|
||||||
readonly displayName?: string
|
readonly displayName?: string
|
||||||
|
/**
|
||||||
|
* Strategy used when executing finalizers on unmount/scope close
|
||||||
|
* @default ExecutionStrategy.sequential
|
||||||
|
*/
|
||||||
readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy
|
readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy
|
||||||
|
/**
|
||||||
|
* Debounce time before executing finalizers after component unmount
|
||||||
|
* Helps avoid unnecessary work during fast remount/remount cycles
|
||||||
|
* @default "100 millis"
|
||||||
|
*/
|
||||||
readonly finalizerExecutionDebounce: Duration.DurationInput
|
readonly finalizerExecutionDebounce: Duration.DurationInput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,6 +337,11 @@ export declare namespace make {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an Effect-based React component.
|
||||||
|
*
|
||||||
|
* Follows the `Effect.fn` API. Supports both generator syntax (recommended) and direct Effect composition.
|
||||||
|
*/
|
||||||
export const make: (
|
export const make: (
|
||||||
& make.Gen
|
& make.Gen
|
||||||
& make.NonGen
|
& make.NonGen
|
||||||
@@ -346,6 +370,12 @@ export const make: (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `make` but creates an untraced version (no automatic span created).
|
||||||
|
* Useful for very low-level utilities or when you want full control over tracing.
|
||||||
|
*
|
||||||
|
* Follows the `Effect.fnUntraced` API.
|
||||||
|
*/
|
||||||
export const makeUntraced: (
|
export const makeUntraced: (
|
||||||
& make.Gen
|
& make.Gen
|
||||||
& make.NonGen
|
& make.NonGen
|
||||||
@@ -367,6 +397,9 @@ export const makeUntraced: (
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new component with modified options while preserving original behavior.
|
||||||
|
*/
|
||||||
export const withOptions: {
|
export const withOptions: {
|
||||||
<T extends Component<any, any, any, any>>(
|
<T extends Component<any, any, any, any>>(
|
||||||
options: Partial<Component.Options>
|
options: Partial<Component.Options>
|
||||||
@@ -383,6 +416,39 @@ export const withOptions: {
|
|||||||
Object.getPrototypeOf(self),
|
Object.getPrototypeOf(self),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps an Effect-FC `Component` and turns it into a regular React function component
|
||||||
|
* that serves as an **entrypoint** into an Effect-FC component hierarchy.
|
||||||
|
*
|
||||||
|
* This is the recommended way to connect Effect-FC components to the rest of your React app,
|
||||||
|
* especially when using routers (TanStack Router, React Router, etc.), lazy-loaded routes,
|
||||||
|
* or any place where a standard React component is expected.
|
||||||
|
*
|
||||||
|
* The runtime is obtained from the provided React Context, allowing you to:
|
||||||
|
* - Provide dependencies once at a high level
|
||||||
|
* - Use the same runtime across an entire route tree or feature
|
||||||
|
*
|
||||||
|
* @example Using TanStack Router
|
||||||
|
* ```tsx
|
||||||
|
* // Main
|
||||||
|
* export const runtime = ReactRuntime.make(Layer.empty)
|
||||||
|
* function App() {
|
||||||
|
* return (
|
||||||
|
* <ReactRuntime.Provider runtime={runtime}>
|
||||||
|
* <RouterProvider router={router} />
|
||||||
|
* </ReactRuntime.Provider>
|
||||||
|
* )
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // Route
|
||||||
|
* export const Route = createFileRoute("/")({
|
||||||
|
* component: withRuntime(HomePage, runtime.context),
|
||||||
|
* })
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param self - The Effect-FC Component you want to render as a regular React component.
|
||||||
|
* @param context - React Context that holds the Runtime to use for this component tree. See the `ReactRuntime` module to create one.
|
||||||
|
*/
|
||||||
export const withRuntime: {
|
export const withRuntime: {
|
||||||
<P extends {}, A extends React.ReactNode, E, R>(
|
<P extends {}, A extends React.ReactNode, E, R>(
|
||||||
context: React.Context<Runtime.Runtime<R>>,
|
context: React.Context<Runtime.Runtime<R>>,
|
||||||
|
|||||||
Reference in New Issue
Block a user