import React, { createContext, useContext, useState, useRef, useCallback, useMemo, MutableRefObject } from 'react'; export interface SelectedElement { id: string; selectorPath: string; tagName: string; className: string; outerHTML: string; computedStyles: Record; screenshot?: string; boundingRect: { x: number; y: number; width: number; height: number }; semanticType?: 'agent-card' | 'message' | 'tool-call' | 'tool-group' | 'view-card' | 'browser-card' | 'dom-element'; semanticLabel?: string; semanticData?: Record; } interface ElementSelectionContextValue { selectMode: boolean; toggleSelectMode: () => void; setSelectMode: (active: boolean) => void; excludeSelectId: string | null; setExcludeSelectId: (id: string | null) => void; activeOwnerId: string | null; setActiveOwnerId: (id: string | null) => void; selectedElements: SelectedElement[]; addSelectedElement: (el: SelectedElement) => void; updateSelectedElement: (id: string, patch: Partial) => void; removeSelectedElement: (id: string) => void; clearSelectedElements: () => void; elementsByOwner: Record; addElementForOwner: (ownerId: string, el: SelectedElement) => void; removeOwnerElement: (ownerId: string, elementId: string) => void; clearOwnerElements: (ownerId: string) => void; iframeRef: MutableRefObject; } const ElementSelectionContext = createContext(null); export function useElementSelection() { return useContext(ElementSelectionContext); } export const ElementSelectionProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [selectMode, setSelectMode] = useState(false); const [excludeSelectId, setExcludeSelectId] = useState(null); const [activeOwnerId, setActiveOwnerId] = useState(null); const [elementsByOwner, setElementsByOwner] = useState>({}); const iframeRef = useRef(null); const activeOwnerIdRef = useRef(activeOwnerId); activeOwnerIdRef.current = activeOwnerId; const selectedElements = useMemo( () => (activeOwnerId ? elementsByOwner[activeOwnerId] ?? [] : []), [activeOwnerId, elementsByOwner], ); const toggleSelectMode = useCallback(() => { setSelectMode((prev) => { if (prev) setExcludeSelectId(null); return !prev; }); }, []); const addSelectedElement = useCallback((el: SelectedElement) => { const ownerId = activeOwnerIdRef.current; if (!ownerId) return; setElementsByOwner((prev) => { const existing = prev[ownerId] ?? []; if (existing.some((e) => e.id === el.id)) return prev; return { ...prev, [ownerId]: [...existing, el] }; }); }, []); const updateSelectedElement = useCallback((id: string, patch: Partial) => { const ownerId = activeOwnerIdRef.current; if (!ownerId) return; setElementsByOwner((prev) => { const existing = prev[ownerId]; if (!existing) return prev; return { ...prev, [ownerId]: existing.map((e) => (e.id === id ? { ...e, ...patch } : e)) }; }); }, []); const removeSelectedElement = useCallback((id: string) => { const ownerId = activeOwnerIdRef.current; if (!ownerId) return; setElementsByOwner((prev) => { const existing = prev[ownerId]; if (!existing) return prev; return { ...prev, [ownerId]: existing.filter((e) => e.id !== id) }; }); }, []); const clearSelectedElements = useCallback(() => { const ownerId = activeOwnerIdRef.current; if (!ownerId) return; setElementsByOwner((prev) => { if (!prev[ownerId]?.length) return prev; return { ...prev, [ownerId]: [] }; }); }, []); const addElementForOwner = useCallback((ownerId: string, el: SelectedElement) => { setElementsByOwner((prev) => { const existing = prev[ownerId] ?? []; if (existing.some((e) => e.semanticData?.selectId === el.semanticData?.selectId)) return prev; return { ...prev, [ownerId]: [...existing, el] }; }); }, []); const removeOwnerElement = useCallback((ownerId: string, elementId: string) => { setElementsByOwner((prev) => { const existing = prev[ownerId]; if (!existing) return prev; return { ...prev, [ownerId]: existing.filter((e) => e.id !== elementId) }; }); }, []); const clearOwnerElements = useCallback((ownerId: string) => { setElementsByOwner((prev) => { if (!prev[ownerId]?.length) return prev; return { ...prev, [ownerId]: [] }; }); }, []); return ( {children} ); };