Breaking changes между версиями

Shopify Draggable — это высокоэффективная библиотека для реализации перетаскивания элементов на веб-странице. При обновлении версии важно понимать breaking changes, которые могут повлиять на существующий код. Эти изменения касаются API, событий, структуры объектов и способов инициализации.


1. Изменения в инициализации Draggable

В версиях до 1.x инициализация выполнялась следующим образом:

const draggable = new Draggable(document.querySelectorAll('.list'), {
  draggable: '.item',
});

Начиная с версии 1.x структура опций изменилась:

  • Ключ draggable остался, но его использование теперь строго типизировано: требуется строго указывать CSS-селектор.
  • Добавился ключ handle, который позволяет ограничивать зону захвата элемента для перетаскивания. Ранее это можно было делать вручную через события.
const draggable = new Draggable(document.querySelectorAll('.list'), {
  draggable: '.item',
  handle: '.handle'
});

Если в коде старой версии handle не использовался, поведение перетаскивания элементов без хэндла может измениться.


2. События и их обработчики

В старых версиях Draggable события привязывались через методы .on() с универсальным именем события, например:

draggable.on('drag:start', (evt) => {
  console.log(evt.source);
});

В новой версии произошли следующие изменения:

  • События теперь разделены по пространствам имен: drag, sort, swap, mirror. Например: sortable:stop вместо drag:stop.

  • Объект события изменил структуру:

    • evt.sourceevt.data.source
    • evt.oldIndexevt.data.oldIndex
    • evt.newIndexevt.data.newIndex

Пример новой версии:

draggable.on('sortable:stop', (evt) => {
  console.log(evt.data.oldIndex, evt.data.newIndex);
});

Важно: старый код, использующий прямой доступ к evt.oldIndex, перестанет работать.


3. Работа с mirror (зеркальным) элементом

Ранее mirror элемент создавался автоматически при начале перетаскивания и был доступен через evt.source.

В версии 1.x:

  • Mirror создается с новым объектом Mirror, который хранит отдельные стили и размеры.
  • Для доступа используется draggable.getMirror() или через событие mirror:created.
  • Стили по умолчанию изменились: теперь mirror получает position: fixed вместо absolute.

Пример использования:

draggable.on('mirror:created', (evt) => {
  const mirrorElement = evt.data.mirror;
  mirrorElement.style.backgroundColor = 'rgba(0,0,0,0.1)';
});

Если старый код полагался на position: absolute, визуальное поведение будет отличаться.


4. Сортировка и swap

В старых версиях операции сортировки выполнялись автоматически. Новый API ввел разделение ролей:

  • Sortable — для элементов, которые можно менять местами внутри контейнера.
  • Swappable — для элементов, которые могут обмениваться позициями между контейнерами.
  • Draggable — только для перетаскивания без изменения порядка.

Пример инициализации Sortable:

import { Draggable, Sortable } from '@shopify/draggable';

const containers = document.querySelectorAll('.list');
const sortable = new Sortable(containers, {
  draggable: '.item'
});

Без явного использования Sortable старые скрипты, полагающиеся на автоматическую сортировку, перестанут работать.


5. Удаление deprecated методов

  • draggable.detach() и draggable.attach() были удалены. Теперь рекомендуется полностью уничтожать экземпляр через draggable.destroy().
  • draggable.addEventListener() больше не поддерживается; используется только .on().

6. Промежуточные изменения в CSS

  • Класс draggable--dragging заменен на draggable--is-dragging.
  • Класс draggable--over для контейнера, над которым происходит перетаскивание, был переименован в draggable--is-over.
  • Эти изменения могут сломать кастомные стили.

Пример обновленного CSS:

.draggable--is-dragging {
  opacity: 0.8;
}

.draggable--is-over {
  border: 2px dashed #333;
}

7. Интеграция с библиотеками внешнего UI

Ранее можно было использовать Draggable с любыми библиотеками, изменяя DOM напрямую. В версии 1.x:

  • Mirror создается в document.body по умолчанию. Это может конфликтовать с фреймворками, использующими Shadow DOM.
  • Для Shadow DOM требуется явно указывать appendTo в настройках Draggable:
const draggable = new Draggable(container, {
  draggable: '.item',
  appendTo: shadowRoot
});

8. Рекомендации по миграции

  1. Проверить все события: заменить прямой доступ к свойствам evt.* на evt.data.*.
  2. Явно инициализировать Sortable/Swappable, если раньше использовалась автоматическая сортировка.
  3. Переписать работу с mirror элементом через mirror:created и evt.data.mirror.
  4. Обновить CSS-классы, чтобы сохранить стили перетаскивания.
  5. Проверить области захвата элементов (handle) для корректной работы.
  6. Полностью избавиться от deprecated методов .attach()/.detach().

Эти изменения являются ключевыми breaking changes между версиями Draggable и напрямую влияют на стабильность существующих решений. Правильная адаптация к новой версии требует внимательной проверки каждого блока кода, который работает с перетаскиваемыми элементами, событиями и зеркальными объектами.