From e3c79c803c471f345f819971070210cc9ffdf71a Mon Sep 17 00:00:00 2001 From: qinglong <166388703+Qin-long@users.noreply.github.com> Date: Fri, 22 May 2026 22:58:33 +0800 Subject: [PATCH] Fix standard React form event targets in front components (#20525) 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 --- .../project.json | 10 +- .../build-source-examples.ts | 80 ++- .../generators/remote-elements.generator.ts | 89 ++- .../src/__stories__/BundleSizes.stories.tsx | 2 +- .../__stories__/EventForwarding.stories.tsx | 517 ---------------- .../FrontComponentRenderer.stories.tsx | 5 +- .../src/__stories__/UILibraries.stories.tsx | 5 +- .../caret-preservation.front-component.tsx | 98 --- .../file-input.front-component.tsx | 120 ---- .../form-events.front-component.tsx | 141 ----- .../host-api-calls.front-component.tsx | 155 ----- .../keyboard-events.front-component.tsx | 125 ---- .../host-api/close-panel.stories.tsx | 60 ++ .../host-api-navigate.front-component.tsx | 52 ++ .../host-api-progress.front-component.tsx | 50 ++ ...t-api-side-panel-close.front-component.tsx | 50 ++ ...st-api-side-panel-open.front-component.tsx | 53 ++ .../host-api-snackbar.front-component.tsx | 53 ++ .../host-api-unmount.front-component.tsx | 50 ++ .../__stories__/host-api/navigate.stories.tsx | 60 ++ .../__stories__/host-api/progress.stories.tsx | 60 ++ .../__stories__/host-api/snackbar.stories.tsx | 63 ++ .../iframe/iframe-click.front-component.tsx | 37 ++ .../embedded/iframe/iframe-events.stories.tsx | 29 + .../iframe-focus-blur.front-component.tsx | 38 ++ .../img/img-click.front-component.tsx | 38 ++ .../embedded/img/img-events.stories.tsx | 29 + .../img/img-focus-blur.front-component.tsx | 39 ++ .../img/img-properties.front-component.tsx | 27 + .../embedded/img/img-properties.stories.tsx | 26 + .../picture/picture-click.front-component.tsx | 42 ++ .../picture/picture-events.stories.tsx | 29 + .../picture-focus-blur.front-component.tsx | 42 ++ .../button/button-click.front-component.tsx | 39 ++ .../form/button/button-events.stories.tsx | 43 ++ .../button-properties.front-component.tsx | 28 + .../form/button/button-properties.stories.tsx | 22 + .../datalist-click.front-component.tsx | 41 ++ .../form/datalist/datalist-events.stories.tsx | 22 + .../fieldset-click.front-component.tsx | 39 ++ .../form/fieldset/fieldset-events.stories.tsx | 29 + .../fieldset-focus-blur.front-component.tsx | 39 ++ .../fieldset-properties.front-component.tsx | 27 + .../fieldset/fieldset-properties.stories.tsx | 22 + .../form/form/form-events.stories.tsx | 40 ++ .../form/form-properties.front-component.tsx | 27 + .../form/form/form-properties.stories.tsx | 22 + .../form/form/form-submit.front-component.tsx | 57 ++ .../input/input-caret.front-component.tsx | 38 ++ .../form/input/input-caret.stories.tsx | 61 ++ .../input/input-checkbox.front-component.tsx | 43 ++ .../form/input/input-checkbox.stories.tsx | 51 ++ .../form/input/input-events.stories.tsx | 63 ++ .../input-file-multiple.front-component.tsx | 39 ++ .../input-file-single.front-component.tsx | 37 ++ .../form/input/input-file.stories.tsx | 76 +++ .../input/input-keyboard.front-component.tsx | 45 ++ .../form/input/input-keyboard.stories.tsx | 65 ++ ...nput-number-properties.front-component.tsx | 33 + .../form/input/input-properties.stories.tsx | 38 ++ .../input-text-focus-blur.front-component.tsx | 40 ++ .../input-text-properties.front-component.tsx | 34 + .../input-text-value.front-component.tsx | 47 ++ .../label/label-click.front-component.tsx | 38 ++ .../form/label/label-events.stories.tsx | 29 + .../label-focus-blur.front-component.tsx | 39 ++ .../label-properties.front-component.tsx | 27 + .../form/label/label-properties.stories.tsx | 22 + .../legend/legend-click.front-component.tsx | 40 ++ .../form/legend/legend-events.stories.tsx | 29 + .../legend-focus-blur.front-component.tsx | 41 ++ .../meter/meter-click.front-component.tsx | 39 ++ .../form/meter/meter-events.stories.tsx | 29 + .../meter-focus-blur.front-component.tsx | 40 ++ .../meter-properties.front-component.tsx | 28 + .../form/meter/meter-properties.stories.tsx | 27 + .../optgroup-click.front-component.tsx | 39 ++ .../form/optgroup/optgroup-events.stories.tsx | 22 + .../option/option-click.front-component.tsx | 41 ++ .../form/option/option-events.stories.tsx | 22 + .../output/output-click.front-component.tsx | 38 ++ .../form/output/output-events.stories.tsx | 29 + .../output-focus-blur.front-component.tsx | 39 ++ .../progress-click.front-component.tsx | 39 ++ .../form/progress/progress-events.stories.tsx | 29 + .../progress-focus-blur.front-component.tsx | 39 ++ .../progress-properties.front-component.tsx | 27 + .../progress/progress-properties.stories.tsx | 26 + .../form/select/select-events.stories.tsx | 51 ++ .../select-properties.front-component.tsx | 33 + .../form/select/select-properties.stories.tsx | 25 + .../select/select-value.front-component.tsx | 48 ++ .../textarea-caret.front-component.tsx | 38 ++ .../form/textarea/textarea-caret.stories.tsx | 63 ++ .../form/textarea/textarea-events.stories.tsx | 44 ++ .../textarea-properties.front-component.tsx | 33 + .../textarea/textarea-properties.stories.tsx | 30 + .../textarea-value.front-component.tsx | 46 ++ .../div/div-click.front-component.tsx | 50 ++ .../div/div-dblclick.front-component.tsx | 50 ++ .../grouping/div/div-events.stories.tsx | 74 +++ .../div-mouseenter-leave.front-component.tsx | 48 ++ .../div/div-properties.front-component.tsx | 27 + .../grouping/div/div-properties.stories.tsx | 22 + .../figcaption-click.front-component.tsx | 41 ++ .../figcaption/figcaption-events.stories.tsx | 29 + .../figcaption-focus-blur.front-component.tsx | 42 ++ .../figure/figure-click.front-component.tsx | 38 ++ .../grouping/figure/figure-events.stories.tsx | 29 + .../figure-focus-blur.front-component.tsx | 39 ++ .../grouping/rp/rp-click.front-component.tsx | 41 ++ .../grouping/rp/rp-events.stories.tsx | 29 + .../rp/rp-focus-blur.front-component.tsx | 42 ++ .../grouping/rt/rt-click.front-component.tsx | 41 ++ .../grouping/rt/rt-events.stories.tsx | 29 + .../rt/rt-focus-blur.front-component.tsx | 42 ++ .../ruby/ruby-click.front-component.tsx | 38 ++ .../grouping/ruby/ruby-events.stories.tsx | 29 + .../ruby/ruby-focus-blur.front-component.tsx | 39 ++ .../interactive/a/a-click.front-component.tsx | 38 ++ .../interactive/a/a-events.stories.tsx | 29 + .../a/a-focus-blur.front-component.tsx | 39 ++ .../a/a-properties.front-component.tsx | 33 + .../interactive/a/a-properties.stories.tsx | 25 + .../details/details-click.front-component.tsx | 39 ++ .../details/details-events.stories.tsx | 29 + .../details-focus-blur.front-component.tsx | 39 ++ .../details-properties.front-component.tsx | 29 + .../details/details-properties.stories.tsx | 22 + .../dialog/dialog-click.front-component.tsx | 39 ++ .../dialog/dialog-events.stories.tsx | 29 + .../dialog-focus-blur.front-component.tsx | 40 ++ .../summary/summary-click.front-component.tsx | 41 ++ .../summary/summary-events.stories.tsx | 29 + .../summary-focus-blur.front-component.tsx | 41 ++ .../list/dd/dd-click.front-component.tsx | 40 ++ .../html-tag/list/dd/dd-events.stories.tsx | 29 + .../list/dd/dd-focus-blur.front-component.tsx | 41 ++ .../list/dl/dl-click.front-component.tsx | 38 ++ .../html-tag/list/dl/dl-events.stories.tsx | 29 + .../list/dl/dl-focus-blur.front-component.tsx | 39 ++ .../list/dt/dt-click.front-component.tsx | 40 ++ .../html-tag/list/dt/dt-events.stories.tsx | 29 + .../list/dt/dt-focus-blur.front-component.tsx | 41 ++ .../list/li/li-click.front-component.tsx | 38 ++ .../html-tag/list/li/li-events.stories.tsx | 29 + .../list/li/li-focus-blur.front-component.tsx | 39 ++ .../list/menu/menu-click.front-component.tsx | 38 ++ .../list/menu/menu-events.stories.tsx | 29 + .../menu/menu-focus-blur.front-component.tsx | 39 ++ .../list/ol/ol-click.front-component.tsx | 38 ++ .../html-tag/list/ol/ol-events.stories.tsx | 29 + .../list/ol/ol-focus-blur.front-component.tsx | 39 ++ .../list/ul/ul-click.front-component.tsx | 38 ++ .../html-tag/list/ul/ul-events.stories.tsx | 29 + .../list/ul/ul-focus-blur.front-component.tsx | 39 ++ .../address/address-click.front-component.tsx | 39 ++ .../address/address-events.stories.tsx | 29 + .../address-focus-blur.front-component.tsx | 39 ++ .../article/article-click.front-component.tsx | 39 ++ .../article/article-events.stories.tsx | 29 + .../article-focus-blur.front-component.tsx | 39 ++ .../article-properties.front-component.tsx | 27 + .../article/article-properties.stories.tsx | 22 + .../aside/aside-click.front-component.tsx | 38 ++ .../sectioning/aside/aside-events.stories.tsx | 29 + .../aside-focus-blur.front-component.tsx | 39 ++ .../aside-properties.front-component.tsx | 27 + .../aside/aside-properties.stories.tsx | 22 + .../footer/footer-click.front-component.tsx | 38 ++ .../footer/footer-events.stories.tsx | 29 + .../footer-focus-blur.front-component.tsx | 39 ++ .../h1/h1-click.front-component.tsx | 38 ++ .../sectioning/h1/h1-events.stories.tsx | 29 + .../h1/h1-focus-blur.front-component.tsx | 39 ++ .../h1/h1-properties.front-component.tsx | 27 + .../sectioning/h1/h1-properties.stories.tsx | 22 + .../h2/h2-click.front-component.tsx | 38 ++ .../sectioning/h2/h2-events.stories.tsx | 29 + .../h2/h2-focus-blur.front-component.tsx | 39 ++ .../h3/h3-click.front-component.tsx | 38 ++ .../sectioning/h3/h3-events.stories.tsx | 29 + .../h3/h3-focus-blur.front-component.tsx | 39 ++ .../h4/h4-click.front-component.tsx | 38 ++ .../sectioning/h4/h4-events.stories.tsx | 29 + .../h4/h4-focus-blur.front-component.tsx | 39 ++ .../h5/h5-click.front-component.tsx | 38 ++ .../sectioning/h5/h5-events.stories.tsx | 29 + .../h5/h5-focus-blur.front-component.tsx | 39 ++ .../h6/h6-click.front-component.tsx | 38 ++ .../sectioning/h6/h6-events.stories.tsx | 29 + .../h6/h6-focus-blur.front-component.tsx | 39 ++ .../header/header-click.front-component.tsx | 38 ++ .../header/header-events.stories.tsx | 29 + .../header-focus-blur.front-component.tsx | 39 ++ .../hgroup/hgroup-click.front-component.tsx | 38 ++ .../hgroup/hgroup-events.stories.tsx | 29 + .../hgroup-focus-blur.front-component.tsx | 39 ++ .../main/main-click.front-component.tsx | 38 ++ .../sectioning/main/main-events.stories.tsx | 29 + .../main/main-focus-blur.front-component.tsx | 39 ++ .../nav/nav-click.front-component.tsx | 38 ++ .../sectioning/nav/nav-events.stories.tsx | 29 + .../nav/nav-focus-blur.front-component.tsx | 39 ++ .../nav/nav-properties.front-component.tsx | 27 + .../sectioning/nav/nav-properties.stories.tsx | 22 + .../search/search-click.front-component.tsx | 38 ++ .../search/search-events.stories.tsx | 29 + .../search-focus-blur.front-component.tsx | 39 ++ .../section/section-click.front-component.tsx | 39 ++ .../section/section-events.stories.tsx | 29 + .../section-focus-blur.front-component.tsx | 39 ++ .../section-properties.front-component.tsx | 27 + .../section/section-properties.stories.tsx | 22 + .../circle/circle-click.front-component.tsx | 41 ++ .../svg/circle/circle-events.stories.tsx | 22 + .../ellipse/ellipse-click.front-component.tsx | 43 ++ .../svg/ellipse/ellipse-events.stories.tsx | 22 + .../svg/g/g-click.front-component.tsx | 39 ++ .../html-tag/svg/g/g-events.stories.tsx | 29 + .../svg/g/g-focus-blur.front-component.tsx | 40 ++ .../svg/line/line-click.front-component.tsx | 43 ++ .../html-tag/svg/line/line-events.stories.tsx | 22 + .../svg/path/path-click.front-component.tsx | 39 ++ .../html-tag/svg/path/path-events.stories.tsx | 22 + .../polygon/polygon-click.front-component.tsx | 40 ++ .../svg/polygon/polygon-events.stories.tsx | 22 + .../polyline-click.front-component.tsx | 42 ++ .../svg/polyline/polyline-events.stories.tsx | 22 + .../svg/rect/rect-click.front-component.tsx | 42 ++ .../html-tag/svg/rect/rect-events.stories.tsx | 22 + .../svg/svg/svg-click.front-component.tsx | 39 ++ .../html-tag/svg/svg/svg-events.stories.tsx | 29 + .../svg/svg-focus-blur.front-component.tsx | 40 ++ .../caption/caption-click.front-component.tsx | 44 ++ .../table/caption/caption-events.stories.tsx | 22 + .../colgroup-click.front-component.tsx | 44 ++ .../colgroup/colgroup-events.stories.tsx | 22 + .../table/table-click.front-component.tsx | 38 ++ .../table/table/table-events.stories.tsx | 29 + .../table-focus-blur.front-component.tsx | 39 ++ .../tbody/tbody-click.front-component.tsx | 41 ++ .../table/tbody/tbody-events.stories.tsx | 22 + .../table/td/td-click.front-component.tsx | 44 ++ .../html-tag/table/td/td-events.stories.tsx | 29 + .../td/td-focus-blur.front-component.tsx | 45 ++ .../tfoot/tfoot-click.front-component.tsx | 41 ++ .../table/tfoot/tfoot-events.stories.tsx | 22 + .../table/th/th-click.front-component.tsx | 44 ++ .../html-tag/table/th/th-events.stories.tsx | 29 + .../th/th-focus-blur.front-component.tsx | 45 ++ .../thead/thead-click.front-component.tsx | 41 ++ .../table/thead/thead-events.stories.tsx | 22 + .../table/tr/tr-click.front-component.tsx | 41 ++ .../html-tag/table/tr/tr-events.stories.tsx | 29 + .../tr/tr-focus-blur.front-component.tsx | 42 ++ .../abbr/abbr-click.front-component.tsx | 38 ++ .../text-inline/abbr/abbr-events.stories.tsx | 29 + .../abbr/abbr-focus-blur.front-component.tsx | 39 ++ .../text-inline/b/b-click.front-component.tsx | 38 ++ .../text-inline/b/b-events.stories.tsx | 29 + .../b/b-focus-blur.front-component.tsx | 39 ++ .../bdi/bdi-click.front-component.tsx | 38 ++ .../text-inline/bdi/bdi-events.stories.tsx | 29 + .../bdi/bdi-focus-blur.front-component.tsx | 39 ++ .../bdo/bdo-click.front-component.tsx | 38 ++ .../text-inline/bdo/bdo-events.stories.tsx | 29 + .../bdo/bdo-focus-blur.front-component.tsx | 39 ++ .../cite/cite-click.front-component.tsx | 38 ++ .../text-inline/cite/cite-events.stories.tsx | 29 + .../cite/cite-focus-blur.front-component.tsx | 39 ++ .../code/code-click.front-component.tsx | 38 ++ .../text-inline/code/code-events.stories.tsx | 29 + .../code/code-focus-blur.front-component.tsx | 39 ++ .../data/data-click.front-component.tsx | 38 ++ .../text-inline/data/data-events.stories.tsx | 29 + .../data/data-focus-blur.front-component.tsx | 39 ++ .../del/del-click.front-component.tsx | 38 ++ .../text-inline/del/del-events.stories.tsx | 29 + .../del/del-focus-blur.front-component.tsx | 39 ++ .../dfn/dfn-click.front-component.tsx | 38 ++ .../text-inline/dfn/dfn-events.stories.tsx | 29 + .../dfn/dfn-focus-blur.front-component.tsx | 39 ++ .../em/em-click.front-component.tsx | 38 ++ .../text-inline/em/em-events.stories.tsx | 29 + .../em/em-focus-blur.front-component.tsx | 39 ++ .../text-inline/i/i-click.front-component.tsx | 38 ++ .../text-inline/i/i-events.stories.tsx | 29 + .../i/i-focus-blur.front-component.tsx | 39 ++ .../ins/ins-click.front-component.tsx | 38 ++ .../text-inline/ins/ins-events.stories.tsx | 29 + .../ins/ins-focus-blur.front-component.tsx | 39 ++ .../kbd/kbd-click.front-component.tsx | 38 ++ .../text-inline/kbd/kbd-events.stories.tsx | 29 + .../kbd/kbd-focus-blur.front-component.tsx | 39 ++ .../mark/mark-click.front-component.tsx | 38 ++ .../text-inline/mark/mark-events.stories.tsx | 29 + .../mark/mark-focus-blur.front-component.tsx | 39 ++ .../text-inline/q/q-click.front-component.tsx | 38 ++ .../text-inline/q/q-events.stories.tsx | 29 + .../q/q-focus-blur.front-component.tsx | 39 ++ .../text-inline/s/s-click.front-component.tsx | 38 ++ .../text-inline/s/s-events.stories.tsx | 29 + .../s/s-focus-blur.front-component.tsx | 39 ++ .../samp/samp-click.front-component.tsx | 38 ++ .../text-inline/samp/samp-events.stories.tsx | 29 + .../samp/samp-focus-blur.front-component.tsx | 39 ++ .../small/small-click.front-component.tsx | 38 ++ .../small/small-events.stories.tsx | 29 + .../small-focus-blur.front-component.tsx | 39 ++ .../span/span-click.front-component.tsx | 38 ++ .../text-inline/span/span-events.stories.tsx | 29 + .../span/span-focus-blur.front-component.tsx | 39 ++ .../span/span-properties.front-component.tsx | 27 + .../span/span-properties.stories.tsx | 22 + .../strong/strong-click.front-component.tsx | 38 ++ .../strong/strong-events.stories.tsx | 29 + .../strong-focus-blur.front-component.tsx | 39 ++ .../sub/sub-click.front-component.tsx | 38 ++ .../text-inline/sub/sub-events.stories.tsx | 29 + .../sub/sub-focus-blur.front-component.tsx | 39 ++ .../sup/sup-click.front-component.tsx | 38 ++ .../text-inline/sup/sup-events.stories.tsx | 29 + .../sup/sup-focus-blur.front-component.tsx | 39 ++ .../time/time-click.front-component.tsx | 38 ++ .../text-inline/time/time-events.stories.tsx | 29 + .../time/time-focus-blur.front-component.tsx | 39 ++ .../text-inline/u/u-click.front-component.tsx | 38 ++ .../text-inline/u/u-events.stories.tsx | 29 + .../u/u-focus-blur.front-component.tsx | 39 ++ .../var/var-click.front-component.tsx | 38 ++ .../text-inline/var/var-events.stories.tsx | 29 + .../var/var-focus-blur.front-component.tsx | 39 ++ .../blockquote-click.front-component.tsx | 39 ++ .../blockquote/blockquote-events.stories.tsx | 29 + .../blockquote-focus-blur.front-component.tsx | 40 ++ .../text/hr/hr-click.front-component.tsx | 36 ++ .../html-tag/text/hr/hr-events.stories.tsx | 22 + .../text/p/p-click.front-component.tsx | 38 ++ .../html-tag/text/p/p-events.stories.tsx | 29 + .../text/p/p-focus-blur.front-component.tsx | 39 ++ .../text/p/p-properties.front-component.tsx | 27 + .../html-tag/text/p/p-properties.stories.tsx | 22 + .../text/pre/pre-click.front-component.tsx | 38 ++ .../html-tag/text/pre/pre-events.stories.tsx | 29 + .../pre/pre-focus-blur.front-component.tsx | 39 ++ .../shared/front-components/event-log.tsx | 238 +++++++ .../front-components/front-component-card.tsx | 44 ++ .../front-components/property-fixture.ts | 22 + .../shared/front-components/styles.ts | 76 +++ .../__stories__/shared/test-utils/README.md | 131 ++++ .../createFrontComponentStoryMeta.ts | 44 ++ .../test-utils/createHtmlElementStory.ts | 53 ++ .../createPropertyReflectionStory.ts | 54 ++ .../test-utils/matchers/expectEventLogged.ts | 135 ++++ .../matchers/expectFrontComponentMounted.ts | 15 + .../matchers/expectFrontComponentValue.ts | 27 + .../matchers/expectPropertyReflected.ts | 62 ++ .../test-utils/runFrontComponentStory.ts | 29 + .../__stories__/shared/test-utils/timeouts.ts | 5 + .../chakra-example.front-component.tsx | 0 .../emotion-example.front-component.tsx | 0 .../interactive.front-component.tsx | 0 .../lifecycle.front-component.tsx | 0 .../mui-example.front-component.tsx | 0 .../sdk-context-example.front-component.tsx | 0 .../shadcn-example.front-component.tsx | 0 .../static.front-component.tsx | 0 ...led-components-example.front-component.tsx | 0 .../tailwind-example.front-component.tsx | 0 .../twenty-ui-example.front-component.tsx | 0 .../src/constants/SerializedEventData.ts | 53 ++ .../src/remote/generated/remote-elements.ts | 583 +++++++++++++----- 373 files changed, 13530 insertions(+), 1366 deletions(-) delete mode 100644 packages/twenty-front-component-renderer/src/__stories__/EventForwarding.stories.tsx delete mode 100644 packages/twenty-front-component-renderer/src/__stories__/example-sources/caret-preservation.front-component.tsx delete mode 100644 packages/twenty-front-component-renderer/src/__stories__/example-sources/file-input.front-component.tsx delete mode 100644 packages/twenty-front-component-renderer/src/__stories__/example-sources/form-events.front-component.tsx delete mode 100644 packages/twenty-front-component-renderer/src/__stories__/example-sources/host-api-calls.front-component.tsx delete mode 100644 packages/twenty-front-component-renderer/src/__stories__/example-sources/keyboard-events.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/close-panel.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/host-api-navigate.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/host-api-progress.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/host-api-side-panel-close.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/host-api-side-panel-open.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/host-api-snackbar.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/host-api-unmount.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/navigate.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/progress.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/host-api/snackbar.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/iframe/iframe-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/iframe/iframe-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/iframe/iframe-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/img/img-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/img/img-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/img/img-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/img/img-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/img/img-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/picture/picture-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/picture/picture-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/embedded/picture/picture-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/button/button-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/button/button-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/button/button-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/button/button-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/datalist/datalist-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/datalist/datalist-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/fieldset/fieldset-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/fieldset/fieldset-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/fieldset/fieldset-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/fieldset/fieldset-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/fieldset/fieldset-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/form/form-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/form/form-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/form/form-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/form/form-submit.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-caret.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-caret.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-checkbox.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-checkbox.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-file-multiple.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-file-single.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-file.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-keyboard.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-keyboard.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-number-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-text-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-text-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/input/input-text-value.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/label/label-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/label/label-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/label/label-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/label/label-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/label/label-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/legend/legend-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/legend/legend-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/legend/legend-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/meter/meter-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/meter/meter-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/meter/meter-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/meter/meter-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/meter/meter-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/optgroup/optgroup-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/optgroup/optgroup-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/option/option-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/option/option-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/output/output-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/output/output-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/output/output-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/progress/progress-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/progress/progress-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/progress/progress-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/progress/progress-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/progress/progress-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/select/select-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/select/select-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/select/select-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/select/select-value.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/textarea/textarea-caret.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/textarea/textarea-caret.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/textarea/textarea-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/textarea/textarea-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/textarea/textarea-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/form/textarea/textarea-value.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/div/div-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/div/div-dblclick.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/div/div-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/div/div-mouseenter-leave.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/div/div-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/div/div-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/figcaption/figcaption-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/figcaption/figcaption-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/figcaption/figcaption-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/figure/figure-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/figure/figure-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/figure/figure-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/rp/rp-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/rp/rp-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/rp/rp-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/rt/rt-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/rt/rt-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/rt/rt-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/ruby/ruby-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/ruby/ruby-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/grouping/ruby/ruby-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/a/a-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/a/a-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/a/a-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/a/a-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/a/a-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/details/details-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/details/details-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/details/details-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/details/details-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/details/details-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/dialog/dialog-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/dialog/dialog-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/dialog/dialog-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/summary/summary-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/summary/summary-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/interactive/summary/summary-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/dd/dd-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/dd/dd-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/dd/dd-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/dl/dl-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/dl/dl-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/dl/dl-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/dt/dt-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/dt/dt-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/dt/dt-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/li/li-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/li/li-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/li/li-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/menu/menu-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/menu/menu-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/menu/menu-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/ol/ol-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/ol/ol-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/ol/ol-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/ul/ul-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/ul/ul-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/list/ul/ul-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/address/address-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/address/address-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/address/address-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/article/article-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/article/article-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/article/article-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/article/article-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/article/article-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/aside/aside-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/aside/aside-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/aside/aside-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/aside/aside-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/aside/aside-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/footer/footer-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/footer/footer-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/footer/footer-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h1/h1-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h1/h1-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h1/h1-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h1/h1-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h1/h1-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h2/h2-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h2/h2-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h2/h2-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h3/h3-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h3/h3-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h3/h3-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h4/h4-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h4/h4-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h4/h4-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h5/h5-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h5/h5-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h5/h5-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h6/h6-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h6/h6-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/h6/h6-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/header/header-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/header/header-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/header/header-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/hgroup/hgroup-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/hgroup/hgroup-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/hgroup/hgroup-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/main/main-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/main/main-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/main/main-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/nav/nav-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/nav/nav-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/nav/nav-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/nav/nav-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/nav/nav-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/search/search-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/search/search-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/search/search-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/section/section-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/section/section-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/section/section-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/section/section-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/sectioning/section/section-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/circle/circle-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/circle/circle-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/ellipse/ellipse-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/ellipse/ellipse-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/g/g-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/g/g-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/g/g-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/line/line-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/line/line-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/path/path-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/path/path-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/polygon/polygon-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/polygon/polygon-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/polyline/polyline-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/polyline/polyline-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/rect/rect-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/rect/rect-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/svg/svg-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/svg/svg-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/svg/svg/svg-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/caption/caption-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/caption/caption-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/colgroup/colgroup-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/colgroup/colgroup-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/table/table-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/table/table-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/table/table-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/tbody/tbody-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/tbody/tbody-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/td/td-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/td/td-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/td/td-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/tfoot/tfoot-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/tfoot/tfoot-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/th/th-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/th/th-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/th/th-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/thead/thead-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/thead/thead-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/tr/tr-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/tr/tr-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/table/tr/tr-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/abbr/abbr-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/abbr/abbr-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/abbr/abbr-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/b/b-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/b/b-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/b/b-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/bdi/bdi-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/bdi/bdi-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/bdi/bdi-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/bdo/bdo-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/bdo/bdo-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/bdo/bdo-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/cite/cite-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/cite/cite-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/cite/cite-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/code/code-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/code/code-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/code/code-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/data/data-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/data/data-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/data/data-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/del/del-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/del/del-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/del/del-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/dfn/dfn-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/dfn/dfn-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/dfn/dfn-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/em/em-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/em/em-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/em/em-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/i/i-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/i/i-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/i/i-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/ins/ins-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/ins/ins-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/ins/ins-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/kbd/kbd-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/kbd/kbd-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/kbd/kbd-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/mark/mark-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/mark/mark-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/mark/mark-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/q/q-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/q/q-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/q/q-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/s/s-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/s/s-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/s/s-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/samp/samp-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/samp/samp-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/samp/samp-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/small/small-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/small/small-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/small/small-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/span/span-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/span/span-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/span/span-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/span/span-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/span/span-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/strong/strong-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/strong/strong-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/strong/strong-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/sub/sub-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/sub/sub-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/sub/sub-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/sup/sup-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/sup/sup-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/sup/sup-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/time/time-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/time/time-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/time/time-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/u/u-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/u/u-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/u/u-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/var/var-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/var/var-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text-inline/var/var-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/blockquote/blockquote-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/blockquote/blockquote-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/blockquote/blockquote-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/hr/hr-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/hr/hr-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/p/p-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/p/p-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/p/p-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/p/p-properties.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/p/p-properties.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/pre/pre-click.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/pre/pre-events.stories.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/html-tag/text/pre/pre-focus-blur.front-component.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/front-components/event-log.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/front-components/front-component-card.tsx create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/front-components/property-fixture.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/front-components/styles.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/README.md create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/createFrontComponentStoryMeta.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/createHtmlElementStory.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/createPropertyReflectionStory.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/matchers/expectEventLogged.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/matchers/expectFrontComponentMounted.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/matchers/expectFrontComponentValue.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/matchers/expectPropertyReflected.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/runFrontComponentStory.ts create mode 100644 packages/twenty-front-component-renderer/src/__stories__/shared/test-utils/timeouts.ts rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/chakra-example.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/emotion-example.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/interactive.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/lifecycle.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/mui-example.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/sdk-context-example.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/shadcn-example.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/static.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/styled-components-example.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/tailwind-example.front-component.tsx (100%) rename packages/twenty-front-component-renderer/src/__stories__/{example-sources => showcase}/twenty-ui-example.front-component.tsx (100%) 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} - -
- -
- -