Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,22 @@ const generateCommonEventsType = (
});
writer.writeLine(');');
writer.blankLine();
writer.writeLine('return new CustomEvent(eventType, {');
writer.writeLine('const event = new CustomEvent(eventType, {');
writer.indent(() => {
writer.writeLine('detail: eventData,');
});
writer.writeLine('}) as RemoteEvent<SerializedEventData>;');
writer.blankLine();
writer.writeLine('applySerializedEventProperties(');
writer.indent(() => {
writer.writeLine(
'event as unknown as Record<string, unknown>,',
);
writer.writeLine('eventData,');
});
writer.writeLine(');');
writer.blankLine();
writer.writeLine('return event;');
});
writer.writeLine('},');
});
Expand Down Expand Up @@ -400,11 +411,18 @@ export const generateRemoteElements = (
});

sourceFile.addImportDeclaration({
moduleSpecifier: '@/constants/SerializedEventData',
namedImports: [
'applySerializedEventTargetProperties',
{ name: 'SerializedEventData', isTypeOnly: true },
],
moduleSpecifier: '@/constants/applySerializedEventProperties',
namedImports: ['applySerializedEventProperties'],
});

sourceFile.addImportDeclaration({
moduleSpecifier: '@/constants/applySerializedEventTargetProperties',
namedImports: ['applySerializedEventTargetProperties'],
});

sourceFile.addImportDeclaration({
moduleSpecifier: '@/types/SerializedEventData',
namedImports: [{ name: 'SerializedEventData', isTypeOnly: true }],
});

const commonPropertyNames = new Set(Object.keys(commonProperties));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import {
createHtmlTagClickStory,
createHtmlTagFocusStory,
createHtmlTagPointerStory,
} from '@/__stories__/shared/test-utils/createHtmlElementStory';

