component DragAndDrop { outputs { dragStart(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) dragEnd(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) dragEnter(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) dragLeave(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) drop(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) change(payload: { value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) } props { size: string = "default" color: string = "primary" title: string = "Drag And Drop" description: string = "" items: unknown[] = [] variant: string = "default" class: string = "" } state orderedItems = items state draggedIndex: number = -1 functions { client function startDrag(index, sourceEvent) { draggedIndex = index; sourceEvent.dataTransfer.setData("text/plain", String(index)); output.dragStart({ index: index }) } client function enter(sourceEvent) { sourceEvent.preventDefault(); output.dragEnter({ sourceEvent: sourceEvent }) } client function leave(sourceEvent) { output.dragLeave({ sourceEvent: sourceEvent }) } client function finish(sourceEvent) { draggedIndex = -1; output.dragEnd({ sourceEvent: sourceEvent }) } client function move(from, to, sourceEvent, next, moved) { if (from < 0 || to < 0 || to >= orderedItems.length || from === to) { return } next = orderedItems.slice(); moved = next.splice(from, 1)[0]; next.splice(to, 0, moved); orderedItems = next output.change({ value: orderedItems, sourceEvent: sourceEvent }) } client function dropAt(index, sourceEvent) { sourceEvent.preventDefault(); move(draggedIndex, index, sourceEvent); draggedIndex = -1; output.drop({ index: index, items: orderedItems }) } } view {
{#if title}{title}{/if}{#if description}

{description}

{/if}
    {#each orderedItems as item, index}
  1. {item.label}
  2. {/each}
} style { .wrn-sortable { display:grid; gap:.75rem; color:var(--wrn-color-text); } .wrn-sortable p { margin:0; color:var(--wrn-color-muted); font-size:.875rem; } .wrn-sortable ol { display:grid; gap:.5rem; list-style:none; margin:0; padding:0; } .wrn-sortable li { display:flex; align-items:center; gap:.6rem; padding:.65rem; background:var(--wrn-color-surface); border:1px solid var(--wrn-color-border); border-radius:var(--wrn-radius-sm); font-size:.875rem; cursor:grab; } .wrn-sortable li > span:nth-child(2) { flex:1; } .wrn-sortable li > span:first-child { width:1rem; height:1rem; color:var(--wrn-color-muted); } .wrn-sortable button { border:1px solid var(--wrn-color-border); background:transparent; color:inherit; border-radius:4px; width:1.75rem; height:1.75rem; cursor:pointer; } .wrn-sortable button:disabled { opacity:.3; } } }