Skip to content

Commit

Permalink
✨ [#52] Implement itemsExpression form field
Browse files Browse the repository at this point in the history
The initial approach used the generic TextArea, but that leads to a
horrible User Experience. Luckily enough we can re-use the JSONEdit
component that was made for Laurens.
  • Loading branch information
sergei-maertens committed Nov 15, 2023
1 parent 83367ad commit fee85ae
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/components/builder/values/items-expression.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {expect} from '@storybook/jest';
import {Meta, StoryObj} from '@storybook/react';
import {within} from '@storybook/testing-library';

import {withFormik} from '@/sb-decorators';

import ItemsExpression from './items-expression';

export default {
title: 'Formio/Builder/Values/ItemsExpression',
component: ItemsExpression,
decorators: [withFormik],
parameters: {
controls: {hideNoControlsWarning: true},
modal: {noModal: true},
formik: {
initialValues: {
openForms: {
itemsExpression: {var: 'someVar'},
},
},
},
},
args: {
name: 'values',
},
argTypes: {
name: {control: {disable: true}},
},
tags: ['autodocs'],
} as Meta<typeof ItemsExpression>;

type Story = StoryObj<typeof ItemsExpression>;

export const Default: Story = {
play: async ({canvasElement}) => {
const canvas = within(canvasElement);

const stringified = JSON.stringify({var: 'someVar'}, null, 2);
expect(canvas.getByRole('textbox')).toHaveDisplayValue(stringified);
},
};
51 changes: 51 additions & 0 deletions src/components/builder/values/items-expression.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {JSONObject} from '@open-formulieren/types/lib/types';
import {useFormikContext} from 'formik';
import {FormattedMessage} from 'react-intl';

import JSONEdit from '@/components/JSONEdit';
import {Component, Description} from '@/components/formio';

const NAME = 'openForms.itemsExpression';

/**
* The `ItemsExpression` component is used to specify the JsonLogic expression to
* calculate the values/options for a component.
*
* @todo: this would really benefit from a nice, context-aware JsonLogic editor.
*/
export const ItemsExpression: React.FC = () => {
const {getFieldProps} = useFormikContext();
const {value = ''} = getFieldProps<JSONObject | string | undefined>(NAME);

const htmlId = `editform-${NAME}`;
return (
<Component
type="textarea"
field={NAME}
required
htmlId={htmlId}
label={
<FormattedMessage
description="Label for 'openForms.itemsExpression' builder field"
defaultMessage="Items expression"
/>
}
>
<div>
<JSONEdit data={value} rows={3} />
</div>

<Description
text={
<FormattedMessage
description="Description for the 'openForms.itemsExpression' builder field"
defaultMessage={`A JSON logWic expression returning a variable (of array type)
whose items should be used as the options for this component.`}
/>
}
/>
</Component>
);
};

export default ItemsExpression;
2 changes: 2 additions & 0 deletions src/components/builder/values/values-config.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {useFormikContext} from 'formik';

import ItemsExpression from './items-expression';
import {SchemaWithDataSrc} from './types';
import ValuesSrc from './values-src';
import ValuesTable, {ValuesTableProps} from './values-table';
Expand Down Expand Up @@ -28,6 +29,7 @@ export function ValuesConfig<T extends SchemaWithDataSrc>({name}: ValuesConfigPr
<>
<ValuesSrc />
{dataSrc === 'manual' && <ValuesTable<T> name={name} />}
{dataSrc === 'variable' && <ItemsExpression />}
</>
);
}
Expand Down

0 comments on commit fee85ae

Please sign in to comment.