import { createElement, type ElementType, type FunctionComponent, type ReactNode, } from 'react'; import { useC42, useC42Events, type C42ControllerClass, type C42EventHandler, } from './useC42'; export interface C42Props { /** The headless controller class from `@42/core`. */ controller: C42ControllerClass; /** Options forwarded to the controller constructor / `update()`. */ options?: O; /** Values that trigger an options re-sync (see {@link useC42}). */ deps?: unknown[]; /** Element/tag to render as the controller root. Defaults to `"div"`. */ as?: ElementType; /** * Map of `data-c42-*` DOM event names to handlers, e.g. * `{ "accordion:change": (detail) => ... }`. Each handler receives the * unwrapped `event.detail` and the original `CustomEvent`. */ events?: Record; /** Children rendered inside the root. */ children?: ReactNode; /** * Raw HTML used as the root's initial markup when no `children` are given. * Useful for rendering a `data-c42-*` skeleton the controller enhances. */ html?: string; className?: string; // Any extra props are forwarded to the rendered element. [key: string]: unknown; } /** * Generic bridge that mounts any `@42/core` controller onto a rendered element. * * ```tsx * import { Accordion } from "@42/core/accordion"; * console.log(d) }}> * …markup… * * ``` */ export function C42(props: C42Props) { const { controller, options, deps = [], as = 'div', events, children, html, className, ...rest } = props; const ref = useC42(controller, options, deps); useC42Events(ref, events ?? {}); const content = children != null ? { children } : html != null ? { dangerouslySetInnerHTML: { __html: html } } : {}; // `createElement`'s overloads don't accept a bare `ElementType`; casting the // tag to a component shape is the standard escape hatch for a dynamic `as`. const Component = as as unknown as FunctionComponent>; return createElement(Component, { ref, className, ...rest, ...content }); }