diff --git a/frontend/packages/volto-form-block/src/index.js b/frontend/packages/volto-form-block/src/index.js
index c727fea..f4222cf 100644
--- a/frontend/packages/volto-form-block/src/index.js
+++ b/frontend/packages/volto-form-block/src/index.js
@@ -93,6 +93,8 @@ const applyConfig = (config) => {
edit: schemaFormBlockEdit,
formSchema: FormSchema,
widgets: null,
+ component: null,
+ buttonComponent: null,
blockSchema: schemaFormBlockSchema,
fieldSchema: FieldSchema,
disableEnter: true,
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/EditSchemaForm.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/EditSchemaForm.jsx
index 1bdf7fc..cab757b 100644
--- a/frontend/packages/volto-form-block/src/schemaFormBlock/EditSchemaForm.jsx
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/EditSchemaForm.jsx
@@ -75,6 +75,10 @@ class Edit extends Component {
title: 'Form',
type: 'object',
}}
+ component={config.blocks.blocksConfig.schemaForm.component}
+ buttonComponent={
+ config.blocks.blocksConfig.schemaForm.buttonComponent
+ }
formData={
isEmpty(data.schema)
? { schema: defaultEmptyData }
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/ViewSchemaForm.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/ViewSchemaForm.jsx
index 0a98280..98ebce6 100644
--- a/frontend/packages/volto-form-block/src/schemaFormBlock/ViewSchemaForm.jsx
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/ViewSchemaForm.jsx
@@ -169,6 +169,10 @@ const FormBlockView = ({ data, id, properties, metadata, path }) => {
}}
formData={initialData}
widgets={config.blocks.blocksConfig.schemaForm.widgets}
+ component={config.blocks.blocksConfig.schemaForm.component}
+ buttonComponent={
+ config.blocks.blocksConfig.schemaForm.buttonComponent
+ }
onSubmit={onSubmit}
resetOnCancel={true}
onCancel={data.show_cancel ? onCancel : null}
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/CheckboxGroupWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/CheckboxGroupWrapper.jsx
new file mode 100644
index 0000000..76ac418
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/CheckboxGroupWrapper.jsx
@@ -0,0 +1,62 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const CheckboxGroupWrapper = (props) => {
+ const {
+ id,
+ value,
+ choices,
+ onChange,
+ onClick,
+ isDisabled,
+ title,
+ description,
+ } = props;
+
+ const ref = useRef();
+ const Widget =
+ config.blocks.blocksConfig.schemaForm.innerWidgets.checkboxGroup;
+ const OptionWidget =
+ config.blocks.blocksConfig.schemaForm.innerWidgets.checkboxGroupOption;
+
+ const options = choices || [];
+
+ return (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ >
+ {options.map((option) => (
+ {option[1]}
+ ))}
+
+
+ );
+};
+
+export default CheckboxGroupWrapper;
+
+CheckboxGroupWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/CheckboxWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/CheckboxWrapper.jsx
new file mode 100644
index 0000000..72ba434
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/CheckboxWrapper.jsx
@@ -0,0 +1,45 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const CheckboxWrapper = (props) => {
+ const { id, value, onChange, onClick, isDisabled, title, description } =
+ props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.checkbox;
+
+ return (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ />
+
+ );
+};
+
+export default CheckboxWrapper;
+
+CheckboxWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/DatetimeWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/DatetimeWrapper.jsx
new file mode 100644
index 0000000..f8c85f8
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/DatetimeWrapper.jsx
@@ -0,0 +1,45 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const DatetimeWrapper = (props) => {
+ const { id, value, onChange, onClick, isDisabled, title, description } =
+ props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.datetime;
+
+ return (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ />
+
+ );
+};
+
+export default DatetimeWrapper;
+
+DatetimeWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/EmailWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/EmailWrapper.jsx
new file mode 100644
index 0000000..38e8b77
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/EmailWrapper.jsx
@@ -0,0 +1,58 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const EmailWrapper = (props) => {
+ const {
+ id,
+ value,
+ onChange,
+ onClick,
+ minLength,
+ maxLength,
+ isDisabled,
+ title,
+ description,
+ } = props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.email;
+
+ return (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ minLength={minLength || null}
+ maxLength={maxLength || null}
+ />
+
+ );
+};
+
+export default EmailWrapper;
+
+EmailWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+ minLength: null,
+ maxLength: null,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/FileWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/FileWrapper.jsx
new file mode 100644
index 0000000..8817520
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/FileWrapper.jsx
@@ -0,0 +1,65 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+import { readAsDataURL } from 'promise-file-reader';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const FileWrapper = (props) => {
+ const { id, value, onChange, isDisabled, title, description, accept, size } =
+ props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.file;
+
+ console.log(value);
+
+ return (
+
+ {
+ if (files.length < 1) return;
+ const file = files[0];
+ readAsDataURL(file).then((data) => {
+ const fields = data.match(/^data:(.*);(.*),(.*)$/);
+ onChange(id, {
+ data: fields[3],
+ encoding: fields[2],
+ 'content-type': fields[1],
+ filename: file.name,
+ });
+ });
+ }}
+ deleteFilesCallback={() => {
+ onChange(id, null);
+ }}
+ ref={ref}
+ />
+
+ );
+};
+
+export default FileWrapper;
+
+FileWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.object,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+ accept: PropTypes.string,
+ size: PropTypes.number,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/FormComponent.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/FormComponent.jsx
new file mode 100644
index 0000000..472dc3a
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/FormComponent.jsx
@@ -0,0 +1,25 @@
+import PropTypes from 'prop-types';
+import _ from 'lodash';
+
+const FormComponent = (props) => {
+ const { children, onSubmit, error } = props;
+
+ const handleSubmit = (e, ...args) => {
+ if (typeof action !== 'string') _.invoke(e, 'preventDefault');
+ _.invoke(props, 'onSubmit', e, props, ...args);
+ };
+
+ return (
+
+ );
+};
+
+export default FormComponent;
+
+FormComponent.propTypes = {
+ children: PropTypes.node,
+ onSubmit: PropTypes.func,
+ error: PropTypes.bool,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/HiddenWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/HiddenWrapper.jsx
new file mode 100644
index 0000000..1055bb4
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/HiddenWrapper.jsx
@@ -0,0 +1,64 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const HiddenWrapper = (props) => {
+ const {
+ id,
+ value,
+ onChange,
+ onClick,
+ placeholder,
+ isDisabled,
+ title,
+ description,
+ onEdit,
+ } = props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.hidden;
+
+ return onEdit ? (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ />
+
+ ) : (
+
+ );
+};
+
+export default HiddenWrapper;
+
+HiddenWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/NumberWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/NumberWrapper.jsx
new file mode 100644
index 0000000..f994adb
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/NumberWrapper.jsx
@@ -0,0 +1,54 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const NumberWrapper = (props) => {
+ const {
+ id,
+ value,
+ onChange,
+ onClick,
+ placeholder,
+ isDisabled,
+ title,
+ description,
+ } = props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.number;
+
+ return (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ />
+
+ );
+};
+
+export default NumberWrapper;
+
+NumberWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/RadioGroupWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/RadioGroupWrapper.jsx
new file mode 100644
index 0000000..a301d3b
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/RadioGroupWrapper.jsx
@@ -0,0 +1,61 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const RadioGroupWrapper = (props) => {
+ const {
+ id,
+ value,
+ choices,
+ onChange,
+ onClick,
+ isDisabled,
+ title,
+ description,
+ } = props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.radioGroup;
+ const OptionWidget =
+ config.blocks.blocksConfig.schemaForm.innerWidgets.radioGroupOption;
+
+ const options = choices || [];
+
+ return (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ >
+ {options.map((option) => (
+ {option[1]}
+ ))}
+
+
+ );
+};
+
+export default RadioGroupWrapper;
+
+RadioGroupWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/SelectWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/SelectWrapper.jsx
new file mode 100644
index 0000000..66a2d73
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/SelectWrapper.jsx
@@ -0,0 +1,59 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const SelectWrapper = (props) => {
+ const {
+ id,
+ value,
+ choices,
+ onChange,
+ onClick,
+ isDisabled,
+ title,
+ description,
+ } = props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.select;
+
+ const options = choices || [];
+
+ return (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ options={options.map((option) => ({
+ value: option[0],
+ label: option[1],
+ }))}
+ />
+
+ );
+};
+
+export default SelectWrapper;
+
+SelectWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TextWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TextWrapper.jsx
index edd9d91..dc68289 100644
--- a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TextWrapper.jsx
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TextWrapper.jsx
@@ -1,4 +1,4 @@
-import { useEffect, useRef } from 'react';
+import { useRef } from 'react';
import PropTypes from 'prop-types';
import config from '@plone/volto/registry';
@@ -15,6 +15,7 @@ const TextWrapper = (props) => {
placeholder,
isDisabled,
title,
+ description,
} = props;
const ref = useRef();
@@ -27,6 +28,7 @@ const TextWrapper = (props) => {
name={id}
value={value || ''}
label={title}
+ description={description}
disabled={isDisabled}
placeholder={placeholder}
onChange={(value) => onChange(id, value === '' ? undefined : value)}
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TextareaWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TextareaWrapper.jsx
new file mode 100644
index 0000000..10bc391
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TextareaWrapper.jsx
@@ -0,0 +1,60 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const TextareaWrapper = (props) => {
+ const {
+ id,
+ value,
+ onChange,
+ onClick,
+ minLength,
+ maxLength,
+ placeholder,
+ isDisabled,
+ title,
+ description,
+ } = props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.textarea;
+
+ return (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ minLength={minLength || null}
+ maxLength={maxLength || null}
+ />
+
+ );
+};
+
+export default TextareaWrapper;
+
+TextareaWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+ minLength: null,
+ maxLength: null,
+};
diff --git a/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TimeWrapper.jsx b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TimeWrapper.jsx
new file mode 100644
index 0000000..b202bdb
--- /dev/null
+++ b/frontend/packages/volto-form-block/src/schemaFormBlock/Wrappers/TimeWrapper.jsx
@@ -0,0 +1,45 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import config from '@plone/volto/registry';
+
+import FormFieldWrapper from './FormFieldWrapper';
+
+const TimeWrapper = (props) => {
+ const { id, value, onChange, onClick, isDisabled, title, description } =
+ props;
+
+ const ref = useRef();
+ const Widget = config.blocks.blocksConfig.schemaForm.innerWidgets.time;
+
+ return (
+
+ onChange(id, value === '' ? undefined : value)}
+ ref={ref}
+ onClick={() => onClick()}
+ />
+
+ );
+};
+
+export default TimeWrapper;
+
+TimeWrapper.propTypes = {
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ required: PropTypes.bool,
+ error: PropTypes.arrayOf(PropTypes.string),
+ value: PropTypes.string,
+ focus: PropTypes.bool,
+ onChange: PropTypes.func,
+ onClick: PropTypes.func,
+ onEdit: PropTypes.func,
+ onDelete: PropTypes.func,
+};