From 41571ea37766326b4134118d333860114f5b8b86 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Sat, 25 Apr 2026 12:12:28 +0200 Subject: [PATCH] feat(front-component-renderer): forward offset/movement coordinates on serialised events (#20046) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Adds `offsetX`, `offsetY`, `movementX`, `movementY` to `SerializedEventData` and the host event serialiser so apps can reason about element-relative pointer positions without trying to read the host element's bounding rect (which is impossible from a remote-DOM worker). ## Motivation I was building a front-component with click-to-drop-pin and trackpad pan/zoom (custom OSM tile renderer). Two real bugs surfaced from the current event-serialisation surface: 1. **Wheel pan/zoom was broken.** The host already forwards `deltaX`/`deltaY`, but app authors naturally read them off the React-style event handler argument as `e.deltaX`/`e.deltaY`. Because remote-DOM bridges everything via `RemoteEvent extends CustomEvent`, the payload actually arrives at `e.detail.deltaX`. Reading the wrong place gives `undefined`, and `undefined < 0 === false`, so every wheel notch zoomed in the same direction. App code now uses `e.detail`, but this was a sharp papercut worth flagging in docs / a helper (separate change). 2. **Element-local click coords are unobtainable from a worker.** With only `clientX/Y`, an app needs the stage's bounding rect to translate viewport coordinates to local — which can't be read across the worker boundary. `offsetX`/`offsetY` close that gap with a one-read solution. `movementX`/`movementY` round out the set for any future drag-style interactions if `mousemove` later joins the allow-list. --- .../src/constants/SerializedEventData.ts | 4 ++++ .../src/host/utils/createHtmlHostWrapper.ts | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/packages/twenty-front-component-renderer/src/constants/SerializedEventData.ts b/packages/twenty-front-component-renderer/src/constants/SerializedEventData.ts index ad69807862..7e5bb4d3b0 100644 --- a/packages/twenty-front-component-renderer/src/constants/SerializedEventData.ts +++ b/packages/twenty-front-component-renderer/src/constants/SerializedEventData.ts @@ -10,6 +10,10 @@ export type SerializedEventData = { pageY?: number; screenX?: number; screenY?: number; + offsetX?: number; + offsetY?: number; + movementX?: number; + movementY?: number; button?: number; buttons?: number; key?: string; diff --git a/packages/twenty-front-component-renderer/src/host/utils/createHtmlHostWrapper.ts b/packages/twenty-front-component-renderer/src/host/utils/createHtmlHostWrapper.ts index dd12398e24..80e5c68b1b 100644 --- a/packages/twenty-front-component-renderer/src/host/utils/createHtmlHostWrapper.ts +++ b/packages/twenty-front-component-renderer/src/host/utils/createHtmlHostWrapper.ts @@ -81,6 +81,12 @@ const serializeEvent = (event: unknown): SerializedEventData => { if ('pageY' in domEvent) serialized.pageY = domEvent.pageY as number; if ('screenX' in domEvent) serialized.screenX = domEvent.screenX as number; if ('screenY' in domEvent) serialized.screenY = domEvent.screenY as number; + if ('offsetX' in domEvent) serialized.offsetX = domEvent.offsetX as number; + if ('offsetY' in domEvent) serialized.offsetY = domEvent.offsetY as number; + if ('movementX' in domEvent) + serialized.movementX = domEvent.movementX as number; + if ('movementY' in domEvent) + serialized.movementY = domEvent.movementY as number; if ('button' in domEvent) serialized.button = domEvent.button as number; if ('buttons' in domEvent) serialized.buttons = domEvent.buttons as number;