|
1 | 1 | <script lang="ts"> |
2 | 2 | import Sortable from 'sortablejs'; |
3 | 3 |
|
4 | | - import { createEventDispatcher, getContext, onMount } from 'svelte'; |
| 4 | + import { createEventDispatcher, getContext, onDestroy, onMount, tick } from 'svelte'; |
5 | 5 | const i18n = getContext('i18n'); |
6 | 6 |
|
7 | 7 | import { models } from '$lib/stores'; |
|
14 | 14 | let modelListElement = null; |
15 | 15 |
|
16 | 16 | const positionChangeHandler = () => { |
17 | | - const modelList = Array.from(modelListElement.children).map((child) => |
| 17 | + // Read new order from DOM |
| 18 | + const newOrder = Array.from(modelListElement.children).map((child) => |
18 | 19 | child.id.replace('model-item-', '') |
19 | 20 | ); |
20 | 21 |
|
21 | | - modelIds = modelList; |
22 | | - }; |
| 22 | + // Revert SortableJS DOM manipulation so Svelte stays in control of the DOM |
| 23 | + if (sortable) { |
| 24 | + sortable.sort( |
| 25 | + modelIds.map((id) => `model-item-${id}`), |
| 26 | + true |
| 27 | + ); |
| 28 | + } |
23 | 29 |
|
24 | | - $: if (modelIds) { |
25 | | - init(); |
26 | | - } |
| 30 | + // Update reactive data — Svelte will re-render with the new order |
| 31 | + modelIds = newOrder; |
| 32 | + }; |
27 | 33 |
|
28 | | - const init = () => { |
| 34 | + const initSortable = () => { |
29 | 35 | if (sortable) { |
30 | 36 | sortable.destroy(); |
| 37 | + sortable = null; |
31 | 38 | } |
32 | 39 |
|
33 | 40 | if (modelListElement) { |
|
40 | 47 | }); |
41 | 48 | } |
42 | 49 | }; |
| 50 | +
|
| 51 | + onMount(() => { |
| 52 | + // Wait a tick for the {#if} block to render and bind modelListElement |
| 53 | + tick().then(() => { |
| 54 | + initSortable(); |
| 55 | + }); |
| 56 | + }); |
| 57 | +
|
| 58 | + onDestroy(() => { |
| 59 | + if (sortable) { |
| 60 | + sortable.destroy(); |
| 61 | + } |
| 62 | + }); |
43 | 63 | </script> |
44 | 64 |
|
45 | 65 | {#if modelIds.length > 0} |
46 | 66 | <div class="flex flex-col -translate-x-1" bind:this={modelListElement}> |
47 | | - {#each modelIds as modelId, modelIdx (`${modelId}-${modelIdx}`)} |
| 67 | + {#each modelIds as modelId (modelId)} |
48 | 68 | <div class=" flex gap-2 w-full justify-between items-center" id="model-item-{modelId}"> |
49 | 69 | <Tooltip content={modelId} placement="top-start"> |
50 | 70 | <div class="flex items-center gap-1"> |
|
0 commit comments