import { useEffect, useRef } from 'react'; import { useTheme } from '../../contexts/ThemeContext'; import type { Project, ProjectSession } from '../../types/app'; type PluginTabContentProps = { pluginName: string; selectedProject: Project | null; selectedSession: ProjectSession | null; }; export default function PluginTabContent({ pluginName, selectedProject, selectedSession, }: PluginTabContentProps) { const iframeRef = useRef(null); const { isDarkMode } = useTheme(); const iframeSrc = `/api/plugins/${encodeURIComponent(pluginName)}/assets/index.html`; // Send context to iframe when it loads or when context changes. // Use '*' as targetOrigin because the sandbox (without allow-same-origin) gives the // iframe an opaque origin that cannot be matched with a specific origin string. useEffect(() => { const iframe = iframeRef.current; if (!iframe) return; const sendContext = () => { iframe.contentWindow?.postMessage( { type: 'ccui:context', theme: isDarkMode ? 'dark' : 'light', project: selectedProject ? { name: selectedProject.name, path: selectedProject.fullPath || selectedProject.path } : null, session: selectedSession ? { id: selectedSession.id, title: selectedSession.title } : null, }, '*', ); }; iframe.addEventListener('load', sendContext); // Also send when context changes (iframe already loaded) if (iframe.contentWindow) { sendContext(); } return () => { iframe.removeEventListener('load', sendContext); }; }, [isDarkMode, selectedProject, selectedSession]); // Listen for messages from plugin iframe. // We verify by event.source rather than event.origin because the sandboxed iframe // (without allow-same-origin) has an opaque origin that shows up as "null". useEffect(() => { const handleMessage = (event: MessageEvent) => { // Only accept messages originating from our plugin iframe if (event.source !== iframeRef.current?.contentWindow) return; if (!event.data || typeof event.data !== 'object') return; const { type } = event.data; switch (type) { case 'ccui:request-context': { // Plugin is requesting current context iframeRef.current?.contentWindow?.postMessage( { type: 'ccui:context', theme: isDarkMode ? 'dark' : 'light', project: selectedProject ? { name: selectedProject.name, path: selectedProject.fullPath || selectedProject.path } : null, session: selectedSession ? { id: selectedSession.id, title: selectedSession.title } : null, }, '*', ); break; } default: break; } }; window.addEventListener('message', handleMessage); return () => window.removeEventListener('message', handleMessage); }, [isDarkMode, selectedProject, selectedSession]); return (