/** * @license * SPDX-License-Identifier: Apache-2.0 */ /* tslint:disable */ import React, {useEffect, useRef} from 'react'; import {InteractionData} from '../types'; interface GeneratedContentProps { htmlContent: string; onInteract: (data: InteractionData) => void; appContext: string | null; isLoading: boolean; // Added isLoading prop } export const GeneratedContent: React.FC = ({ htmlContent, onInteract, appContext, isLoading, }) => { const contentRef = useRef(null); const processedHtmlContentRef = useRef(null); // Ref to track processed content useEffect(() => { const container = contentRef.current; if (!container) return; const handleClick = (event: MouseEvent) => { let targetElement = event.target as HTMLElement; while ( targetElement && targetElement !== container && !targetElement.dataset.interactionId ) { targetElement = targetElement.parentElement as HTMLElement; } if (targetElement && targetElement.dataset.interactionId) { event.preventDefault(); let interactionValue: string | undefined = targetElement.dataset.interactionValue; if (targetElement.dataset.valueFrom) { const inputElement = document.getElementById( targetElement.dataset.valueFrom, ) as HTMLInputElement | HTMLTextAreaElement; if (inputElement) { interactionValue = inputElement.value; } } const interactionData: InteractionData = { id: targetElement.dataset.interactionId, type: targetElement.dataset.interactionType || 'generic_click', value: interactionValue, elementType: targetElement.tagName.toLowerCase(), elementText: ( targetElement.innerText || (targetElement as HTMLInputElement).value || '' ) .trim() .substring(0, 75), appContext: appContext, }; onInteract(interactionData); } }; container.addEventListener('click', handleClick); // Process scripts only when loading is complete and content has changed if (!isLoading) { if (htmlContent !== processedHtmlContentRef.current) { const scripts = Array.from(container.getElementsByTagName('script')); scripts.forEach((oldScript) => { try { const newScript = document.createElement('script'); Array.from(oldScript.attributes).forEach((attr) => newScript.setAttribute(attr.name, attr.value), ); newScript.text = oldScript.innerHTML; if (oldScript.parentNode) { oldScript.parentNode.replaceChild(newScript, oldScript); } else { console.warn( 'Script tag found without a parent node:', oldScript, ); } } catch (e) { console.error( 'Error processing/executing script tag. This usually indicates a syntax error in the LLM-generated script.', { scriptContent: oldScript.innerHTML.substring(0, 500) + (oldScript.innerHTML.length > 500 ? '...' : ''), error: e, }, ); } }); processedHtmlContentRef.current = htmlContent; // Mark this content as processed } } else { // If loading, reset the processed content ref. This ensures that when loading finishes, // the new content (even if identical to a previous state before loading) is processed. processedHtmlContentRef.current = null; } return () => { container.removeEventListener('click', handleClick); }; }, [htmlContent, onInteract, appContext, isLoading]); return (
); };