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}) => ( +