import * as React from "react"; import { merge } from "lodash"; import { FormBuilderProps, FormFieldTypes } from "./types"; import { EditorMode } from "../../Editor/types"; import LiveFormField from "./LiveFormField"; import { EditFormField } from "./EditFormField"; import { LiveFormFieldProps } from "./LiveFormField/types"; import { SortableList, DefaultItemComponent, } from "@sc/modules/v2/CRUD/SortableList"; import { Grid } from "@material-ui/core"; import { Icon } from "@sc/plugins/webcomponents/v2"; import { FieldNamePresets, FieldNameIcons } from "./EditFormField/types"; import { IconTypes } from "@sc/plugins/webcomponents/v2/Icon"; import theme from "@sc/components/ui/theme"; import { ItemComponentTypes } from "../SortableList/types"; interface ItemProps extends LiveFormFieldProps { onMouseEnter?: (event: React.MouseEvent) => void; onMouseLeave?: (event: React.MouseEvent) => void; isHovering?: boolean; } const newFormItem: LiveFormFieldProps = { id: Math.random() .toString(36) .slice(2), type: FormFieldTypes.TEXT, name: "MyTextBox", placeholder: "Placeholder Test", label: "Text Label", description: "Text Description", defaultValue: "Testing Default Value", // styles: styleData, // icon: IconTypes.Email, columns: 12, preset: FieldNamePresets.CUSTOM, }; /** * A module for displaying, validating, and handling groups of form fields * * - Displays in either live view or edit view * - In "edit view", a drag-and-drop ux is provided to help users build forms * - Shows a list sortable object with a custom item container (<EditFormField />) * - In "live view", the form is generated based on the incoming data it receives */ const FormBuilder: React.FC = ({ mode = EditorMode.LIVE, data = [], globalFieldStyle, onChange = () => null, onBlur = () => null, }) => { const [isExpandedList, setIsExpandedList] = React.useState([]); const handleTypeChange = (id: string, type: FormFieldTypes): void => { const key = data.findIndex((itm) => itm.id === id); onChange([ ...data.slice(0, key), { ...data[key], type }, ...data.slice(key + 1), ]); // make sure it is expanded if (isExpandedList.indexOf(id) === -1) setIsExpandedList([...isExpandedList, id]); }; const handleChange = (mutatedPayload: LiveFormFieldProps[]): void => { console.log({ mutatedPayload }); onChange(mutatedPayload); }; const handleEdit = (data: LiveFormFieldProps): void => { // toggle expansion if (isExpandedList.indexOf(data.id) > -1) { // remove if it exists setIsExpandedList(isExpandedList.filter((id) => id !== data.id)); } else { // add if it doesn't exist setIsExpandedList([...isExpandedList, data.id]); } }; const ItemComponent: React.FC = (itm) => { const { id, type, preset, styles } = itm; const [fieldData, setFieldData] = React.useState(itm); const isExpanded = Boolean(isExpandedList.indexOf(id) > -1); const handleSingleFieldChange = ( attrItem: LiveFormFieldProps, dbUpdate = true ): void => { const key = data.findIndex((itm) => itm.id === attrItem.id); const newData = [...data.slice(0, key), attrItem, ...data.slice(key + 1)]; setFieldData(attrItem); if (dbUpdate) onChange(newData); }; const handleSingleFieldBlur = ( attrItem: LiveFormFieldProps, dbUpdate = true ): void => { const key = data.findIndex((itm) => itm.id === attrItem.id); const newData = [...data.slice(0, key), attrItem, ...data.slice(key + 1)]; setFieldData(attrItem); if (dbUpdate) onBlur(newData); }; return ( handleSingleFieldBlur(newData)} onChange={(newData) => handleSingleFieldChange(newData, false)} onTypeChange={(type: FormFieldTypes) => handleTypeChange(id, type)} globalFieldStyle={merge(globalFieldStyle, styles)} isExpanded /> ); }; return (
{mode === EditorMode.LIVE && ( {data.map((itm, key) => ( ))} )} {mode === EditorMode.EDITOR && ( handleChange([...data, newFormItem])} onEdit={handleEdit} onChange={handleChange} onDelete={(payload, updatedData) => handleChange(updatedData)} canDragAndDrop showItemInline={false} /> )}
); }; export default FormBuilder;