Skip to content

Commit

Permalink
✨ [#21] Implement preview reacting to multiple toggle + defaultValue
Browse files Browse the repository at this point in the history
  • Loading branch information
sergei-maertens committed Sep 4, 2023
1 parent 6fd3f5e commit a44cc6a
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/components/ComponentEditForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const ComponentEditForm: React.FC<ComponentEditFormProps> = ({

<div className="row">
<div className="col col-sm-6">
<Form>
<Form data-testid="componentEditForm">
<div className="formio-component formio-component-label-hidden">
<div className="formio-form">
<div className="formio-component-tabs">
Expand Down
4 changes: 0 additions & 4 deletions src/components/ComponentPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ export interface GenericComponentPreviewProps {
* It is also responsible for handling the `multiple: true` variants in a generic way.
*/
const GenericComponentPreview: React.FC<GenericComponentPreviewProps> = ({component}) => {
console.log(component);

const key = isKnownComponentType(component) ? component.key : '';
const entry = getRegistryEntry(component);
const {preview: PreviewComponent, defaultValue = ''} = entry;
Expand All @@ -77,8 +75,6 @@ const GenericComponentPreview: React.FC<GenericComponentPreviewProps> = ({compon
? component.defaultValue ?? []

Check failure on line 75 in src/components/ComponentPreview.tsx

View workflow job for this annotation

GitHub Actions / Create 'production' build

Property 'defaultValue' does not exist on type 'FallbackSchema'.
: component.defaultValue ?? defaultValue;

Check failure on line 76 in src/components/ComponentPreview.tsx

View workflow job for this annotation

GitHub Actions / Create 'production' build

Property 'defaultValue' does not exist on type 'FallbackSchema'.

console.log(previewDefaultValue);

const initialValues = key ? {[key]: previewDefaultValue} : {};

return (
Expand Down
29 changes: 27 additions & 2 deletions src/components/builder/multiple.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
import {AnyComponentSchema} from '@open-formulieren/types';
import {useFormikContext} from 'formik';
import {FormattedMessage, useIntl} from 'react-intl';

import {hasOwnProperty} from '@/types';

import {Checkbox} from '../formio';

const Multiple = () => {
const hasDefaultValue = (component: any): component is AnyComponentSchema & {defaultValue: any} => {
return hasOwnProperty(component, 'defaultValue');
};

function Multiple<T = unknown>() {
const intl = useIntl();
const {values, getFieldProps, setFieldValue} = useFormikContext<T>();
const {onChange: formikOnChange} = getFieldProps<boolean>('multiple');

const tooltip = intl.formatMessage({
description: "Tooltip for 'Multiple values' builder field",
defaultMessage: 'Are there multiple values possible for this field?',
});

const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
formikOnChange(e);
// update the default value, if there is any
if (!hasDefaultValue(values)) return;
const {defaultValue} = values;
if (defaultValue === undefined) return;

const multiEnabled = e.target.checked;
const newDefaultValue = multiEnabled ? [defaultValue] : defaultValue[0];
setFieldValue('defaultValue', newDefaultValue);
};

return (
<Checkbox
name="multiple"
Expand All @@ -18,8 +42,9 @@ const Multiple = () => {
/>
}
tooltip={tooltip}
onChange={onChange}
/>
);
};
}

export default Multiple;
11 changes: 9 additions & 2 deletions src/components/formio/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import clsx from 'clsx';
import {Field} from 'formik';
import {Field, FormikHandlers, useFormikContext} from 'formik';

import {useValidationErrors} from '@/utils/errors';

Expand All @@ -10,9 +10,12 @@ export interface CheckboxProps {
name: string;
label?: React.ReactNode;
tooltip?: string;
onChange?: FormikHandlers['handleChange'];
}

const Checkbox: React.FC<CheckboxProps> = ({name, label, tooltip = ''}) => {
const Checkbox: React.FC<CheckboxProps> = ({name, label, tooltip = '', onChange}) => {
const {getFieldProps} = useFormikContext();
const {onChange: formikOnChange} = getFieldProps(name);
const {hasErrors} = useValidationErrors(name);
return (
<Component field={name} type="checkbox">
Expand All @@ -23,6 +26,10 @@ const Checkbox: React.FC<CheckboxProps> = ({name, label, tooltip = ''}) => {
as="input"
type="checkbox"
className={clsx('form-check-input', {'is-invalid': hasErrors})}
onChange={(e: React.ChangeEvent<any>) => {
formikOnChange(e);
onChange?.(e);
}}
/>
<span>{label}</span>
{tooltip && ' '}
Expand Down
2 changes: 1 addition & 1 deletion src/registry/textfield/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const EditForm: EditFormDefinition<TextFieldComponentSchema> = () => {
<Description />
<Tooltip />
<PresentationConfig />
<Multiple />
<Multiple<TextFieldComponentSchema> />
<Hidden />
<ClearOnHide />
<IsSensitiveData />
Expand Down
24 changes: 24 additions & 0 deletions src/registry/textfield/textfield-component.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const PreviewInitialValues: Story = {
name: 'defaultValue in preview',
play: async ({canvasElement, step}) => {
const canvas = within(canvasElement);
const editForm = within(canvas.getByTestId('componentEditForm'));
const preview = within(canvas.getByTestId('componentPreview'));

await step('Render single defaultValue in preview', async () => {
Expand All @@ -45,5 +46,28 @@ export const PreviewInitialValues: Story = {
const previewInput = preview.getByRole('textbox');
expect(previewInput).toHaveDisplayValue('Show me in preview!');
});

await step('Toggle to multi=true', async () => {
await userEvent.click(canvas.getByLabelText('Multiple values'));
// the single defaultValue should become the first element in the multiple array
await editForm.findByDisplayValue('Show me in preview!');
});

await step('Add a second item to default value', async () => {
const addButton = editForm.getByRole('button', {name: 'Add another'});
await userEvent.click(addButton);
await userEvent.type(editForm.getByTestId('input-defaultValue[1]'), 'Second item');
await editForm.findByDisplayValue('Second item');
});

await step('Toggle back to multi=false', async () => {
await userEvent.click(canvas.getByLabelText('Multiple values'));
// the single defaultValue should become the first element in the multiple array
await editForm.findByDisplayValue('Show me in preview!');
expect(editForm.queryByDisplayValue('Second item')).not.toBeInTheDocument();

await preview.findByDisplayValue('Show me in preview!');
expect(preview.queryByDisplayValue('Second item')).not.toBeInTheDocument();
});
},
};

0 comments on commit a44cc6a

Please sign in to comment.