|
| 1 | +<script lang="ts"> |
| 2 | + import { dndzone } from 'svelte-dnd-action'; |
| 3 | + import type { Snippet } from 'svelte'; |
| 4 | +
|
| 5 | + interface Props { |
| 6 | + items: any[]; |
| 7 | + onReorder?: (reorderedItems: any[]) => void; |
| 8 | + flipDurationMs?: number; |
| 9 | + dragDisabled?: boolean; |
| 10 | + class?: string; |
| 11 | + children: Snippet<[{ item: any; index: number; originalItem: any }]>; |
| 12 | + } |
| 13 | +
|
| 14 | + let { |
| 15 | + items, |
| 16 | + onReorder = () => {}, |
| 17 | + flipDurationMs = 200, |
| 18 | + dragDisabled = false, |
| 19 | + class: className = '', |
| 20 | + children |
| 21 | + }: Props = $props(); |
| 22 | +
|
| 23 | + // Create a state array with IDs for drag-and-drop functionality |
| 24 | + let itemsWithIds: any[] = $state([]); |
| 25 | +
|
| 26 | + // Update the drag-and-drop array whenever items change |
| 27 | + $effect(() => { |
| 28 | + itemsWithIds = items.map((item, index) => ({ |
| 29 | + ...item, |
| 30 | + id: item.id || `dnd-item-${index}-${Date.now()}` // Generate unique ID with timestamp |
| 31 | + })); |
| 32 | + }); |
| 33 | +
|
| 34 | + function handleSort(e: any) { |
| 35 | + // Update the visual drag-and-drop array immediately |
| 36 | + itemsWithIds = e.detail.items; |
| 37 | + } |
| 38 | +
|
| 39 | + function handleFinalizeSort(e: any) { |
| 40 | + // Remove only temporary IDs, preserve original device IDs |
| 41 | + const reorderedItems = e.detail.items.map((item: any) => { |
| 42 | + // If this is a temporary ID we added (string starting with 'dnd-item-'), remove it |
| 43 | + if (typeof item.id === 'string' && item.id.startsWith('dnd-item-')) { |
| 44 | + const { id, ...itemWithoutTempId } = item; |
| 45 | + return itemWithoutTempId; |
| 46 | + } |
| 47 | + // Otherwise, keep the item as-is (preserving original numeric IDs) |
| 48 | + return item; |
| 49 | + }); |
| 50 | +
|
| 51 | + // Call the parent's reorder handler |
| 52 | + onReorder(reorderedItems); |
| 53 | + } |
| 54 | +
|
| 55 | +</script> |
| 56 | + |
| 57 | +<section |
| 58 | + use:dndzone={{ |
| 59 | + items: itemsWithIds, |
| 60 | + flipDurationMs, |
| 61 | + dropTargetStyle: {}, // This is to actively clear default styles |
| 62 | + dropTargetClasses: ['dragzone-outline'], // This applies custom styling |
| 63 | + dragDisabled |
| 64 | + }} |
| 65 | + onconsider={handleSort} |
| 66 | + onfinalize={handleFinalizeSort} |
| 67 | + class={className} |
| 68 | +> |
| 69 | + {#each itemsWithIds as item, index (item.id)} |
| 70 | + {@render children({ item, index, originalItem: items[index] })} |
| 71 | + {/each} |
| 72 | +</section> |
| 73 | + |
| 74 | +<style> |
| 75 | + @reference "$src/app.css"; |
| 76 | + :global(.dragzone-outline) { |
| 77 | + @apply outline-solid outline-2 outline-(--color-primary); |
| 78 | + } |
| 79 | + :global(#dnd-action-dragged-el) { |
| 80 | + @apply outline-solid outline-2 outline-current; |
| 81 | +
|
| 82 | + } |
| 83 | +</style> |
0 commit comments