export const CANVAS_AGENT_VIEW_INTERACTION_DEFER_MS = 700; const CANVAS_AGENT_VIEW_OPERATION_TARGET_SELECTOR = [ '[data-canvas-workspace-root="true"]', "[data-canvas-node-id]", "[data-canvas-overlay]", ].join(", "); const EDITABLE_SELECTOR = [ "input", "textarea", "select", '[contenteditable="true"]', '[role="textbox"]', ].join(", "); export function isCanvasAgentViewOperationTarget(target: EventTarget | null) { return target instanceof Element ? Boolean(target.closest(CANVAS_AGENT_VIEW_OPERATION_TARGET_SELECTOR)) : false; } export function isCanvasAgentViewEditableElement(params: { activeElement?: Element | null; rootElement?: Element | null; }) { const activeElement = params.activeElement; if (!(activeElement instanceof HTMLElement)) return false; if (params.rootElement && !params.rootElement.contains(activeElement)) { return false; } return activeElement.isContentEditable || Boolean(activeElement.closest(EDITABLE_SELECTOR)); } export function shouldDeferCanvasAgentViewOperation(params: { activeEditable?: boolean; deferMs?: number; lastPointerInteractionAt?: number | null; now?: number; pointerDown?: boolean; }) { if (params.pointerDown) return true; if (params.activeEditable) return true; const lastPointerInteractionAt = Number(params.lastPointerInteractionAt || 0); if (lastPointerInteractionAt <= 0) return false; const now = Number.isFinite(Number(params.now)) ? Number(params.now) : Date.now(); const deferMs = Math.max( 0, Number.isFinite(Number(params.deferMs)) ? Number(params.deferMs) : CANVAS_AGENT_VIEW_INTERACTION_DEFER_MS ); return now - lastPointerInteractionAt < deferMs; }