From fd9a13fb680bf39334ca4c2c30b38b10b60c6678 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Fri, 16 Aug 2024 14:34:15 +0200 Subject: [PATCH] :alembic: Implemented full form previews POC --- src/components/ComponentPreview.tsx | 9 +- src/components/FormPreview.stories.ts | 148 +++++++++++ src/components/FormPreview.tsx | 251 ++++++++++++++++++ src/components/form-preview.scss | 97 +++++++ src/registry/addressNL/index.ts | 4 +- src/registry/bsn/index.ts | 2 +- src/registry/checkbox/index.ts | 2 +- src/registry/columns/index.ts | 11 +- .../{preview.tsx => panel-preview.tsx} | 71 +++-- .../columns/{preview.scss => previews.scss} | 21 ++ src/registry/columns/structure-preview.tsx | 28 ++ src/registry/columns/webform-preview.tsx | 25 ++ src/registry/content/index.ts | 15 +- src/registry/content/webform-preview.tsx | 9 + src/registry/cosignV1/index.ts | 2 +- src/registry/cosignV2/index.ts | 2 +- src/registry/currency/index.ts | 2 +- src/registry/date/index.ts | 2 +- src/registry/datetime/index.ts | 2 +- src/registry/editgrid/index.ts | 11 +- .../{preview.tsx => panel-preview.tsx} | 0 src/registry/editgrid/previews.scss | 3 + src/registry/editgrid/structure-preview.tsx | 21 ++ src/registry/editgrid/webform-preview.tsx | 48 ++++ src/registry/email/index.ts | 2 +- src/registry/fieldset/index.ts | 10 +- .../{preview.tsx => panel-preview.tsx} | 0 src/registry/fieldset/structure-preview.tsx | 10 + src/registry/fieldset/webform-preview.tsx | 18 ++ src/registry/file/index.ts | 2 +- src/registry/iban/index.ts | 2 +- src/registry/{index.tsx => index.ts} | 0 src/registry/licenseplate/index.ts | 2 +- src/registry/map/index.ts | 2 +- src/registry/npFamilyMembers/index.ts | 2 +- src/registry/number/index.ts | 2 +- src/registry/password/index.ts | 2 +- src/registry/phonenumber/index.ts | 2 +- src/registry/postcode/index.ts | 2 +- src/registry/radio/index.ts | 2 +- src/registry/select/index.ts | 2 +- src/registry/selectboxes/index.ts | 2 +- src/registry/signature/index.ts | 2 +- src/registry/textarea/index.ts | 2 +- src/registry/textfield/index.ts | 2 +- src/registry/time/index.ts | 2 +- src/registry/types.ts | 60 ++++- 47 files changed, 836 insertions(+), 82 deletions(-) create mode 100644 src/components/FormPreview.stories.ts create mode 100644 src/components/FormPreview.tsx create mode 100644 src/components/form-preview.scss rename src/registry/columns/{preview.tsx => panel-preview.tsx} (51%) rename src/registry/columns/{preview.scss => previews.scss} (74%) create mode 100644 src/registry/columns/structure-preview.tsx create mode 100644 src/registry/columns/webform-preview.tsx create mode 100644 src/registry/content/webform-preview.tsx rename src/registry/editgrid/{preview.tsx => panel-preview.tsx} (100%) create mode 100644 src/registry/editgrid/previews.scss create mode 100644 src/registry/editgrid/structure-preview.tsx create mode 100644 src/registry/editgrid/webform-preview.tsx rename src/registry/fieldset/{preview.tsx => panel-preview.tsx} (100%) create mode 100644 src/registry/fieldset/structure-preview.tsx create mode 100644 src/registry/fieldset/webform-preview.tsx rename src/registry/{index.tsx => index.ts} (100%) diff --git a/src/components/ComponentPreview.tsx b/src/components/ComponentPreview.tsx index 5c9e2813..5d55e08e 100644 --- a/src/components/ComponentPreview.tsx +++ b/src/components/ComponentPreview.tsx @@ -85,8 +85,11 @@ const GenericComponentPreview: React.FC = ({ }) => { const {key} = component; const entry = getRegistryEntry(component); - const {preview: PreviewComponent, defaultValue = ''} = entry; - if (PreviewComponent === null) { + const { + preview: {panel: PanelPreviewComponent}, + defaultValue = '', + } = entry; + if (PanelPreviewComponent === null) { return null; } const isMultiple = hasOwnProperty(component, 'multiple') ? component.multiple : false; @@ -106,7 +109,7 @@ const GenericComponentPreview: React.FC = ({ component={component} initialValues={initialValues} > - + ); }; diff --git a/src/components/FormPreview.stories.ts b/src/components/FormPreview.stories.ts new file mode 100644 index 00000000..4c2bfe6a --- /dev/null +++ b/src/components/FormPreview.stories.ts @@ -0,0 +1,148 @@ +import {Meta, StoryObj} from '@storybook/react'; +import {expect, userEvent, waitFor, within} from '@storybook/test'; + +import {BuilderContextDecorator} from '@/sb-decorators'; + +import FormPreview from './FormPreview'; + +export default { + title: 'Public API/FormPreview (⚠️ UNSTABLE)', + component: FormPreview, + decorators: [BuilderContextDecorator], + parameters: { + modal: {noModal: true}, + }, +} satisfies Meta; + +type Story = StoryObj; + +export const SingleTextField: Story = { + name: 'Form with text field', + args: { + components: [ + { + id: 'oiejwa', + type: 'textfield', + key: 'parent.aTextField', + label: 'A text field', + defaultValue: 'a default value', + }, + ], + }, + play: async ({canvasElement}) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole('button', {name: 'Edit'})); + await waitFor(async () => { + expect(await canvas.findByRole('dialog')).toBeVisible(); + }); + }, +}; + +export const FieldSet: Story = { + name: 'Form with fieldset', + args: { + components: [ + { + id: 'oiejwa', + type: 'textfield', + key: 'aTextField', + label: 'A text field', + }, + { + id: 'wieurq4', + type: 'fieldset', + key: 'aFieldset', + label: 'Fieldset with nested components', + hideHeader: false, + components: [ + { + id: 'vr832jc', + type: 'textfield', + key: 'nestedTextfield', + label: 'Nested textfield', + }, + { + id: 'vrekjc', + type: 'textfield', + key: 'nestedTextfield2', + label: 'Nested textfield 2', + }, + ], + }, + { + id: 'cols1', + type: 'columns', + key: 'cols1', + columns: [ + { + size: 6, + sizeMobile: 4, + components: [ + { + id: 'number1', + type: 'number', + key: 'number1', + label: 'Number', + }, + ], + }, + { + size: 3, + sizeMobile: 4, + components: [ + { + id: 'email1', + type: 'email', + key: 'email1', + label: 'Email 1', + validateOn: 'blur', + }, + { + id: 'email2', + type: 'email', + key: 'email2', + label: 'Email 2', + validateOn: 'blur', + }, + ], + }, + { + size: 3, + sizeMobile: 4, + components: [ + { + id: 'content1', + type: 'content', + key: 'content1', + html: '

Some free form content

', + }, + ], + }, + ], + }, + { + id: 'editgrid1', + type: 'editgrid', + key: 'editgrid1', + label: 'Contacts', + groupLabel: 'Person', + disableAddingRemovingRows: false, + components: [ + { + id: 'editgridNested1', + type: 'textfield', + key: 'editgridNested1', + label: 'Name', + }, + { + id: 'editgridNested2', + type: 'phoneNumber', + key: 'editgridNested2', + label: 'Phone number', + inputMask: null, + }, + ], + }, + ], + }, +}; diff --git a/src/components/FormPreview.tsx b/src/components/FormPreview.tsx new file mode 100644 index 00000000..9c0c15ad --- /dev/null +++ b/src/components/FormPreview.tsx @@ -0,0 +1,251 @@ +import {AnyComponentSchema} from '@open-formulieren/types'; +import clsx from 'clsx'; +import {Formik} from 'formik'; +import {set} from 'lodash'; +import {useState} from 'react'; +import {FormattedMessage, useIntl} from 'react-intl'; + +import ComponentEditForm from '@/components/ComponentEditForm'; +import Modal from '@/components/Modal'; +import ModeToggle from '@/components/ModeToggle'; +import {getRegistryEntry} from '@/registry'; +import {hasOwnProperty} from '@/types'; + +import './form-preview.scss'; + +interface ActionIconProps { + icon: string; + label: string; + onClick: (event: React.MouseEvent) => void; +} + +const ActionIcon: React.FC = ({icon, label, onClick}) => ( +