diff --git a/packages/twenty-front-component-renderer/project.json b/packages/twenty-front-component-renderer/project.json index b246b8cc7d..9485478cc1 100644 --- a/packages/twenty-front-component-renderer/project.json +++ b/packages/twenty-front-component-renderer/project.json @@ -66,10 +66,16 @@ ], "inputs": [ "{projectRoot}/scripts/front-component-stories/**/*", - "{projectRoot}/src/__stories__/example-sources/*", + "{projectRoot}/src/__stories__/html-tag/**/*", + "{projectRoot}/src/__stories__/host-api/**/*", + "{projectRoot}/src/__stories__/showcase/**/*", + "{projectRoot}/src/__stories__/shared/front-components/**/*", "{workspaceRoot}/packages/twenty-sdk/src/cli/utilities/build/**/*" ], - "outputs": ["{projectRoot}/src/__stories__/example-sources-built/*"], + "outputs": [ + "{projectRoot}/src/__stories__/example-sources-built/*", + "{projectRoot}/src/__stories__/example-sources-built-preact/*" + ], "options": { "command": "tsx {projectRoot}/scripts/front-component-stories/build-source-examples.ts" } diff --git a/packages/twenty-front-component-renderer/scripts/front-component-stories/build-source-examples.ts b/packages/twenty-front-component-renderer/scripts/front-component-stories/build-source-examples.ts index 541820b003..553cca6504 100644 --- a/packages/twenty-front-component-renderer/scripts/front-component-stories/build-source-examples.ts +++ b/packages/twenty-front-component-renderer/scripts/front-component-stories/build-source-examples.ts @@ -6,10 +6,7 @@ import { fileURLToPath } from 'node:url'; import { getFrontComponentBuildPlugins } from 'twenty-sdk/front-component-renderer/build'; const dirname = path.dirname(fileURLToPath(import.meta.url)); -const exampleSourcesDir = path.resolve( - dirname, - '../../src/__stories__/example-sources', -); +const storiesDir = path.resolve(dirname, '../../src/__stories__'); const exampleSourcesBuiltDir = path.resolve( dirname, '../../src/__stories__/example-sources-built', @@ -19,6 +16,8 @@ const exampleSourcesBuiltPreactDir = path.resolve( '../../src/__stories__/example-sources-built-preact', ); +const SOURCE_SCAN_ROOTS = ['html-tag', 'host-api', 'showcase']; + const rootNodeModules = path.resolve(dirname, '../../../../node_modules'); const twentyUiIndividualIndex = path.resolve( @@ -71,44 +70,69 @@ const storyAlias = { ...twentySharedAliases, }; -const STORY_COMPONENTS = [ - 'static.front-component', - 'interactive.front-component', - 'lifecycle.front-component', - 'chakra-example.front-component', - 'tailwind-example.front-component', - 'emotion-example.front-component', - 'styled-components-example.front-component', - 'shadcn-example.front-component', - 'mui-example.front-component', - 'twenty-ui-example.front-component', - 'sdk-context-example.front-component', - 'form-events.front-component', - 'keyboard-events.front-component', - 'host-api-calls.front-component', - 'caret-preservation.front-component', - 'file-input.front-component', -]; +const ENTRY_POINT_PATTERN = /\.front-component\.tsx$/; + +const findEntryPointFiles = (directory: string): string[] => { + const result: string[] = []; + + if (!fs.existsSync(directory)) { + return result; + } + + for (const dirent of fs.readdirSync(directory, { withFileTypes: true })) { + const absolutePath = path.join(directory, dirent.name); + + if (dirent.isDirectory()) { + if (dirent.name === 'shared') { + continue; + } + + result.push(...findEntryPointFiles(absolutePath)); + continue; + } + + if (!dirent.isFile()) { + continue; + } + + if (ENTRY_POINT_PATTERN.test(dirent.name)) { + result.push(absolutePath); + } + } + + return result; +}; const resolveEntryPoints = (): Record => { + const files = SOURCE_SCAN_ROOTS.flatMap((root) => + findEntryPointFiles(path.join(storiesDir, root)), + ); + const entryPoints: Record = {}; - for (const name of STORY_COMPONENTS) { - const filePath = path.join(exampleSourcesDir, `${name}.tsx`); + for (const filePath of files) { + const basename = path.basename(filePath).replace(/\.tsx$/, ''); - if (!fs.existsSync(filePath)) { + if (entryPoints[basename] !== undefined) { throw new Error( - `Story component source file not found: ${filePath}\n` + - `Ensure the file exists in ${exampleSourcesDir} and the name in STORY_COMPONENTS is correct.`, + `Duplicate front-component basename "${basename}" found at ${filePath} and ${entryPoints[basename]}`, ); } - entryPoints[name] = filePath; + entryPoints[basename] = filePath; + } + + if (Object.keys(entryPoints).length === 0) { + throw new Error( + `No front-component source files found under ${storiesDir} (scanned: ${SOURCE_SCAN_ROOTS.join(', ')})`, + ); } return entryPoints; }; +const STORY_COMPONENTS = Object.keys(resolveEntryPoints()); + type BundleSizeEntry = { name: string; reactBytes: number; diff --git a/packages/twenty-front-component-renderer/scripts/remote-dom/generators/remote-elements.generator.ts b/packages/twenty-front-component-renderer/scripts/remote-dom/generators/remote-elements.generator.ts index 8f8cb7ab38..18d5d9b632 100644 --- a/packages/twenty-front-component-renderer/scripts/remote-dom/generators/remote-elements.generator.ts +++ b/packages/twenty-front-component-renderer/scripts/remote-dom/generators/remote-elements.generator.ts @@ -107,6 +107,66 @@ const generateCommonEventsType = ( }, ], }); + + sourceFile.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: 'createSerializedEventConfig', + initializer: (writer) => { + writer.write( + '(eventType: string): RemoteElementEventListenerDefinition => (', + ); + writer.block(() => { + writer.writeLine( + 'dispatchEvent(this: Element, eventData: SerializedEventData) {', + ); + writer.indent(() => { + writer.writeLine('applySerializedEventTargetProperties('); + writer.indent(() => { + writer.writeLine('this as unknown as Record,'); + writer.writeLine('eventData,'); + }); + writer.writeLine(');'); + writer.blankLine(); + writer.writeLine('return new CustomEvent(eventType, {'); + writer.indent(() => { + writer.writeLine('detail: eventData,'); + }); + writer.writeLine('}) as RemoteEvent;'); + }); + writer.writeLine('},'); + }); + writer.write(')'); + }, + }, + ], + }); + + sourceFile.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: 'HTML_COMMON_EVENTS_CONFIG', + initializer: (writer) => { + writer.writeLine('Object.fromEntries('); + writer.indent(() => { + writer.writeLine( + `${TYPE_NAMES.COMMON_EVENTS_ARRAY}.map((eventType) => [`, + ); + writer.indent(() => { + writer.writeLine('eventType,'); + writer.writeLine('createSerializedEventConfig(eventType),'); + }); + writer.writeLine(']),'); + }); + writer.write( + `) as RemoteElementEventListenersDefinition<${TYPE_NAMES.COMMON_EVENTS}>`, + ); + }, + }, + ], + }); }; const generateCommonPropertiesConfig = ( @@ -246,17 +306,19 @@ const generateElementDefinition = ( } } if (hasEvents) { - const formattedCustomEvents = customEvents - .map((event) => `'${event}'`) - .join(', '); + writer.write('events: '); + writer.block(() => { + if (hasCommonHtmlEvents) { + writer.writeLine('...HTML_COMMON_EVENTS_CONFIG,'); + } - writer.write( - hasCommonHtmlEvents && customEvents.length > 0 - ? `events: [...${TYPE_NAMES.COMMON_EVENTS_ARRAY}, ${formattedCustomEvents}],` - : hasCommonHtmlEvents - ? `events: [...${TYPE_NAMES.COMMON_EVENTS_ARRAY}],` - : `events: [${formattedCustomEvents}],`, - ); + for (const event of customEvents) { + writer.writeLine( + `'${event}': createSerializedEventConfig('${event}'),`, + ); + } + }); + writer.write(','); writer.newLine(); } }); @@ -332,12 +394,17 @@ export const generateRemoteElements = ( INTERNAL_ELEMENT_CLASSES.ROOT, INTERNAL_ELEMENT_CLASSES.FRAGMENT, { name: 'RemoteEvent', isTypeOnly: true }, + { name: 'RemoteElementEventListenerDefinition', isTypeOnly: true }, + { name: 'RemoteElementEventListenersDefinition', isTypeOnly: true }, ], }); sourceFile.addImportDeclaration({ moduleSpecifier: '@/constants/SerializedEventData', - namedImports: [{ name: 'SerializedEventData', isTypeOnly: true }], + namedImports: [ + 'applySerializedEventTargetProperties', + { name: 'SerializedEventData', isTypeOnly: true }, + ], }); const commonPropertyNames = new Set(Object.keys(commonProperties)); diff --git a/packages/twenty-front-component-renderer/src/__stories__/BundleSizes.stories.tsx b/packages/twenty-front-component-renderer/src/__stories__/BundleSizes.stories.tsx index c58e6a5568..25ad5b3d13 100644 --- a/packages/twenty-front-component-renderer/src/__stories__/BundleSizes.stories.tsx +++ b/packages/twenty-front-component-renderer/src/__stories__/BundleSizes.stories.tsx @@ -1,6 +1,6 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; -import bundleSizes from './example-sources-built/bundle-sizes.json'; +import bundleSizes from '@/__stories__/example-sources-built/bundle-sizes.json'; type BundleSizeEntry = { name: string; diff --git a/packages/twenty-front-component-renderer/src/__stories__/EventForwarding.stories.tsx b/packages/twenty-front-component-renderer/src/__stories__/EventForwarding.stories.tsx deleted file mode 100644 index a4ba39fcd5..0000000000 --- a/packages/twenty-front-component-renderer/src/__stories__/EventForwarding.stories.tsx +++ /dev/null @@ -1,517 +0,0 @@ -import { type Meta, type StoryObj } from '@storybook/react-vite'; -import { expect, fn, userEvent, waitFor, within } from 'storybook/test'; - -import { FrontComponentRenderer } from '../host/components/FrontComponentRenderer'; - -import { getBuiltStoryComponentPathForRender } from './utils/getBuiltStoryComponentPathForRender'; - -const errorHandler = fn(); - -const createHostApiMocks = () => ({ - navigate: fn().mockResolvedValue(undefined), - enqueueSnackbar: fn().mockResolvedValue(undefined), - openSidePanelPage: fn().mockResolvedValue(undefined), - closeSidePanel: fn().mockResolvedValue(undefined), - unmountFrontComponent: fn().mockResolvedValue(undefined), - updateProgress: fn().mockResolvedValue(undefined), - requestAccessTokenRefresh: fn().mockResolvedValue('refreshed-token'), - openCommandConfirmationModal: fn().mockResolvedValue(undefined), -}); - -const meta: Meta = { - title: 'FrontComponent/EventForwarding', - component: FrontComponentRenderer, - parameters: { - layout: 'centered', - }, - args: { - onError: errorHandler, - applicationAccessToken: 'fake-token', - executionContext: { - frontComponentId: 'storybook-test', - userId: null, - recordId: null, - selectedRecordIds: [], - }, - colorScheme: 'light', - frontComponentHostCommunicationApi: createHostApiMocks(), - }, - beforeEach: () => { - errorHandler.mockClear(); - }, -}; - -export default meta; -type Story = StoryObj; - -const MOUNT_TIMEOUT = 30000; -const INTERACTION_TIMEOUT = 5000; -const HOST_API_TIMEOUT = 10000; - -const createComponentStory = ( - name: string, - options?: { play?: Story['play'] }, -): Story => ({ - args: { - componentUrl: getBuiltStoryComponentPathForRender( - `${name}.front-component`, - ), - }, - ...(options?.play ? { play: options.play } : {}), -}); - -const createHostApiStory = (play: Story['play']): Story => ({ - ...createComponentStory('host-api-calls'), - args: { - ...createComponentStory('host-api-calls').args, - frontComponentHostCommunicationApi: createHostApiMocks(), - }, - play, -}); - -export const FormTextInput: Story = createComponentStory('form-events', { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'form-events-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const textInput = await canvas.findByTestId('text-input'); - await userEvent.type(textInput, 'hello'); - - expect( - await canvas.findByText('hello', {}, { timeout: INTERACTION_TIMEOUT }), - ).toBeVisible(); - }, -}); - -export const FormCheckbox: Story = createComponentStory('form-events', { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'form-events-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const checkbox = await canvas.findByTestId('checkbox-input'); - await userEvent.click(checkbox); - - expect( - await canvas.findByText('true', {}, { timeout: INTERACTION_TIMEOUT }), - ).toBeVisible(); - }, -}); - -export const FormFocusAndBlur: Story = createComponentStory('form-events', { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'form-events-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const textInput = await canvas.findByTestId('text-input'); - await userEvent.click(textInput); - - expect( - await canvas.findByText('focused', {}, { timeout: INTERACTION_TIMEOUT }), - ).toBeVisible(); - - await userEvent.click(await canvas.findByTestId('form-events-component')); - - expect( - await canvas.findByText('blurred', {}, { timeout: INTERACTION_TIMEOUT }), - ).toBeVisible(); - }, -}); - -export const FormSubmission: Story = createComponentStory('form-events', { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'form-events-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const textInput = await canvas.findByTestId('text-input'); - await userEvent.type(textInput, 'hello'); - - const checkbox = await canvas.findByTestId('checkbox-input'); - await userEvent.click(checkbox); - - const submitButton = await canvas.findByTestId('submit-button'); - await userEvent.click(submitButton); - - expect( - await canvas.findByText( - '{"text":"hello","checkbox":true}', - {}, - { timeout: INTERACTION_TIMEOUT }, - ), - ).toBeVisible(); - }, -}); - -export const KeyboardBasicInput: Story = createComponentStory( - 'keyboard-events', - { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'keyboard-events-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const input = await canvas.findByTestId('keyboard-input'); - await userEvent.click(input); - - await userEvent.keyboard('a'); - - expect( - await canvas.findByText('a', {}, { timeout: INTERACTION_TIMEOUT }), - ).toBeVisible(); - - expect( - await canvas.findByText('KeyA', {}, { timeout: INTERACTION_TIMEOUT }), - ).toBeVisible(); - - expect( - await canvas.findByText( - /^[1-9]\d*$/, - {}, - { timeout: INTERACTION_TIMEOUT }, - ), - ).toBeVisible(); - }, - }, -); - -export const KeyboardModifiers: Story = createComponentStory( - 'keyboard-events', - { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'keyboard-events-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const input = await canvas.findByTestId('keyboard-input'); - await userEvent.click(input); - - await userEvent.keyboard('{Shift>}b{/Shift}'); - - expect( - await canvas.findByText('shift', {}, { timeout: INTERACTION_TIMEOUT }), - ).toBeVisible(); - }, - }, -); - -export const HostApiNavigate: Story = createHostApiStory( - async ({ canvasElement, args }) => { - const canvas = within(canvasElement); - const api = args.frontComponentHostCommunicationApi!; - - await canvas.findByTestId( - 'host-api-calls-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const navigateBtn = await canvas.findByTestId('btn-navigate'); - await userEvent.click(navigateBtn); - - await waitFor( - () => { - expect(api.navigate).toHaveBeenCalled(); - }, - { timeout: HOST_API_TIMEOUT }, - ); - - expect( - await canvas.findByText( - 'navigate:success', - {}, - { timeout: INTERACTION_TIMEOUT }, - ), - ).toBeVisible(); - }, -); - -export const HostApiSnackbar: Story = createHostApiStory( - async ({ canvasElement, args }) => { - const canvas = within(canvasElement); - const api = args.frontComponentHostCommunicationApi!; - - await canvas.findByTestId( - 'host-api-calls-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const snackbarBtn = await canvas.findByTestId('btn-snackbar'); - await userEvent.click(snackbarBtn); - - await waitFor( - () => { - expect(api.enqueueSnackbar).toHaveBeenCalledWith({ - message: 'Test notification', - variant: 'success', - }); - }, - { timeout: HOST_API_TIMEOUT }, - ); - - expect( - await canvas.findByText( - 'snackbar:success', - {}, - { timeout: INTERACTION_TIMEOUT }, - ), - ).toBeVisible(); - }, -); - -export const HostApiProgress: Story = createHostApiStory( - async ({ canvasElement, args }) => { - const canvas = within(canvasElement); - const api = args.frontComponentHostCommunicationApi!; - - await canvas.findByTestId( - 'host-api-calls-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const progressBtn = await canvas.findByTestId('btn-progress'); - await userEvent.click(progressBtn); - - await waitFor( - () => { - expect(api.updateProgress).toHaveBeenCalledWith(50); - }, - { timeout: HOST_API_TIMEOUT }, - ); - - expect( - await canvas.findByText( - 'progress:success', - {}, - { timeout: INTERACTION_TIMEOUT }, - ), - ).toBeVisible(); - }, -); - -const TYPING_TIMEOUT = 10000; - -const expectCaretAt = async ( - element: HTMLInputElement | HTMLTextAreaElement, - position: number, -): Promise => { - await waitFor( - () => { - expect(element.selectionStart).toBe(position); - expect(element.selectionEnd).toBe(position); - }, - { timeout: TYPING_TIMEOUT }, - ); -}; - -export const InputCaretPreservedMidString: Story = createComponentStory( - 'caret-preservation', - { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'caret-preservation-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const input = (await canvas.findByTestId( - 'caret-text-input', - )) as HTMLInputElement; - - await waitFor( - () => { - expect(input.value).toBe('Hello world'); - }, - { timeout: INTERACTION_TIMEOUT }, - ); - - input.focus(); - input.setSelectionRange(4, 4); - - await userEvent.keyboard('X'); - - await waitFor( - () => { - expect(input.value).toBe('HellXo world'); - expect(canvas.getByTestId('caret-text-value').textContent).toBe( - 'HellXo world', - ); - }, - { timeout: TYPING_TIMEOUT }, - ); - - await expectCaretAt(input, 5); - }, - }, -); - -export const TextareaCaretPreservedMidString: Story = createComponentStory( - 'caret-preservation', - { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'caret-preservation-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const textarea = (await canvas.findByTestId( - 'caret-textarea-input', - )) as HTMLTextAreaElement; - - await waitFor( - () => { - expect(textarea.value).toBe('Hello world'); - }, - { timeout: INTERACTION_TIMEOUT }, - ); - - textarea.focus(); - textarea.setSelectionRange(4, 4); - - await userEvent.keyboard('X'); - - await waitFor( - () => { - expect(textarea.value).toBe('HellXo world'); - expect(canvas.getByTestId('caret-textarea-value').textContent).toBe( - 'HellXo world', - ); - }, - { timeout: TYPING_TIMEOUT }, - ); - - await expectCaretAt(textarea, 5); - }, - }, -); - -export const FileInputSingle: Story = createComponentStory('file-input', { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'file-input-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const input = (await canvas.findByTestId( - 'single-file-input', - )) as HTMLInputElement; - - const file = new File(['hello world'], 'hello.txt', { - type: 'text/plain', - lastModified: 1700000000000, - }); - - await userEvent.upload(input, file); - - await waitFor( - () => { - expect(canvas.getByTestId('single-file-count').textContent).toBe('1'); - expect(canvas.getByTestId('single-file-name').textContent).toContain( - 'hello.txt', - ); - expect(canvas.getByTestId('single-file-name').textContent).toContain( - 'text/plain', - ); - }, - { timeout: INTERACTION_TIMEOUT }, - ); - }, -}); - -export const FileInputMultiple: Story = createComponentStory('file-input', { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await canvas.findByTestId( - 'file-input-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const input = (await canvas.findByTestId( - 'multi-file-input', - )) as HTMLInputElement; - - const first = new File(['a'], 'one.png', { type: 'image/png' }); - const second = new File(['bb'], 'two.png', { type: 'image/png' }); - - await userEvent.upload(input, [first, second]); - - await waitFor( - () => { - expect(canvas.getByTestId('multi-file-count').textContent).toBe('2'); - const list = canvas.getByTestId('multi-file-list'); - expect(list.textContent).toContain('one.png'); - expect(list.textContent).toContain('two.png'); - }, - { timeout: INTERACTION_TIMEOUT }, - ); - }, -}); - -export const HostApiClosePanel: Story = createHostApiStory( - async ({ canvasElement, args }) => { - const canvas = within(canvasElement); - const api = args.frontComponentHostCommunicationApi!; - - await canvas.findByTestId( - 'host-api-calls-component', - {}, - { timeout: MOUNT_TIMEOUT }, - ); - - const closePanelBtn = await canvas.findByTestId('btn-close-panel'); - await userEvent.click(closePanelBtn); - - await waitFor( - () => { - expect(api.closeSidePanel).toHaveBeenCalled(); - }, - { timeout: HOST_API_TIMEOUT }, - ); - - expect( - await canvas.findByText( - 'closePanel:success', - {}, - { timeout: INTERACTION_TIMEOUT }, - ), - ).toBeVisible(); - }, -); diff --git a/packages/twenty-front-component-renderer/src/__stories__/FrontComponentRenderer.stories.tsx b/packages/twenty-front-component-renderer/src/__stories__/FrontComponentRenderer.stories.tsx index 985bf71444..2a6e0a0fa9 100644 --- a/packages/twenty-front-component-renderer/src/__stories__/FrontComponentRenderer.stories.tsx +++ b/packages/twenty-front-component-renderer/src/__stories__/FrontComponentRenderer.stories.tsx @@ -1,9 +1,8 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; import { expect, fn, userEvent, waitFor, within } from 'storybook/test'; -import { FrontComponentRenderer } from '../host/components/FrontComponentRenderer'; - -import { getBuiltStoryComponentPathForRender } from './utils/getBuiltStoryComponentPathForRender'; +import { FrontComponentRenderer } from '@/host/components/FrontComponentRenderer'; +import { getBuiltStoryComponentPathForRender } from '@/__stories__/utils/getBuiltStoryComponentPathForRender'; const errorHandler = fn(); diff --git a/packages/twenty-front-component-renderer/src/__stories__/UILibraries.stories.tsx b/packages/twenty-front-component-renderer/src/__stories__/UILibraries.stories.tsx index 3c02969617..9829d95660 100644 --- a/packages/twenty-front-component-renderer/src/__stories__/UILibraries.stories.tsx +++ b/packages/twenty-front-component-renderer/src/__stories__/UILibraries.stories.tsx @@ -1,9 +1,8 @@ import { type Meta, type StoryObj } from '@storybook/react-vite'; import { expect, fn, userEvent, within } from 'storybook/test'; -import { FrontComponentRenderer } from '../host/components/FrontComponentRenderer'; - -import { getBuiltStoryComponentPathForRender } from './utils/getBuiltStoryComponentPathForRender'; +import { FrontComponentRenderer } from '@/host/components/FrontComponentRenderer'; +import { getBuiltStoryComponentPathForRender } from '@/__stories__/utils/getBuiltStoryComponentPathForRender'; const errorHandler = fn(); diff --git a/packages/twenty-front-component-renderer/src/__stories__/example-sources/caret-preservation.front-component.tsx b/packages/twenty-front-component-renderer/src/__stories__/example-sources/caret-preservation.front-component.tsx deleted file mode 100644 index 9a9ae6b910..0000000000 --- a/packages/twenty-front-component-renderer/src/__stories__/example-sources/caret-preservation.front-component.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { defineFrontComponent } from 'twenty-sdk/define'; -import { type ChangeEvent, useState } from 'react'; - -const CARD_STYLE = { - padding: 24, - backgroundColor: '#eff6ff', - border: '2px solid #3b82f6', - borderRadius: 12, - fontFamily: 'system-ui, sans-serif', - display: 'flex', - flexDirection: 'column' as const, - gap: 16, - maxWidth: 400, -}; - -const HEADING_STYLE = { - color: '#1e3a8a', - fontWeight: 700, - fontSize: 18, - margin: 0, -}; - -const LABEL_STYLE = { - fontSize: 13, - fontWeight: 600, - color: '#374151', -}; - -const HINT_STYLE = { - fontSize: 13, - color: '#6b7280', - fontFamily: 'monospace', -}; - -const INPUT_STYLE = { - padding: '8px 12px', - border: '1px solid #d1d5db', - borderRadius: 6, - fontSize: 14, - fontFamily: 'monospace', -}; - -const INITIAL_VALUE = 'Hello world'; - -const CaretPreservationComponent = () => { - const [text, setText] = useState(INITIAL_VALUE); - const [textareaText, setTextareaText] = useState(INITIAL_VALUE); - - return ( -
-

Caret Preservation

- -
- - ) => { - const detail = (event as unknown as { detail: { value?: string } }) - .detail; - setText(detail?.value ?? ''); - }} - style={INPUT_STYLE} - /> - - {text} - -
- -
- -