import { HTML_NAMESPACE } from "./constants.js";
import {
ElementProps,
JSXChildTypes,
NonBooleanPrimitive,
Ref,
VElement,
VNode,
WebJSXManagedElement,
} from "./types.js";
/**
* Flattens nested virtual nodes by replacing Fragments with their children.
* @param vnodes Virtual nodes to flatten
* @returns Array of flattened virtual nodes
*/
export function flattenVNodes(
vnodes: JSXChildTypes,
result: VNode[] = []
): VNode[] {
if (Array.isArray(vnodes)) {
for (const vnode of vnodes) {
flattenVNodes(vnode, result);
}
} else if (isValidVNode(vnodes)) {
result.push(vnodes);
}
return result;
}
export function isValidVNode(
vnode: VNode | boolean | null | undefined
): vnode is VNode {
const typeofVNode = typeof vnode;
return (
vnode !== null &&
vnode !== undefined &&
(typeofVNode === "string" ||
typeofVNode === "object" ||
typeofVNode === "number" ||
typeofVNode === "bigint")
);
}
/* Get Child Nodes Efficiently */
export function getChildNodes(parent: Node): Node[] {
const nodes: Node[] = [];
let current: Node | null = parent.firstChild;
while (current) {
nodes.push(current);
current = current.nextSibling;
}
return nodes;
}
/**
* Assigns a ref to a DOM node.
* @param node Target DOM node
* @param ref Reference to assign (function or object with current property)
*/
export function assignRef(node: Node, ref: Ref): void {
if (typeof ref === "function") {
ref(node);
} else if (ref && typeof ref === "object") {
ref.current = node;
}
}
export function isVElement(vnode: VNode): vnode is VElement {
const typeofVNode = typeof vnode;
return (
typeofVNode !== "string" &&
typeofVNode !== "number" &&
typeofVNode !== "bigint"
);
}
export function isNonBooleanPrimitive(
vnode: VNode
): vnode is NonBooleanPrimitive {
const typeofVNode = typeof vnode;
return (
typeofVNode === "string" ||
typeofVNode === "number" ||
typeofVNode === "bigint"
);
}
export function getNamespaceURI(node: Node): string | undefined {
return node instanceof Element && node.namespaceURI !== HTML_NAMESPACE
? node.namespaceURI ?? undefined
: undefined;
}
export function setWebJSXProps(
element: Element | ShadowRoot,
props: ElementProps
) {
(element as WebJSXManagedElement).__webjsx_props = props;
}
export function getWebJSXProps(element: Element | ShadowRoot) {
let props = (element as WebJSXManagedElement).__webjsx_props;
if (!props) {
props = {};
(element as WebJSXManagedElement).__webjsx_props = props;
}
return props;
}
export function setWebJSXChildNodeCache(
element: Element | ShadowRoot,
childNodes: Node[]
) {
(element as WebJSXManagedElement).__webjsx_childNodes = childNodes;
}
export function getWebJSXChildNodeCache(
element: Element | ShadowRoot
): Node[] | undefined {
return (element as WebJSXManagedElement).__webjsx_childNodes;
}