@meonode/ui
Version:
A structured approach to component composition with built-in theming, prop separation, and dynamic children handling.
138 lines • 6.55 kB
TypeScript
import type { Attributes as ReactAttributes, ComponentProps, CSSProperties, ReactNode, JSX, ElementType, ComponentType, JSXElementConstructor, Component, Ref } from 'react';
import type { Root as ReactDOMRoot } from 'react-dom/client';
export type NodeElement = ReactNode | Component<any, any, any> | ElementType | ComponentType<any> | NodeInstance<any> | ((props?: any) => ReactNode | Promise<ReactNode> | Component<any, any, any> | NodeInstance<any> | ComponentNode);
/**
* Defines valid child types that can be passed to a node:
* - ReactNode: Any valid React child (elements, strings, numbers, etc.)
* - ElementType: React component types (functions/classes)
* - NodeInstance: Other node instances in the tree
* - Function: Lazy child evaluation, useful for conditional rendering and hooks
*/
export type Children = ReactNode | Component<any> | NodeElement | NodeInstance<any> | ComponentNode;
/**
* Forward declaration of the BaseNode interface to avoid circular dependencies.
* Defines the core structure and capabilities of a BaseNode instance.
* @template T - The type of React element/component that this node represents
*/
export interface NodeInstance<T extends NodeElement = NodeElement> {
/** The underlying React element or component type that this node will render */
readonly element: T;
/** Original props passed during node construction, preserved for cloning/recreation */
readonly rawProps: RawNodeProps<T>;
readonly isBaseNode: true;
/** Converts this node instance into a renderable React element/tree */
render(): ReactNode;
/** Creates Portal-compatible React elements for rendering outside of the DOM tree */
toPortal(): ReactDOMRoot | null;
}
/**
* Extracts the props type from a given element type, handling both intrinsic (HTML) elements
* and custom React components.
* @template E - The element type to extract props from
*/
export type PropsOf<E extends NodeElement> = E extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[E] : E extends JSXElementConstructor<any> ? ComponentProps<E> : NodeInstance<E>;
/**
* Theme configuration object that can be passed through the node tree.
* Supports nested theme properties for complex styling systems:
* - Simple values (strings, numbers)
* - Nested theme objects with unlimited depth
* - Common CSS values and units
* - Custom theme variables and tokens
* Used for consistent styling and dynamic theme application.
*/
export interface Theme {
[key: string]: string | number | boolean | null | undefined | any | Theme | Record<string, Theme | string | number | boolean | null | undefined | any>;
}
/**
* Internal props type used by BaseNode instances after initial processing.
* Ensures consistent prop shape throughout the node's lifecycle:
* - Normalizes style properties into a CSSProperties object
* - Processes children into known concrete types
* - Handles theme context propagation
* @template E - The element type these props apply to
*/
export type FinalNodeProps = ReactAttributes & {
ref?: Ref<unknown>;
style?: CSSProperties;
children?: Children | Children[];
theme?: Theme;
nodetheme?: Theme;
};
/**
* Helper type to determine if the props P have a 'style' property
* that is compatible with CSSProperties.
* @template P - The props object of a component (e.g., PropsOf<E>)
*/
type HasCSSCompatibleStyleProp<P> = P extends {
style?: infer S;
} ? S extends CSSProperties | undefined ? true : false : false;
/**
* Public API for node creation props, providing a flexible and type-safe interface:
* - Preserves original component props while allowing direct style properties (conditionally)
* - Supports both single and array children
* - Enables theme customization
* - Maintains React's key prop for reconciliation
* @template E - The element type these props apply to
*/
export type NodeProps<E extends NodeElement> = Omit<PropsOf<E>, keyof CSSProperties | 'children'> & ReactAttributes & (HasCSSCompatibleStyleProp<PropsOf<E>> extends true ? CSSProperties : object) & Partial<{
props: Partial<Omit<PropsOf<E>, 'children'>>;
children: Children | Children[];
theme: Theme;
}>;
/**
* BaseNode's internal props type, extending NodeProps:
* - Makes all properties optional for flexible node creation
* - Adds nodetheme for theme context handling
* - Used for both initial construction and internal state
* @template E - The element type these props apply to
*/
export type RawNodeProps<E extends NodeElement> = Partial<NodeProps<E>> & {
nodetheme?: Theme;
};
/**
* Props interface for the internal FunctionRenderer component.
* Handles dynamic function children within React's component lifecycle:
* - Ensures proper timing of function evaluation
* - Maintains theme context for rendered content
* - Enables hook usage in function children
*/
export interface FunctionRendererProps<E extends NodeElement> {
/** Function that returns the child content to render */
render: (props?: NodeProps<E>) => ReactNode | NodeInstance<E>;
/** Theme context to be applied to the rendered content */
passedTheme?: Theme;
/** Optional key prop to help React identify unique instances in lists */
passedKey?: string;
processRawNode: (node: NodeElement, parentTheme?: Theme, childIndex?: number) => NodeElement;
}
export type ComponentNode = (NodeInstance<any> | ReactNode) | (() => NodeInstance<any> | ReactNode);
/**
* Props type for components rendered through the Portal HOC.
* Extends the component's own props with portal-specific functionality.
* @template T The component's own prop types
*/
export type PortalProps<T extends Record<string, any>> = T & {
/** Content to render within the portal */
children?: NodeElement | NodeElement[];
/** Portal control object containing lifecycle methods */
portal: {
/** Unmounts and cleans up the portal */
unmount: () => void;
};
};
/**
* Function type for creating portal instances.
* Allows passing providers through props at portal creation time.
* @template P The portal content component's prop types
*/
export type PortalLauncher<P extends Record<string, any>> = (props: P & {
/** Optional provider components to wrap the portal content */
provider?: NodeInstance<any>
/**
* @deprecated
* Use a single NodeInstance instead of an array for fixed provider.
*/
| NodeInstance<any>[];
} & Omit<PortalProps<P>, 'portal'>) => ReactDOMRoot | null;
export {};
//# sourceMappingURL=node.type.d.ts.map