UNPKG

@open-formulieren/formio-builder

Version:

An opinionated Formio webform builder for Open Forms

70 lines (69 loc) 4.73 kB
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;