fix: industrial accuracy for record mode events via cross-window sync

This commit is contained in:
2026-02-15 18:10:59 +01:00
parent 4e762ebfdf
commit 460eeec0bb

View File

@@ -60,6 +60,15 @@ export function RecordModeProvider({ children }: { children: React.ReactNode })
const [zoomLevel, setZoomLevel] = useState(1);
const [isBlurry, setIsBlurry] = useState(false);
const [isFeedbackActive, setIsFeedbackActiveState] = useState(false);
const [isEmbedded, setIsEmbedded] = useState(false);
useEffect(() => {
const embedded = typeof window !== 'undefined' &&
(window.location.search.includes('embedded=true') ||
window.name === 'record-mode-iframe' ||
window.self !== window.top);
setIsEmbedded(embedded);
}, []);
// Synchronous mutually exclusive setters
const setIsActive = (active: boolean) => {
@@ -102,6 +111,48 @@ export function RecordModeProvider({ children }: { children: React.ReactNode })
}
}, [isFeedbackActive, isActive]);
// GUEST LISTENERS: Execute events coming from host
useEffect(() => {
if (!isEmbedded) return;
const handlePlaybackMessage = (e: MessageEvent) => {
if (e.data.type === 'PLAY_EVENT') {
const { event } = e.data;
if (event.selector) {
const el = document.querySelector(event.selector) as HTMLElement;
if (el) {
if (event.type === 'scroll') {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
} else if (event.type === 'click') {
// Get CURRENT rect for industrial precision
const currentRect = el.getBoundingClientRect();
const eventCoords = {
clientX: currentRect.left + currentRect.width / 2,
clientY: currentRect.top + currentRect.height / 2
};
const dispatchMouse = (type: string) => {
el.dispatchEvent(new MouseEvent(type, {
view: window,
bubbles: true,
cancelable: true,
...eventCoords
}));
};
dispatchMouse('mousedown');
dispatchMouse('mouseup');
dispatchMouse('click');
el.click();
}
}
}
}
};
window.addEventListener('message', handlePlaybackMessage);
return () => window.removeEventListener('message', handlePlaybackMessage);
}, [isEmbedded]);
const addEvent = (event: Omit<RecordEvent, 'id' | 'timestamp'>) => {
const newEvent: RecordEvent = {
...event,
@@ -151,42 +202,51 @@ export function RecordModeProvider({ children }: { children: React.ReactNode })
for (const event of sortedEvents) {
if (!isPlayingRef.current) break;
// 1. Move Cursor
if (event.rect) {
// 1. Move Cursor (Host logic)
if (event.rect && !isEmbedded) {
const iframe = document.querySelector('iframe[name="record-mode-iframe"]') as HTMLIFrameElement;
const iframeRect = iframe?.getBoundingClientRect();
// Add iframe offset to guest-relative coordinates
setCursorPosition({
x: event.rect.x + event.rect.width / 2,
y: event.rect.y + event.rect.height / 2,
x: (iframeRect?.left || 0) + event.rect.x + event.rect.width / 2,
y: (iframeRect?.top || 0) + event.rect.y + event.rect.height / 2,
});
}
// 2. Handle Action
if (event.selector) {
const el = document.querySelector(event.selector) as HTMLElement;
if (el) {
if (event.type === 'scroll') {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
} else if (event.type === 'click') {
// Precise industrial click sequence: mousedown -> mouseup -> click
const eventCoords = {
clientX: event.rect ? event.rect.x + event.rect.width / 2 : 0,
clientY: event.rect ? event.rect.y + event.rect.height / 2 : 0
};
const dispatchMouse = (type: string) => {
el.dispatchEvent(new MouseEvent(type, {
view: window,
bubbles: true,
cancelable: true,
...eventCoords
}));
};
dispatchMouse('mousedown');
dispatchMouse('mouseup');
dispatchMouse('click');
// Fallback for native elements
el.click();
if (!isEmbedded) {
// HOST: Delegate to Iframe
const iframe = document.querySelector('iframe[name="record-mode-iframe"]') as HTMLIFrameElement;
if (iframe?.contentWindow) {
iframe.contentWindow.postMessage({ type: 'PLAY_EVENT', event }, '*');
}
} else {
// GUEST (Self-execution failsafe)
const el = document.querySelector(event.selector) as HTMLElement;
if (el) {
if (event.type === 'scroll') {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
} else if (event.type === 'click') {
const currentRect = el.getBoundingClientRect();
const eventCoords = {
clientX: currentRect.left + currentRect.width / 2,
clientY: currentRect.top + currentRect.height / 2
};
const dispatchMouse = (type: string) => {
el.dispatchEvent(new MouseEvent(type, {
view: window,
bubbles: true,
cancelable: true,
...eventCoords
}));
};
dispatchMouse('mousedown');
dispatchMouse('mouseup');
dispatchMouse('click');
el.click();
}
}
}
}