import { Data, Predicate } from 'effect'; import type { Signal } from '../types/index.js'; import type { ElementProps, Portals, PortalFn } from '../schema/index.js'; import { EFFUSE_NODE, NodeType } from '../constants.js'; export type { ElementProps, Portals, PortalFn }; export { EFFUSE_NODE, NodeType }; export type EffuseChild = | EffuseNode | string | number | boolean | null | undefined | Signal | (() => EffuseChild) | EffuseChild[]; export interface BlueprintContext

> { readonly props: P; readonly state: Record; readonly portals: Portals; } export interface BlueprintDef

> { readonly _tag: 'Blueprint'; readonly name?: string | undefined; readonly props?: P | undefined; state?(props: P): Record; view(context: BlueprintContext

): EffuseChild; error?(error: Error): EffuseChild; loading?(): EffuseChild; } export interface Component< P = Record, > extends BlueprintDef

{ (props?: P): EffuseNode; } export type EffuseNode = Data.TaggedEnum<{ Element: { readonly [EFFUSE_NODE]: true; readonly tag: string; readonly props: ElementProps | null; readonly children: EffuseChild[]; readonly key?: string | number | undefined; }; Text: { readonly [EFFUSE_NODE]: true; readonly text: string; readonly key?: string | number | undefined; }; Fragment: { readonly [EFFUSE_NODE]: true; readonly children: EffuseChild[]; readonly key?: string | number | undefined; }; List: { readonly [EFFUSE_NODE]: true; readonly children: EffuseChild[]; readonly key?: string | number | undefined; }; Blueprint: { readonly [EFFUSE_NODE]: true; readonly blueprint: BlueprintDef; readonly props: Record; readonly portals: Portals | null; readonly key?: string | number | undefined; }; }>; const { $match, Element, Text, Fragment, List, Blueprint } = Data.taggedEnum(); export const isEffuseNode = (u: unknown): u is EffuseNode => Predicate.isObject(u) && Predicate.hasProperty(u, EFFUSE_NODE); export type ElementNodeInput = Omit; export type TextNodeInput = Omit; export type FragmentNodeInput = Omit; export type ListNodeInput = Omit; export type BlueprintNodeInput = Omit; export const CreateElementNode = (args: ElementNodeInput): ElementNode => Element(args); export const CreateTextNode = (args: TextNodeInput): TextNode => Text(args); export const CreateFragmentNode = (args: FragmentNodeInput): FragmentNode => Fragment(args); export const CreateListNode = (args: ListNodeInput): ListNode => List(args); export const CreateBlueprintNode = (args: BlueprintNodeInput): BlueprintNode => Blueprint(args); export const matchEffuseNode = $match; export type ElementNode = Extract; export type TextNode = Extract; export type FragmentNode = Extract; export type ListNode = Extract; export type BlueprintNode

> = Extract< EffuseNode, { _tag: 'Blueprint' } > & { props: P; blueprint: BlueprintDef

}; export const createTextNode = (text: string): TextNode => Text({ [EFFUSE_NODE]: true, text, }); export const createFragmentNode = (children: EffuseChild[]): FragmentNode => Fragment({ [EFFUSE_NODE]: true, children, }); export const createListNode = (children: EffuseChild[]): ListNode => List({ [EFFUSE_NODE]: true, children, }); export const isSignalChild = (value: unknown): value is Signal => { return ( Predicate.isObject(value) && 'value' in value && Predicate.isObject((value as Record)._subscribers) ); };