import React from 'react'; /** * Creates a React component wrapper for a Web Component */ export function createReactComponent( tagName: string, events: string[] = [] ): React.ForwardRefExoticComponent & React.RefAttributes> { return React.forwardRef((props: any, ref) => { const elementRef = React.useRef(null); React.useImperativeHandle(ref, () => elementRef.current as T); React.useEffect(() => { const element = elementRef.current; if (!element) return; // Filter out special React props and event listeners const filteredProps = { ...props }; delete filteredProps.children; delete filteredProps.ref; delete filteredProps.className; // Handle properties and attributes Object.keys(filteredProps).forEach(key => { if (key.startsWith('on') && events.includes(key.toLowerCase().substring(2))) { // Event listeners are handled separately if needed return; } const value = filteredProps[key]; // If the key exists as a property on the element, set it if (key in element) { (element as any)[key] = value; } else { // Otherwise set it as an attribute if (typeof value === 'boolean') { if (value) element.setAttribute(key, ''); else element.removeAttribute(key); } else if (value != null) { element.setAttribute(key, String(value)); } else { element.removeAttribute(key); } } }); // Special handling for className if (props.className) { element.className = props.className; } }, [props]); // Setup event listeners React.useEffect(() => { const element = elementRef.current; if (!element) return; const handlers: { name: string; handler: any }[] = []; events.forEach(eventName => { const propName = `on${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`; const handler = props[propName]; if (handler) { element.addEventListener(eventName, handler); handlers.push({ name: eventName, handler }); } }); return () => { handlers.forEach(({ name, handler }) => { element.removeEventListener(name, handler); }); }; }, [props, ...events.map(e => props[`on${e.charAt(0).toUpperCase()}${e.slice(1)}`])]); return React.createElement(tagName, { ref: elementRef, class: props.className, // Web Components often use 'class' instead of 'className' ...(() => { // Pass through only basic attributes to the actual element tag // to avoid React warnings about unknown props on intrinsic elements const attrs: any = {}; if (props.id) attrs.id = props.id; if (props.style) attrs.style = props.style; if (props.slot) attrs.slot = props.slot; return attrs; })() }, props.children); }); }