import type { HTMLTag, MarkdownRuntime } from '@intlayer/core';
import {
cloneElement,
createElement,
Fragment,
type ReactElement,
type ReactNode,
} from 'react';
/**
* React-specific runtime for the markdown processor.
* Implements the MarkdownRuntime interface using React's primitives.
*/
export const reactRuntime: MarkdownRuntime = {
/**
* Creates a React element.
* Handles the conversion of props and children to React format.
*/
createElement: (
type: string | any,
props: Record<string, any> | null,
...children: any[]
): ReactNode => {
// React accepts children as rest args or as a single array
// If there's only one child, pass it directly to avoid unnecessary array
if (children.length === 0) {
return createElement(type, props);
}
if (children.length === 1) {
return createElement(type, props, children[0]);
}
return createElement(type, props, ...children);
},
/**
* Clones a React element with new props.
*/
cloneElement: (
element: unknown,
props: Record<string, any>,
...children: any[]
): ReactNode => {
if (children.length === 0) {
return cloneElement(element as ReactElement, props);
}
return cloneElement(element as ReactElement, props, ...children);
},
/**
* React Fragment component.
*/
Fragment,
/**
* React-specific prop normalization.
* React uses className instead of class, htmlFor instead of for, etc.
* The core processor already handles ATTRIBUTE_TO_NODE_PROP_MAP,
* so this is mostly a no-op but can be used for additional React-specific transforms.
*/
normalizeProps: (
_tag: HTMLTag,
props: Record<string, any>
): Record<string, any> => {
// The core already handles class -> className and for -> htmlFor
// via ATTRIBUTE_TO_NODE_PROP_MAP in the attrStringToMap function.
// This hook is available for any additional React-specific transforms.
return props;
},
};
/**
* Creates a React runtime with custom createElement for advanced use cases.
* Useful for wrapping elements or adding middleware.
*/
export const createReactRuntime = (
options: {
onCreateElement?: (
type: string | any,
props: Record<string, any> | null,
children: any[]
) => ReactNode;
} = {}
): MarkdownRuntime => {
const { onCreateElement } = options;
if (onCreateElement) {
return {
...reactRuntime,
createElement: (
type: string | any,
props: Record<string, any> | null,
...children: any[]
): ReactNode => {
return onCreateElement(type, props, children);
},
};
}
return reactRuntime;
};
export default reactRuntime;