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 ( +
+ {children} +
+ ); +}; + +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, +};