eb651180aa
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. -->
45 lines
1.6 KiB
TypeScript
45 lines
1.6 KiB
TypeScript
import { createDropTargetGuardProps } from '../createDropTargetGuardProps';
|
|
|
|
describe('createDropTargetGuardProps', () => {
|
|
it('should return undefined without drag over or drop handlers', () => {
|
|
expect(createDropTargetGuardProps({ onClick: jest.fn() })).toBeUndefined();
|
|
});
|
|
|
|
it('should prevent default on drag over and forward to the remote handler', () => {
|
|
const onDragOver = jest.fn();
|
|
const props = createDropTargetGuardProps({ onDragOver });
|
|
const event = { preventDefault: jest.fn() };
|
|
|
|
(props?.onDragOver as (event: unknown) => void)(event);
|
|
|
|
expect(event.preventDefault).toHaveBeenCalledTimes(1);
|
|
expect(onDragOver).toHaveBeenCalledWith(event);
|
|
});
|
|
|
|
it('should prevent default on drag over when only a drop handler exists', () => {
|
|
const onDrop = jest.fn();
|
|
const props = createDropTargetGuardProps({ onDrop });
|
|
const dragOverEvent = { preventDefault: jest.fn() };
|
|
const dropEvent = { preventDefault: jest.fn() };
|
|
|
|
(props?.onDragOver as (event: unknown) => void)(dragOverEvent);
|
|
(props?.onDrop as (event: unknown) => void)(dropEvent);
|
|
|
|
expect(dragOverEvent.preventDefault).toHaveBeenCalledTimes(1);
|
|
expect(dropEvent.preventDefault).toHaveBeenCalledTimes(1);
|
|
expect(onDrop).toHaveBeenCalledWith(dropEvent);
|
|
});
|
|
|
|
it('should prevent default without forwarding to a non-function handler', () => {
|
|
const props = createDropTargetGuardProps({
|
|
onDragOver: 'alert(1)',
|
|
onDrop: jest.fn(),
|
|
});
|
|
const event = { preventDefault: jest.fn() };
|
|
|
|
(props?.onDragOver as (event: unknown) => void)(event);
|
|
|
|
expect(event.preventDefault).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|