diff --git a/src/components/formDesigner/ComponentRenderer.vue b/src/components/formDesigner/ComponentRenderer.vue index e360327..94287ad 100644 --- a/src/components/formDesigner/ComponentRenderer.vue +++ b/src/components/formDesigner/ComponentRenderer.vue @@ -1,6 +1,10 @@ @@ -29,6 +33,14 @@ export default defineComponent({ type: Object, required: true, }, + index: { + type: Number, + required: true, + }, + direction: { + type: String, + required: true, + }, }, computed: { resolvedComponent() { @@ -42,11 +54,67 @@ export default defineComponent({ }; return componentMap[this.element.type] || null; }, + computedDropClass() { + return this.direction === "horizontal" ? "drop-zone-horizontal" : "drop-zone-vertical"; + }, }, methods: { updateSchema(newItems) { this.$emit("update-schema", newItems); // 🔥 Leitet die Änderung weiter }, + onDragEnter(event) { + event.preventDefault(); + }, + onDrop(event, position) { + event.preventDefault(); + const droppedType = event.dataTransfer.getData("text/plain"); + const newElement = this.createElementByType(droppedType); + if (newElement) { + this.$emit("insert-item", { position, newElement }); + } + }, + createElementByType(type) { + switch (type) { + case "InputText": + return { type: "InputText", label: "Neues Textfeld", placeholder: "Hier eingeben..." }; + case "InputNumber": + return { type: "InputNumber", label: "Neue Zahl", placeholder: "0" }; + case "InputDate": + return { type: "InputDate", label: "Neues Datum" }; + case "Button": + return { type: "Button", label: "Klicken" }; + case "Label": + return { type: "Label", value: "Neues Label" }; + case "FlexLayout": + return { type: "FlexLayout", direction: "vertical", items: [] }; + default: + console.warn("⚠ Unbekannter Typ:", type); + return null; + } + }, }, }); + + diff --git a/src/components/formDesigner/formRenderer/FlexLayoutRenderer.vue b/src/components/formDesigner/formRenderer/FlexLayoutRenderer.vue index 2407fc9..7439c95 100644 --- a/src/components/formDesigner/formRenderer/FlexLayoutRenderer.vue +++ b/src/components/formDesigner/formRenderer/FlexLayoutRenderer.vue @@ -1,8 +1,6 @@ @@ -16,7 +14,6 @@ export default defineComponent({ data() { return { dragOverActive: false, - hasParentFlexLayout: false, }; }, props: { @@ -33,67 +30,52 @@ export default defineComponent({ computedDirection() { return this.direction === "horizontal" ? "horizontal" : "vertical"; }, - isInnerMostLayout() { - return !this.items.some((item) => item.type === "FlexLayout") && this.hasParentFlexLayout; - }, - isOuterLayout() { - return !this.hasParentFlexLayout; + computedDropClass() { + return this.direction === "horizontal" ? "drop-zone-horizontal" : "drop-zone-vertical"; }, }, methods: { - /** - * 🔄 Aktualisiert verschachtelte FlexLayouts - */ updateChildItems(index, newItems) { const updatedItems = [...this.items]; - updatedItems[index] = { ...updatedItems[index], items: newItems }; // ✅ Tiefere Rekursion möglich - this.$emit("update-items", updatedItems); // 🔥 Weitergabe an Parent + updatedItems[index] = { ...updatedItems[index], items: newItems }; + this.$emit("update-items", updatedItems); }, - - /** - * 🚀 Wenn ein Drag über das Layout geht - */ onDragOver(event) { event.preventDefault(); - event.stopPropagation(); - if (this.isInnerMostLayout) { - this.dragOverActive = true; - } else if (this.isOuterLayout) { - this.dragOverActive = true; - } else { - this.dragOverActive = false; - } + this.dragOverActive = true; }, - - /** - * 📌 Wenn ein Element in das FlexLayout gedroppt wird - */ - onDrop(event) { + onDragEnter(event) { event.preventDefault(); - event.stopPropagation(); - this.dragOverActive = false; + }, + onDrop(event, position) { + event.preventDefault(); + console.log(`📌 onDrop aufgerufen bei Position: ${position}`); // 🔥 Debugging-Log const droppedType = event.dataTransfer.getData("text/plain"); + console.log(`📦 Gedropptes Element: ${droppedType}`); // 🔥 Zeigt an, was gedroppt wurde const newElement = this.createElementByType(droppedType); if (newElement) { - const updatedItems = [...this.items, newElement]; // ✅ Neue Liste mit Element - this.$emit("update-items", updatedItems); // 🔥 An Parent weiterleiten + console.log(`✅ Neues Element erstellt:`, newElement); + this.insertItem({ position, newElement }); + } else { + console.warn("⚠ Kein gültiges Element erstellt!"); } }, + insertItem({ position, newElement }) { + console.log(`🔧 Inserting at position: ${position}`, newElement); // 🔥 Debugging-Log - /** - * ❌ Wenn das Drag das Layout verlässt - */ - onDragLeave(event) { - event.preventDefault(); - event.stopPropagation(); - this.dragOverActive = false; + const updatedItems = [...this.items]; + + // 🛠 Stelle sicher, dass `position` innerhalb der Liste bleibt + if (position < 0) position = 0; + if (position > updatedItems.length) position = updatedItems.length; + + updatedItems.splice(position, 0, newElement); // 🔥 Element an richtiger Stelle einfügen + console.log("🔄 Updated Items:", updatedItems); // 🔥 Zeigt die neue Liste in der Konsole + + this.$emit("update-items", updatedItems); // 🔥 Änderungen an Parent weitergeben }, - - /** - * 🔧 Erstellt das passende Element basierend auf dem Typ - */ createElementByType(type) { switch (type) { case "InputText": @@ -114,16 +96,6 @@ export default defineComponent({ } }, }, - mounted() { - let parent = this.$parent; - while (parent) { - if (parent.$options.name === "FlexLayoutRenderer") { - this.hasParentFlexLayout = true; - break; - } - parent = parent.$parent; - } - }, }); @@ -134,6 +106,7 @@ export default defineComponent({ min-height: 50px; } +/* Layouts richtig ausrichten */ .horizontal { flex-direction: row; } @@ -142,8 +115,21 @@ export default defineComponent({ flex-direction: column; } -.flex-layout.drag-over { - border-left: 5px solid var(--bs-primary); - background: rgba(0, 0, 255, 0.03); +/* Drop-Zonen für horizontale Layouts (zwischen Spalten) */ +.drop-zone-horizontal { + width: 8px; /* Dünne vertikale Linie für horizontale Anordnung */ + height: auto; /* ✅ Höhe passt sich dem Inhalt an */ + align-self: center; /* ✅ Zentriert die Drop-Zone vertikal */ + background: rgba(0, 0, 255, 0.3); + cursor: pointer; +} + +/* Drop-Zonen für vertikale Layouts (zwischen Reihen) */ +.drop-zone-vertical { + height: 6px; /* Dünne horizontale Linie für vertikale Anordnung */ + width: 100%; + background: rgba(0, 0, 255, 0.3); + margin: 2px 0; /* ✅ Kleinere Abstände */ + cursor: pointer; } diff --git a/src/layouts/FormDesignerLayout.vue b/src/layouts/FormDesignerLayout.vue index 2f9ed08..826e363 100644 --- a/src/layouts/FormDesignerLayout.vue +++ b/src/layouts/FormDesignerLayout.vue @@ -21,7 +21,7 @@