const meta: Meta<typeof FrontComponentRenderer> = {
Expand All @@ -27,3 +28,7 @@ export const Click = createHtmlTagClickStory({
export const FocusBlur = createHtmlTagFocusStory({
frontComponentBundleName: 'svg-focus-blur',
});

export const Pointer = createHtmlTagPointerStory({
frontComponentBundleName: 'svg-pointer',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
EventLog,
useEventLog,
} from '@/__stories__/shared/front-components/event-log';
import { FrontComponentCard } from '@/__stories__/shared/front-components/front-component-card';
import { SVG_ROOT_STYLE } from '@/__stories__/shared/front-components/styles';
import { useState } from 'react';
import { defineFrontComponent } from 'twenty-sdk/define';

const SvgPointerFrontComponent = () => {
const [interactionCount, setInteractionCount] = useState(0);
const [pointerCoordinates, setPointerCoordinates] = useState('');
const { entries, pushEvent } = useEventLog();

return (
<FrontComponentCard title="svg:pointer">
<svg
data-testid="subject"
viewBox="0 0 200 120"
onPointerDown={(event) => {
setInteractionCount((previous) => previous + 1);
setPointerCoordinates(`${event.clientX},${event.clientY}`);
pushEvent(event);
}}
onPointerMove={(event) => {
pushEvent(event);
}}
tabIndex={0}
style={SVG_ROOT_STYLE}
>
<rect x="20" y="20" width="160" height="80" fill="#2563eb" />
</svg>
<span data-testid="front-component-value">{interactionCount}</span>
<span data-testid="pointer-coordinates">{pointerCoordinates}</span>
<EventLog entries={entries} />
</FrontComponentCard>
);
};

export default defineFrontComponent({
universalIdentifier: 'fc-svg-c-pointer-0000000-0000-0000-0000-000000000021',
name: 'svg-pointer-front-component',
description: 'Front component covering pointer events on <svg>',
component: SvgPointerFrontComponent,
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ export type LoggedEventEntry = {
scrollLeft?: number;
deltaX?: number;
deltaY?: number;
clientX?: number;
clientY?: number;
offsetX?: number;
offsetY?: number;
movementX?: number;
movementY?: number;
};

const EVENT_LOG_STYLE = {
Expand Down Expand Up @@ -216,6 +222,36 @@ export const useEventLog = () => {
entry.deltaY = deltaY;
}

const clientX = pickFromRecords(records, 'clientX', isNumberValue);
if (isDefined(clientX)) {
entry.clientX = clientX;
}

const clientY = pickFromRecords(records, 'clientY', isNumberValue);
if (isDefined(clientY)) {
entry.clientY = clientY;
}

const offsetX = pickFromRecords(records, 'offsetX', isNumberValue);
if (isDefined(offsetX)) {
entry.offsetX = offsetX;
}

const offsetY = pickFromRecords(records, 'offsetY', isNumberValue);
if (isDefined(offsetY)) {
entry.offsetY = offsetY;
}

const movementX = pickFromRecords(records, 'movementX', isNumberValue);
if (isDefined(movementX)) {
entry.movementX = movementX;
}

const movementY = pickFromRecords(records, 'movementY', isNumberValue);
if (isDefined(movementY)) {
entry.movementY = movementY;
}

return [...previousEntries, entry];
});
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { type StoryObj } from '@storybook/react-vite';
import { userEvent, within } from 'storybook/test';
import { expect, fireEvent, userEvent, waitFor, within } from 'storybook/test';

import { type FrontComponentRenderer } from '@/host/components/FrontComponentRenderer';
import { expectEventLogged } from '@/__stories__/shared/test-utils/matchers/expectEventLogged';
import { expectFrontComponentMounted } from '@/__stories__/shared/test-utils/matchers/expectFrontComponentMounted';
import { runFrontComponentStory } from '@/__stories__/shared/test-utils/runFrontComponentStory';
import { type FrontComponentRenderer } from '@/host/components/FrontComponentRenderer';

type Story = StoryObj<typeof FrontComponentRenderer>;

Expand All @@ -30,6 +30,33 @@ export const createHtmlTagClickStory = ({
},
});

export const createHtmlTagPointerStory = ({
frontComponentBundleName,
}: CreateHtmlTagStoryParams): Story =>
runFrontComponentStory({
frontComponentBundleName,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await expectFrontComponentMounted(canvas);

const subject = await canvas.findByTestId('subject');

fireEvent.pointerDown(subject, { clientX: 123, clientY: 45 });

await expectEventLogged({
canvas,
matcher: { type: 'pointerdown', clientX: 123, clientY: 45 },
});

await waitFor(() => {
const coordinates = canvas.getByTestId('pointer-coordinates');

expect(coordinates.textContent).toBe('123,45');
});
},
});

export const createHtmlTagFocusStory = ({
frontComponentBundleName,
}: CreateHtmlTagStoryParams): Story =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ type LoggedEventMatcher = {
ctrlKey?: boolean;
metaKey?: boolean;
altKey?: boolean;
clientX?: number;
clientY?: number;
offsetX?: number;
offsetY?: number;
movementX?: number;
movementY?: number;
files?: { name?: string; type?: string }[];
};

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { type SerializedEventData } from '@/types/SerializedEventData';

const SERIALIZED_EVENT_PROPERTY_KEYS = [
'altKey',
'ctrlKey',
'metaKey',
'shiftKey',
'clientX',
'clientY',
'x',
'y',
'pageX',
'pageY',
'screenX',
'screenY',
'offsetX',
'offsetY',
'movementX',
'movementY',
'button',
'buttons',
'pointerId',
'pointerType',
'pressure',
'tangentialPressure',
'tiltX',
'tiltY',
'twist',
'width',
'height',
'isPrimary',
'key',
'code',
'repeat',
'deltaX',
'deltaY',
'deltaZ',
'deltaMode',
] as const satisfies readonly (keyof SerializedEventData)[];

export const applySerializedEventProperties = (
event: Record<string, unknown>,
eventData: SerializedEventData,
): void => {
for (const key of SERIALIZED_EVENT_PROPERTY_KEYS) {
if (key in eventData) {
event[key] = eventData[key];
}
}
};
Loading
Loading