ai-chatbot/lib/canvas/agent-view-interaction-guard.ts

57 lines
1.7 KiB
TypeScript

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;
}