Enhance Form Builder with New Component Insertion and Styling Updates
- Added functionality to insert components at a specific index in the form builder, allowing for more flexible component arrangement. - Updated the form store to support the new insertion method, ensuring components can be added dynamically at designated positions. - Modified CSS styles for form components, including adjustments to disabled states and ghost component appearance for improved user experience. - Refined drag-and-drop behavior by removing animation for immediate feedback during reordering, enhancing usability. - Introduced a new background color for disabled states to maintain visual consistency across the form builder.
This commit is contained in:
parent
577128a799
commit
b29c035370
@ -10,6 +10,7 @@ html[data-theme="default"] {
|
||||
--border-color: 228, 228, 231;
|
||||
--bg-1: 243, 244, 246;
|
||||
--bg-2: 255, 255, 255;
|
||||
--bg-disabled: 250, 250, 250;
|
||||
--scroll-color: 170, 170, 170;
|
||||
--scroll-hover-color: 155, 155, 155;
|
||||
--fk-border-color: 228, 228, 231;
|
||||
|
@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.formkit-outer-global {
|
||||
@apply mb-4 text-[rgb(var(--text-color))] formkit-disabled:opacity-50;
|
||||
@apply mb-4 text-[rgb(var(--text-color))];
|
||||
}
|
||||
|
||||
.formkit-help-global {
|
||||
|
@ -26,9 +26,9 @@
|
||||
bg-[rgb(var(--bg-2))]
|
||||
placeholder-[rgb(var(--fk-placeholder-color))]
|
||||
focus:outline-none
|
||||
disabled:bg-[rgb(var(--bg-1))]
|
||||
disabled:border-[rgb(var(--bg-1))]
|
||||
disabled:placeholder-[rgb(var(--bg-1))];
|
||||
disabled:bg-[rgb(var(--bg-disabled))]
|
||||
disabled:border-[rgb(var(--bg-disabled))]
|
||||
disabled:placeholder-[rgb(var(--bg-disabled))];
|
||||
}
|
||||
|
||||
.formkit-prefix-text {
|
||||
|
@ -29,13 +29,14 @@
|
||||
item-key="id"
|
||||
handle=".drag-handle"
|
||||
ghost-class="ghost"
|
||||
animation="300"
|
||||
animation="0"
|
||||
class="draggable-container"
|
||||
@end="onDragEnd"
|
||||
@start="onDragStart"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<div
|
||||
class="form-component relative border rounded-md overflow-hidden transition-all duration-200 cursor-pointer"
|
||||
class="form-component relative border rounded-md overflow-hidden cursor-pointer"
|
||||
:class="{
|
||||
'ring-2 ring-blue-500 bg-blue-50 border-blue-300 shadow-lg': selectedComponentId === element.id,
|
||||
'bg-white border-gray-200 hover:border-blue-300 hover:shadow-md hover:bg-blue-25': selectedComponentId !== element.id
|
||||
@ -114,7 +115,7 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['select-component', 'move-component', 'delete-component', 'update-component', 'optimize-layout', 'select-nested-component']);
|
||||
const emit = defineEmits(['select-component', 'move-component', 'delete-component', 'update-component', 'optimize-layout', 'select-nested-component', 'insert-component-at-index']);
|
||||
|
||||
const selectedComponentId = ref(null);
|
||||
const resizeMode = ref(false);
|
||||
@ -273,6 +274,11 @@ const stopResize = () => {
|
||||
document.removeEventListener('mouseup', stopResize);
|
||||
};
|
||||
|
||||
// Handle drag start from internal reordering
|
||||
const onDragStart = (event) => {
|
||||
// Internal reordering
|
||||
};
|
||||
|
||||
// Handle drag end event for reordering
|
||||
const onDragEnd = (event) => {
|
||||
if (event.oldIndex !== event.newIndex) {
|
||||
@ -294,7 +300,7 @@ onUnmounted(() => {
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
grid-auto-flow: row dense; /* This enables automatic filling of gaps */
|
||||
grid-auto-flow: row; /* Changed: Remove 'dense' to preserve intentional spacing */
|
||||
column-gap: 16px;
|
||||
row-gap: 16px;
|
||||
width: 100%;
|
||||
@ -307,20 +313,23 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.ghost {
|
||||
opacity: 0.5;
|
||||
background: #e0f2fe;
|
||||
border: 1px dashed #60a5fa;
|
||||
opacity: 0.3;
|
||||
background: #dbeafe;
|
||||
border: 2px dashed #3b82f6;
|
||||
width: 100% !important;
|
||||
grid-column: span 12 !important;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.form-component {
|
||||
transition: all 0.2s ease;
|
||||
/* Removed transition for immediate snapping */
|
||||
grid-column: span 12; /* Default to full width */
|
||||
width: 100% !important; /* Force the width within the grid cell */
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.form-component:hover .component-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
@ -330,6 +330,7 @@
|
||||
@delete-component="handleDeleteComponent"
|
||||
@update-component="handleUpdateComponent"
|
||||
@optimize-layout="handleOptimizeLayout"
|
||||
@insert-component-at-index="handleInsertComponentAtIndex"
|
||||
/>
|
||||
|
||||
<!-- Instruction Overlay when no component is selected -->
|
||||
@ -2727,6 +2728,11 @@ const handleOptimizeLayout = () => {
|
||||
formStore.optimizeGridLayout();
|
||||
};
|
||||
|
||||
// Handle inserting component at specific index (for drop zones)
|
||||
const handleInsertComponentAtIndex = ({ component, index }) => {
|
||||
formStore.insertComponentAtIndex(component, index);
|
||||
};
|
||||
|
||||
// Add the new handler function
|
||||
const handleDragEnter = (event) => {
|
||||
// Prevent default to allow drop
|
||||
|
@ -425,7 +425,7 @@ export const useFormBuilderStore = defineStore('formBuilder', {
|
||||
},
|
||||
|
||||
// Find optimal placement for a new component in the grid
|
||||
findOptimalGridPlacement() {
|
||||
findOptimalGridPlacement(respectDesignSpacing = true) {
|
||||
if (this.formComponents.length === 0) {
|
||||
// First component - full width
|
||||
return {
|
||||
@ -435,6 +435,16 @@ export const useFormBuilderStore = defineStore('formBuilder', {
|
||||
};
|
||||
}
|
||||
|
||||
// If respecting design spacing, always create a new row (don't auto-fill gaps)
|
||||
if (respectDesignSpacing) {
|
||||
return {
|
||||
gridColumn: 'span 12',
|
||||
rowIndex: this.formComponents.length,
|
||||
width: '100%'
|
||||
};
|
||||
}
|
||||
|
||||
// Legacy auto-fill behavior (kept for compatibility)
|
||||
// Group components by their implicit row
|
||||
const rows = [];
|
||||
let currentRowY = 0;
|
||||
@ -505,6 +515,62 @@ export const useFormBuilderStore = defineStore('formBuilder', {
|
||||
}
|
||||
},
|
||||
|
||||
// Insert component at a specific index (for drop zones)
|
||||
insertComponentAtIndex(component, index) {
|
||||
console.log('FormStore: Inserting component at index', index, component.type);
|
||||
|
||||
// Store the state before the change for history
|
||||
const beforeComponents = [...this.formComponents];
|
||||
|
||||
const newComponentId = uuidv4();
|
||||
|
||||
try {
|
||||
// Create a deep copy of the default props to avoid reference issues
|
||||
const defaultProps = component.defaultProps ? JSON.parse(JSON.stringify(component.defaultProps)) : {};
|
||||
|
||||
// Set default grid properties - respect design spacing by using full width
|
||||
defaultProps.width = defaultProps.width || '100%';
|
||||
defaultProps.gridColumn = defaultProps.gridColumn || 'span 12';
|
||||
|
||||
// Generate a default name based on component type if not provided
|
||||
if (!defaultProps.name) {
|
||||
defaultProps.name = `${component.type}_${this.formComponents.length + 1}`;
|
||||
}
|
||||
|
||||
// Generate a default label based on component name if not provided
|
||||
if (!defaultProps.label && !['heading', 'paragraph', 'divider'].includes(component.type)) {
|
||||
defaultProps.label = `${component.name} ${this.formComponents.length + 1}`;
|
||||
}
|
||||
|
||||
// Create the new component object
|
||||
const newComponent = {
|
||||
id: newComponentId,
|
||||
type: component.type,
|
||||
name: component.name,
|
||||
icon: component.icon,
|
||||
category: component.category,
|
||||
props: defaultProps
|
||||
};
|
||||
|
||||
// Insert the component at the specified index
|
||||
this.formComponents.splice(index, 0, newComponent);
|
||||
|
||||
// Select the new component
|
||||
this.selectedComponentId = newComponentId;
|
||||
|
||||
// Mark as having unsaved changes
|
||||
this.hasUnsavedChanges = true;
|
||||
|
||||
// Record history
|
||||
this.recordAction('Add component', beforeComponents, [...this.formComponents]);
|
||||
|
||||
console.log('FormStore: Component inserted at index', index, 'Total components:', this.formComponents.length);
|
||||
} catch (error) {
|
||||
console.error('Error inserting component at index:', error);
|
||||
console.error('Problematic component:', component);
|
||||
}
|
||||
},
|
||||
|
||||
selectComponent(id) {
|
||||
// Don't record history for selection changes
|
||||
this.selectedComponentId = id;
|
||||
|
Loading…
x
Reference in New Issue
Block a user