Skip to content

Commit

Permalink
✨ [#52] Implement a minimal SelectBoxes formio component
Browse files Browse the repository at this point in the history
This component is to be used in the builder preview pane and
to set the defaultValue for the SelectBoxes inside the builder
edit form.
  • Loading branch information
sergei-maertens committed Nov 17, 2023
1 parent 99473b0 commit b22b7ab
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/components/formio/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export {default as DateTimeField} from './datetimefield';
export {default as TimeField} from './timefield';
export {default as Panel} from './panel';
export {default as Select} from './select';
export {default as SelectBoxes} from './selectboxes';
export {default as NumberField} from './number';
export * from './datagrid';
export {default as DataGrid} from './datagrid';
Expand Down
89 changes: 89 additions & 0 deletions src/components/formio/selectboxes.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {expect} from '@storybook/jest';
import {Meta, StoryObj} from '@storybook/react';
import {within} from '@storybook/testing-library';

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

import SelectBoxes from './selectboxes';

export default {
title: 'Formio/Components/SelectBoxes',
component: SelectBoxes,
decorators: [withFormik],
parameters: {
modal: {noModal: true},
formik: {initialValues: {'my-selectboxes': {}}},
},
args: {
name: 'my-selectboxes',
label: '',
tooltip: '',
options: [
{value: 'a', label: 'A'},
{value: 'b', label: 'B'},
],
},
} as Meta<typeof SelectBoxes>;

type Story = StoryObj<typeof SelectBoxes>;

export const Default: Story = {
args: {
label: 'Labeled selectboxes',
},
};

export const WithInitialChecked: Story = {
parameters: {
formik: {
initialValues: {
'my-selectboxes': {
b: true,
},
},
},
},
args: {
label: 'Labeled selectboxes',
},

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

await expect(canvas.getByLabelText('A')).not.toBeChecked();
await expect(canvas.getByLabelText('B')).toBeChecked();
},
};

export const WithToolTip: Story = {
args: {
label: 'With tooltip',
tooltip: 'Hiya!',
},
};

export const WithDescription: Story = {
args: {
label: 'With description',
description: 'A description',
},
};

export const WithErrors: Story = {
args: {
label: 'With errors',
},

parameters: {
formik: {
initialValues: {'my-selectboxes': false},
initialErrors: {'my-selectboxes': 'Example error', 'other-field': 'Other error'},
},
},

play: async ({canvasElement}) => {
const canvas = within(canvasElement);
await expect(canvas.queryByText('Other error')).not.toBeInTheDocument();
await expect(canvas.queryByText('Example error')).toBeInTheDocument();
},
};
46 changes: 46 additions & 0 deletions src/components/formio/selectboxes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {ReactNode} from 'react';

import {CheckboxInput} from './checkbox';
import Component from './component';
import Description from './description';

export interface Option {
value: string;
label: ReactNode;
}

export interface SelectBoxesProps {
name: string;
options: Option[];
label?: React.ReactNode;
required?: boolean;
tooltip?: string;
description?: string;
}

export const SelectBoxes: React.FC<SelectBoxesProps> = ({
name,
options,
label,
required = false,
tooltip = '',
description = '',
}) => {
return (
<Component type="selectboxes" field={name} label={label} tooltip={tooltip} required={required}>
<div className="form-radio radio">
{options.map(({value, label}, index) => (
<div key={`option-${value}-${index}`} className="form-check">
<label className="form-check-label">
<CheckboxInput name={`${name}.${value}`} label={label} />
</label>
</div>
))}
</div>

{description && <Description text={description} />}
</Component>
);
};

export default SelectBoxes;

0 comments on commit b22b7ab

Please sign in to comment.