# Dragging Component

## Описание

Перетаскивание элементов списка мышью — самостоятельная "ручка" (иконка `MoveVerticalIcon`), которая при зажатии и перемещении мыши переставляет элемент внутри переданного массива (`array`) и визуально показывает призрак перетаскиваемого элемента и плейсхолдер на месте вставки. Компонент не рендерит сам список — только ручку; сортировкой самого массива и его перерисовкой занимается вызывающий код через `onUpdate`.

Лежит прямо в `src/lib/Dragging.svelte` (без отдельной папки), у него нет парного `*Props.svelte` — это низкоуровневый примитив для чужих конструкторских панелей (например `TabsSettings`/`PeriodChartProps` используют его для сортировки вкладок/уровней), а не то, что добавляется на холст конструктора напрямую.

## Пропсы

| Название         | Тип                                          | По умолчанию | Описание                                                                                                                     |
| ---------------- | --------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| `wrapperClass`   | `string`                                      | `undefined`  | CSS-классы для обёртки ручки перетаскивания                                                                                   |
| `container`      | `HTMLDivElement`                              | `-` (обязателен) | Контейнер, внутри которого ищутся элементы списка (по атрибуту `id`, см. ниже) для определения точки вставки              |
| `array`          | `any[]`                                       | `-` (обязателен) | Массив элементов списка — мутируется на месте (`splice`) в процессе перетаскивания                                        |
| `elementsId`     | `string`                                      | `"item"`     | Префикс `id` DOM-элементов списка: ожидается `#{elementsId}-{index}` или `#{elementsId}-{index}-{containerIndex}`             |
| `elementIndex`   | `number`                                      | `-` (обязателен) | Индекс элемента, которому принадлежит эта ручка, в `array`                                                                 |
| `containerIndex` | `number`                                      | `undefined`  | Индекс контейнера — нужен, когда на странице несколько независимых списков и id элементов включают ещё и номер контейнера    |
| `onUpdate`       | `(arr: any[], index?: number \| null) => void` | `undefined`  | Вызывается дважды за одно перетаскивание: сразу после извлечения элемента (`array` без него) и по завершении (`array` с элементом на новом месте, вторым аргументом — `containerIndex`) |

## События

Компонент не генерирует DOM-события — используйте `onUpdate` для сохранения нового порядка `array`.

## Пример

Список из N строк, каждая — `<div id="item-{i}">...</div>` внутри общего контейнера; ручка перетаскивания — `UI.Dragging` с тем же `elementsId`/`elementIndex`, что и у `id` строки:

```svelte
<script>
  import * as UI from "poe-svelte-ui-lib"

  let container = $state()
  let items = $state(["Первый", "Второй", "Третий"])

  const handleUpdate = (arr) => {
    items = arr
  }
</script>

<div bind:this={container} class="flex flex-col gap-1">
  {#each items as item, index (item)}
    <div id={`item-${index}`} class="flex items-center gap-2 bg-(--field-color) p-2">
      <UI.Dragging {container} array={items} elementIndex={index} onUpdate={handleUpdate} />
      <span>{item}</span>
    </div>
  {/each}
</div>
```

## Внутренняя архитектура

### Реактивность

- `dragState` (`$state`) — служебное состояние текущего перетаскивания: перетаскиваемый элемент, экранные координаты, DOM-узлы призрака/плейсхолдера, целевой индекс вставки
- `commandItems` (`$state`) — снимок всех DOM-элементов списка на момент начала перетаскивания (`container.querySelectorAll`), используется для определения элемента под курсором
- `$effect` навешивает/снимает глобальные обработчики `mousemove`/`mouseup` на весь документ, пока идёт перетаскивание (`dragState.isDragging`)

### Директивы

- `onmousedown` на ручке — запускает перетаскивание (`startDrag`), если в массиве больше одного элемента
- Глобальные `mousemove`/`mouseup` (см. выше) — двигают призрак/плейсхолдер (`processDrag`) и завершают перестановку (`endDrag`)

### Слоты

- Компонент не использует слоты — контент фиксирован (иконка `MoveVerticalIcon`)

## Заметки

### Ограничения

- При единственном элементе в `array` (`array.length == 1`) ручка визуально приглушена (`opacity-50`) и перетаскивание не запускается
- Работает только с `MouseEvent` — нет отдельной поддержки touch/pointer-событий и клавиатурной перестановки (ручка фокусируема как `role="button"`, но `onkeydown` не обрабатывается — известное ограничение доступности)
- `container`/`elementIndex`/`array` обязательны — компонент не проверяет их наличие и упадёт при обращении к `array.length` в классе, если `array` не передан
