@open-formulieren/formio-builder
Version:
An opinionated Formio webform builder for Open Forms
70 lines (69 loc) • 4.73 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
* Wrapper/HOC component to enable multi-input behaviour for (certain) fields.
*
* This component operates on arrays of values instead of just scalars, e.g. a list of
* strings, a list of dates... This is not guaranteed to be compatible with every
* 'atomic' component type of Form.io - Select/File upload handle this property
* themselves rather than needing to be wrapped.
*
* Usage:
*
* const MyComponent = ({name, label, description, ...props}) => {...}
* const MultipleMyComponent = withMultiple(MyComponent);
*
* <MyComponent name="foo" {...props} /> // <input name="foo" />
* <MultipleMyComponent multiple={true|false} name="foo" {...props} /> // <input name="foo[0]" /> etc. />
*
*/
import { FieldArray, useFormikContext } from 'formik';
import { FormattedMessage } from 'react-intl';
import { RenderContext } from '../../context';
import ComponentLabel from './component-label';
import Description from './description';
const Multiple = (props) => {
const { label, description, required, tooltip } = props;
const { as: WrappedComponent, defaultValue, name } = props, otherProps = __rest(props, ["as", "defaultValue", "name"]);
// TypeScript can't infer this itself with generics, as it doesn't know yet what P looks
// like by omitting multiple - but *we* know that HoC forward the remainder of the props.
const nestedProps = otherProps;
const { getFieldProps } = useFormikContext();
let { value: fieldValue } = getFieldProps(name);
// due to possibly bad value initialization, it's possible the value is undefined or
// even a completely different type (because you're switching from multiple false -> true)
// TODO: figure out we can figure this at the formik level? this probably depends on render
// order though
if (!Array.isArray(fieldValue)) {
fieldValue = [];
}
return (_jsxs(RenderContext.Provider, Object.assign({ value: { bareInput: true } }, { children: [label && _jsx(ComponentLabel, { label: label, required: required, tooltip: tooltip }), _jsx(FieldArray, Object.assign({ name: name }, { children: arrayHelpers => (_jsx("table", Object.assign({ className: "table table-bordered" }, { children: _jsxs("tbody", { children: [(fieldValue || []).map((_, index) => (_jsxs("tr", { children: [_jsx("td", { children: _jsx(WrappedComponent, Object.assign({ name: `${name}[${index}]` }, nestedProps)) }), _jsx("td", { children: _jsxs("button", Object.assign({ className: "btn btn-secondary", type: "button", onClick: () => arrayHelpers.remove(index) }, { children: [_jsx("span", Object.assign({ className: "sr-only" }, { children: _jsx(FormattedMessage, { id: 'd5SKAT', defaultMessage: [{ type: 0, value: "Remove item" }] }) })), _jsx("i", { className: "fa fa-times-circle-o", "aria-hidden": "true" })] })) })] }, index))), _jsx("tr", { children: _jsx("td", Object.assign({ colSpan: 2 }, { children: _jsxs("button", Object.assign({ type: "button", className: "btn btn-primary formio-button-add-another", onClick: () => arrayHelpers.push(defaultValue) }, { children: [_jsx("i", { className: "fa fa-plus", "aria-hidden": "true" }), _jsx(FormattedMessage, { id: 'Fc/emc', defaultMessage: [{ type: 0, value: "Add another" }] })] })) })) })] }) }))) })), description && _jsx(Description, { text: description })] })));
};
/**
* Wrap a given component into a higher order Multiple component.
*/
export function withMultiple(WrappedComponent, defaultValue) {
return (props) => {
const { multiple } = props, otherProps = __rest(props, ["multiple"]);
// TypeScript can't infer this itself with generics, as it doesn't know yet what P looks
// like by omitting multiple - but *we* know that HoC forward the remainder of the props.
const nestedProps = otherProps;
// in single value/scalar mode -> just render the component itself
if (!multiple) {
return _jsx(WrappedComponent, Object.assign({}, nestedProps));
}
// otherwise, go into array-of-fields mode
return _jsx(Multiple, Object.assign({ as: WrappedComponent, defaultValue: defaultValue }, otherProps));
};
}
export default Multiple;