From 7078ce2f2aab4b710d597f0b93de4ed96631fcfd Mon Sep 17 00:00:00 2001 From: Yanzhen Yu Date: Wed, 1 Apr 2026 12:00:00 +0800 Subject: [PATCH] add mouse interactions observer --- src/record/index.ts | 10 ++++++++++ src/record/observer.ts | 38 ++++++++++++++++++++++++++++++++++++++ src/types.ts | 39 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/record/index.ts b/src/record/index.ts index 5d543fcf..abc627cd 100644 --- a/src/record/index.ts +++ b/src/record/index.ts @@ -70,6 +70,16 @@ function record(options: recordOptions) { }, }), ), + mouseInteractionCb: d => + emit( + wrapEvent({ + type: EventType.IncrementalSnapshot, + data: { + source: IncrementalSource.MouseInteraction, + ...d, + }, + }), + ), }); }); } catch (error) { diff --git a/src/record/observer.ts b/src/record/observer.ts index b0b2482e..4f08b59c 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -9,6 +9,9 @@ import { observerParam, mousemoveCallBack, mousePosition, + handlerMap, + mouseInteractionCallBack, + MouseInteractions, } from '../types'; function initMutationObserver(cb: mutationCallBack): MutationObserver { @@ -139,11 +142,46 @@ function initMousemoveObserver(cb: mousemoveCallBack): () => void { }; } +function initMouseInteractionObserver( + cb: mouseInteractionCallBack, +): () => void { + const handlers: handlerMap = {}; + const getHandler = (eventKey: keyof typeof MouseInteractions) => { + return (event: MouseEvent) => { + const id = mirror.getId(event.target as INode); + const { clientX, clientY } = event; + cb({ + type: MouseInteractions[eventKey], + id, + x: clientX, + y: clientY, + }); + }; + }; + Object.keys(MouseInteractions) + .filter(key => Number.isNaN(Number(key))) + .forEach((eventKey: keyof typeof MouseInteractions) => { + const eventName = eventKey.toLowerCase(); + const handler = getHandler(eventKey); + handlers[eventName] = handler; + document.addEventListener(eventName, handler); + }); + return () => { + Object.keys(handlers).forEach(eventName => { + document.removeEventListener(eventName, handlers[eventName]); + }); + }; +} + export default function initObservers(o: observerParam) { const mutationObserver = initMutationObserver(o.mutationCb); const mousemoveHandler = initMousemoveObserver(o.mousemoveCb); + const mouseInteractionHandler = initMouseInteractionObserver( + o.mouseInteractionCb, + ); return { mutationObserver, mousemoveHandler, + mouseInteractionHandler, }; } diff --git a/src/types.ts b/src/types.ts index d141eb12..a2b8920e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,6 +34,7 @@ export type incrementalSnapshotEvent = { export enum IncrementalSource { Mutation, MouseMove, + MouseInteraction, } export type mutationData = { @@ -45,7 +46,14 @@ export type mousemoveData = { positions: mousePosition[]; }; -export type incrementalData = mutationData | mousemoveData; +export type mouseInteractionData = { + source: IncrementalSource.MouseInteraction; +} & mouseInteractionParam; + +export type incrementalData = + | mutationData + | mousemoveData + | mouseInteractionData; export type event = | domContentLoadedEvent @@ -64,6 +72,7 @@ export type recordOptions = { export type observerParam = { mutationCb: mutationCallBack; mousemoveCb: mousemoveCallBack; + mouseInteractionCb: mouseInteractionCallBack; }; export type textMutation = { @@ -99,7 +108,7 @@ type mutationCallbackParam = { export type mutationCallBack = (m: mutationCallbackParam) => void; -export type mousemoveCallBack = (m: mousePosition[]) => void; +export type mousemoveCallBack = (p: mousePosition[]) => void; export type mousePosition = { x: number; @@ -107,6 +116,32 @@ export type mousePosition = { timeOffset: number; }; +export type handlerMap = { + [key: string]: EventListener; +}; + +export enum MouseInteractions { + MouseUp, + MouseDown, + Click, + ContextMenu, + DblClick, + Focus, + Blur, + TouchStart, + TouchMove, + TouchEnd, +} + +type mouseInteractionParam = { + type: MouseInteractions; + id: number; + x: number; + y: number; +}; + +export type mouseInteractionCallBack = (d: mouseInteractionParam) => void; + export type Mirror = { map: idNodeMap; getId: (n: INode) => number;