diff --git a/web/src/lib/actions/drag-and-drop.ts b/web/src/lib/actions/drag-and-drop.ts new file mode 100644 index 0000000000..be53bf03be --- /dev/null +++ b/web/src/lib/actions/drag-and-drop.ts @@ -0,0 +1,89 @@ +export interface DragAndDropOptions { + index: number; + onDragStart?: (index: number) => void; + onDragEnter?: (index: number) => void; + onDrop?: (e: DragEvent, index: number) => void; + onDragEnd?: () => void; + isDragging?: boolean; + isDragOver?: boolean; +} + +export function dragAndDrop(node: HTMLElement, options: DragAndDropOptions) { + let { index, onDragStart, onDragEnter, onDrop, onDragEnd, isDragging, isDragOver } = options; + + const handleDragStart = () => { + onDragStart?.(index); + }; + + const handleDragEnter = () => { + onDragEnter?.(index); + }; + + const handleDragOver = (e: DragEvent) => { + e.preventDefault(); + }; + + const handleDrop = (e: DragEvent) => { + onDrop?.(e, index); + }; + + const handleDragEnd = () => { + onDragEnd?.(); + }; + + node.setAttribute('draggable', 'true'); + node.setAttribute('role', 'button'); + node.setAttribute('tabindex', '0'); + + node.addEventListener('dragstart', handleDragStart); + node.addEventListener('dragenter', handleDragEnter); + node.addEventListener('dragover', handleDragOver); + node.addEventListener('drop', handleDrop); + node.addEventListener('dragend', handleDragEnd); + + // Update classes based on drag state + const updateClasses = (dragging: boolean, dragOver: boolean) => { + // Remove all drag-related classes first + node.classList.remove('opacity-50', 'border-gray-400', 'dark:border-gray-500', 'border-solid'); + + // Add back only the active ones + if (dragging) { + node.classList.add('opacity-50'); + } + + if (dragOver) { + node.classList.add('border-gray-400', 'dark:border-gray-500', 'border-solid'); + node.classList.remove('border-transparent'); + } else { + node.classList.add('border-transparent'); + } + }; + + updateClasses(isDragging || false, isDragOver || false); + + return { + update(newOptions: DragAndDropOptions) { + index = newOptions.index; + onDragStart = newOptions.onDragStart; + onDragEnter = newOptions.onDragEnter; + onDrop = newOptions.onDrop; + onDragEnd = newOptions.onDragEnd; + + const newIsDragging = newOptions.isDragging || false; + const newIsDragOver = newOptions.isDragOver || false; + + if (newIsDragging !== isDragging || newIsDragOver !== isDragOver) { + isDragging = newIsDragging; + isDragOver = newIsDragOver; + updateClasses(isDragging, isDragOver); + } + }, + destroy() { + node.removeEventListener('dragstart', handleDragStart); + node.removeEventListener('dragenter', handleDragEnter); + node.removeEventListener('dragover', handleDragOver); + node.removeEventListener('drop', handleDrop); + node.removeEventListener('dragend', handleDragEnd); + }, + }; +} diff --git a/web/src/lib/components/workflow/schema-form/SchemaFormFields.svelte b/web/src/lib/components/workflow/schema-form/SchemaFormFields.svelte index 7d7c6d480e..9be98dc72f 100644 --- a/web/src/lib/components/workflow/schema-form/SchemaFormFields.svelte +++ b/web/src/lib/components/workflow/schema-form/SchemaFormFields.svelte @@ -241,7 +241,7 @@ {@const label = component.title || component.label || key}
{trigger.name}
++ {index + 1}. {filter.title} +
+ {/each} ++ {index + 1}. {action.title} +
+ {/each} ++ {index + 1} +
++ {index + 1} +
+