Adds the text-editing events input-heavy front components need:
`beforeinput`, `compositionstart/update/end` and `copy/paste/cut`,
allowed on `input` and `textarea` only.
These events carry payload: `beforeinput` forwards `inputType`/`data`
through a native host listener (React synthesizes `onBeforeInput`
without them), composition events forward `data`, and paste forwards
`clipboardData.getData('text')` capped at 100k chars. Clipboard text is
read only on an explicit paste into the component's own input, never on
copy/cut, and the worker synthesizes a minimal `clipboardData` so
`onPaste` handlers work. `beforeinput` is observe-only: `preventDefault`
cannot cross the async worker boundary.
Allow-listing these events makes the host bind them, so the
`buildHostReactPropsFromRemoteProps` test that pinned them as rejected
now pins events that are still unmapped.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22630?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
Front components are third-party UI that runs in a sandboxed worker, so
every DOM event reaching them has to be on an explicit allow-list. That
list was small: mostly click, focus and pointer events.
This adds touch, drag and drop, focusin/focusout,
animationend/transitionend and scrollend, plus load/error on `<img>` and
toggle on `<details>`/`<dialog>`.
Two of them need the host to do more than forward the event:
- react-dom has no `onFocusIn`/`onFocusOut` props, so the host attaches
those two with `addEventListener` instead.
- a browser only fires `drop` on an element whose `dragover` default was
prevented, and the component's own `preventDefault` arrives too late
across the async worker boundary. The host prevents it synchronously as
soon as the component declares either handler.
Touch events carry their coordinates on `changedTouches`, so the first
touch fills the existing coordinate fields.
Still not crossing, since each would need a new serialized field: touch
lists, `animationName`/`propertyName`/`elapsedTime`, toggle `newState`
and `dataTransfer`.
The diff also renames a few things it touches (`filterProps` and
`EventToReact` in particular) so the host-side event path reads in
order.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22616?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
Fixes https://github.com/twentyhq/twenty/issues/21000
Front-component event handlers read standard event fields
(event.clientX, event.offsetX, …), but these were always undefined. On
the remote side, serialized event data was passed only as the
CustomEvent's detail — and CustomEvent ignores every constructor option
except detail, so the values lived at event.detail.clientX and never on
the event object itself.
- Added `applySerializedEventProperties`, to copy a curated allowlist of
event-level keys onto the event. Element/target state (value, checked,
files, scroll, media props) stays in
`applySerializedEventTargetProperties`, applied to this (the dispatch
element = event.target).
- Added x/y to `SerializedEventData` and to host-side serialization in
`createHtmlHostWrapper`.
- Added an `svg-pointer `story + `createHtmlTagPointerStory`
Note: Also pinned @types/react to v18 so the renderer stops dragging in
React 19 types and breaking typecheck.
Fixes#20354
## Problem
Front component form events currently expose serialized form state
through a sandbox-specific event shape, such as `event.detail.value` and
`event.detail.checked`.
That works for examples that explicitly read `event.detail`, but it is
surprising for app authors writing standard React form handlers:
```tsx
onChange={(event) => {
setValue(event.target.value);
}}
Internal app code already has to defend against multiple possible shapes:
// Values may live on e.detail.value, e.value, or e.target.value.
This suggests the sandbox event shape is leaking into userland.
Solution
This change keeps the existing event.detail behavior, but also syncs serialized event target properties back onto the remote element before dispatching the event.
That means both styles work:
// Existing sandbox-specific style
event.detail.value;
// Standard React style
event.target.value;
The same applies to checked, files, scroll/media target properties, and similar serialized target state.
What Changed
Added a shared helper to apply serialized event target properties onto the remote element.
Updated generated remote element event configs to dispatch serialized events through a custom event config.
Updated the remote-dom element generator so regenerated files preserve this behavior.
Updated Storybook form-event examples to use standard React event target reads.
Added/updated Storybook coverage for input, checkbox, textarea, select, submit, and caret preservation flows.
Validation
Ran git diff --check
Ran a targeted TypeScript error scan for the changed front component renderer files
Manually verified the Storybook FrontComponent/EventForwarding form event story locally:
text input updates state
checkbox updates state
submit reflects the updated JSON
Note: local Storybook verification on Windows required temporary local build/cache fixes that are not included in this PR, to keep this change focused on front component event behavior.
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
- Add 72 missing HTML and SVG elements to the remote-dom component
registry (48 HTML + 24 SVG), bringing the total from 47 to 119 supported
elements
- HTML additions include semantic inline text (b, i, u, s, mark, sub,
sup, kbd, etc.), description lists, ruby annotations, structural
elements (figure, details, dialog), and form utilities (fieldset,
progress, meter, optgroup)
- SVG additions include containers (svg, g, defs), shapes (path, circle,
rect, line, polygon), text (text, tspan), gradients (linearGradient,
radialGradient, stop), and utilities (clipPath, mask, foreignObject,
marker)
- Add htmlTag override to support SVG elements with camelCase names
(e.g. clipPath, foreignObject) while keeping custom element tags
lowercase per the Web Components spec