'use client'; import React, { useState, useEffect } from 'react'; import { finder } from '@medv/finder'; export function PickingHelper() { const [pickingMode, setPickingMode] = useState<'click' | 'scroll' | null>(null); const [hoveredElement, setHoveredElement] = useState(null); useEffect(() => { const handleMessage = (e: MessageEvent) => { if (e.data.type === 'START_PICKING') { setPickingMode(e.data.mode); } else if (e.data.type === 'STOP_PICKING') { setPickingMode(null); setHoveredElement(null); } else if (e.data.type === 'SET_HOVER_SELECTOR') { const selector = e.data.selector; if (selector) { const el = document.querySelector(selector) as HTMLElement; setHoveredElement(el || null); } else { setHoveredElement(null); } } }; window.addEventListener('message', handleMessage); return () => window.removeEventListener('message', handleMessage); }, []); useEffect(() => { if (!pickingMode) return; const handleMouseOver = (e: MouseEvent) => { const target = e.target as HTMLElement; if (target.closest('.record-mode-ignore') || target.closest('.feedback-ui-ignore')) return; setHoveredElement(target); }; const handleClick = (e: MouseEvent) => { if (hoveredElement) { e.preventDefault(); e.stopPropagation(); const selector = finder(hoveredElement, { root: document.body, seedMinLength: 3, optimizedMinLength: 2, className: (name) => !name.startsWith('record-mode-') && !name.startsWith('feedback-') && !name.includes('[') && !name.includes('/') && !name.match(/^[a-z]-[0-9]/) && !name.match(/[0-9]{4,}/), // Avoid dynamic IDs in classnames idName: (name) => !name.startsWith('__next') && !name.includes(':') && !name.match(/[0-9]{5,}/), }); const rect = hoveredElement.getBoundingClientRect(); window.parent.postMessage({ type: 'ELEMENT_SELECTED', selector, rect: { x: rect.left, y: rect.top, width: rect.width, height: rect.height }, tagName: hoveredElement.tagName.toLowerCase() }, '*'); setPickingMode(null); setHoveredElement(null); } }; const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') { setPickingMode(null); setHoveredElement(null); window.parent.postMessage({ type: 'PICKING_CANCELLED' }, '*'); } }; window.addEventListener('mouseover', handleMouseOver); window.addEventListener('click', handleClick, true); window.addEventListener('keydown', handleKeyDown); return () => { window.removeEventListener('mouseover', handleMouseOver); window.removeEventListener('click', handleClick, true); window.removeEventListener('keydown', handleKeyDown); }; }, [pickingMode, hoveredElement]); if (!hoveredElement) return null; // Don't show highlight if we are in picking mode but NOT hovering anything (handled by logic above) // but DO show if we have a hoveredElement (from message or mouseover) const rect = hoveredElement.getBoundingClientRect(); return (
{hoveredElement.tagName.toLowerCase()}
); }