From 7fdb76bca64e2e72768f6de7bfa3fea98d2d5bbb Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 30 Aug 2023 14:41:37 -0400 Subject: feat: add form builder component --- src/components/FormBuilder/index.js | 315 ++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 src/components/FormBuilder/index.js diff --git a/src/components/FormBuilder/index.js b/src/components/FormBuilder/index.js new file mode 100644 index 0000000..b9f0389 --- /dev/null +++ b/src/components/FormBuilder/index.js @@ -0,0 +1,315 @@ +import { DragIndicator, Clear } from "@mui/icons-material"; +import { + Card, + CardContent, + CardHeader, + IconButton, + Stack, + TextField, +} from "@mui/material"; +import React, { useRef, useState } from "react"; +export default function FormBuilder() { + return ( + +

FormBuilder

+ +
+ + + + ); +} + +const availableWidgets = { + label: { + name: "Label", + element: (props) => ( + + props?.setFormField({ ...props, name: e.target.value }) + } + fullWidth + /> + ), + finalElement: (props) =>
{props?.id}
, + }, + number: { + name: "Number", + element: (props) => ( + + ), + }, + text: { + name: "Text", + element: (props) => ( + + ), + }, + multiline: { + name: "Multiline", + element: (props) => ( + + ), + }, +}; + +function WidgetsLibrary() { + return ( + + {Object.keys(availableWidgets).map((k) => { + const props = availableWidgets[k]; + return ; + })} + + ); +} + +function WidgetCard({ name, element, type, finalElement }) { + function onDragStart(e) { + e.dataTransfer.setData("application/formwidgettype", type); + e.dataTransfer.effectAllowed = "copy"; + console.log(e); + } + + const disabledFieldOverlay = { + pointerEvents: "none", + background: "#7773", + zIndex: 10, + }; + if (!element) { + return; + } else { + return ( + + + +
+ + +
+ {finalElement ? finalElement() : element()} +
+
+
+
+
+ ); + } +} + +function FormField(props) { + if (!props?.type) { + console.log("formfield render failed", props); + return; + } + const { element: Element } = availableWidgets[props?.type]; + const dragHandleRef = useRef(); + const [target, setTarget] = useState(); + return ( + setTarget(e.target)} + onDragStart={(e) => { + if (dragHandleRef.current.contains(target)) { + e.dataTransfer.setData("application/formwidgetid", props?.id); + } else { + e.preventDefault(); + } + }} + > + + + + + props?.deleteFormField()}> + + + + ); +} + +function capture(e) { + e.stopPropagation(); + e.preventDefault(); +} + +function DropZone({ insertField, index, moveField }) { + const [dragOver, setDragOver] = useState(false); + return ( + capture(e) || setDragOver(true)} + onDragExit={() => setDragOver(false)} + onDrop={(e) => { + e.stopPropagation(); + e.preventDefault(); + setDragOver(false); + console.log(e); + if ([...e.dataTransfer.types].includes("application/formwidgettype")) { + const type = e.dataTransfer.getData("application/formwidgettype"); + insertField({ index, type }); + } else if ( + [...e.dataTransfer.types].includes("application/formwidgetid") + ) { + const oldId = e.dataTransfer.getData("application/formwidgetid"); + moveField(oldId, index); + } + }} + /> + ); +} + +function Form({ initialForm, editable }) { + const [form, setForm] = useState({ fields: [], ...initialForm }); + + function updateFormField(newField) { + setForm({ + ...form, + fields: form.fields.map((field) => + field?.id === newField.id ? newField : field, + ), + }); + } + + function deleteFormField(id) { + const newForm = { + ...form, + fields: form.fields.filter((field) => id !== field?.id), + }; + console.log("deleteFormField", { id, form, newForm }); + setForm({ ...newForm }); + } + console.log("render", form.fields); + + function insertField({ index, type }) { + const id = crypto.randomUUID(); + const newField = { + id, + type, + }; + form?.fields?.splice(index + 1, 0, newField); + setForm({ ...form }); + } + + function moveField(oldId, newIndex) { + console.log({ oldId, newIndex }); + const oldIndex = form.fields.findIndex(({ id }) => id === oldId); + const [oldFormField] = form.fields.splice(oldIndex, 1); + if (oldIndex > newIndex) { + newIndex++; + } + form.fields.splice(newIndex, 0, oldFormField); + console.log("newform", form); + setForm({ ...form }); + } + + if (!editable && !initialForm) { + return; + // else if (!initialForm) { + // return ; + // } + } else { + return ( + + + {editable && ( + + )} + {form?.fields?.map((props, i) => ( + + updateFormField(field)} + deleteFormField={() => deleteFormField(props.id)} + {...props} + /> + {editable && ( + + )} + + ))} + + ); + } +} + +function FormHeader() { + return; +} + +//function FormInitialPrompt() { +// return ( +//
+// Drag and drop and field here to get started +//
+// ); +//} +// +function Grouping({ children }) { + return <>{children}; +} -- cgit v1.2.3