Skip to content

Начало работы (V1)

Установка

Введите в своем терминале:

sh
# npm
npm i effdnd

# pnpm
pnpm add effdnd

# yarn
yarn add effdnd

Быстрый старт

Вкратце, effdnd использует data-атрибуты для установки ролей обычных HTML-элементов:

  • элемента перетаскивания item,
  • цели перетаскивания target,
  • области перетаскивания scope.

Кастомный веб-компонент effdnd-trigger инициирует перетаскивание ближайщего по дереву item. Он может быть сконфигурирован с помощью атрибутов (подробнее смотрите интерфейс ITriggerAttrs). Сам effdnd-trigger тоже может иметь роль item - то есть может инициировать собственное перемещение.

Чтобы определить effdnd-trigger просто вызовите функицю useDnD, а результаты вызова используйте для формирования необходимых data-атрибутов.

jsx
import { useDnD } from 'effdnd';

// вы можете передать параметры стиля в useDnD,
// чтобы переопределить глобальный CSS для элементов Drag-and-Drop
// (подробнее смотрите тип `TUseDnD`)
const { scope, item, target, css, observe } = useDnD();
// создает объект с атрибутом scope-эдемента
const scopeAttrs = scope('local');
// создает объект с атрибутом target-эдемента
const fisrtTargetAttrs = target('first');
// target-эдементы могут быть сгруппированы
const secondTargetAttrs = target('second', 'group');
// создает объект с атрибутом item-эдемента
const fisrtItemAttrs = item('first');
const secondItemAttrs = item('second');
// Вы даже можете переопределить стили для элементов Drag-and-Drop
const separateStyleAttrs = css({
    passiveTarget: 'border: 4px solid grey',
});

export const Component = () => {
    const ref = useRef();
    useEffect(() => {
      // вы можете подписаться на Drag-and-Drop события
      const unobserve = observe((e) => {
        // здесь идет обработка события
      }, ref.current);
      // и вы можете отписаться
      return () => unobserve();
    })
    // просто передайте объекты с атрибутами нужным элементам - и случится магия
    // не забудьте использовать `effdnd-trigger` внутри item-элементов
    return <div ref={ref} {...scopeAttrs}>
        <div className="targets-wrapper">
            <div {...fisrtTargetAttrs}>...</div>
            <div {...secondTargetAttrs} {...separateStyleAttrs}>...</div>
        </div>
        <div id="items-wrapper">
            <div {...fisrtItemAttrs}>
                <effdnd-trigger>Trigger #1</effdnd-trigger>
            </div>
            <div {...secondItemAttrs}>
                <effdnd-trigger>Trigger #2</effdnd-trigger>
            </div>
        </div>
    </div>;
}

Активные и пассивные элементы

Во время перетаскивания effdnd устанавливает динамические атрибуты, показывающие состояние элементов. Элементы могут быть

  • без состояния,
  • в пассивном состоянии,
  • в активном состоянии.

Элемент item активен во время его перетаскивания.

Элемент scope пассивен, когда внутри него претаскивается item и выполняется любое из условий

  • effdnd-trigger содержит атрибут scope со значением, равным ключу области перетасиквания (scope-элемента),
  • effdnd-trigger не содержит атрибут scope, и это ближайшая к нему область перетаскивания.

Элемент scope становится активным, если находится в пассивном состоянии и item пытается выйти за его пределы. Это состояние помогает показать пользователю доступные пределы перетаскивания.

Элемент target пассивен, когда он находится внутри scope с активным или пассивным состоянием и выполняется любое из условий

  • effdnd-trigger содержит атрибут target со значением равным группе target-элемента,
  • effdnd-trigger не содержит атрибут target (все элементы target подходят).

Элемент target становится активным, если находится в пассивном состоянии и item перетаскивается над ним.

useDnD

Функция принимает настройки перехода в качестве первого аргумента и пользовательские стили в качестве второго. Она возвращает функции для создания data-атрибутов и прослушивания событий:

ts
type TEventDetail = {
    type: TEventType;
    refs: TRefs;
    keys: TKeys;
    event: MouseEvent | TouchEvent;
};

interface TDnDEvent extends CustomEvent {
    detail: TEventDetail;
}

type TDnDCallback = (event: TDnDEvent) => void;

type TDynamicAttrs = Partial<{
    /**
     * Стили активного `item`
     */
    activeItem: string;
    /**
     * Стили пассивного `target`
     */
    passiveTarget: string;
    /**
     * Стили активного `target`
     */
    activeTarget: string;
    /**
     * Стили пассивного `scope`
     */
    passiveScope: string;
    /**
     * Стили активного `scope`
     */
    activeScope: string;
}>;

type TUseDnD = {
    (transition?: Partial<{
        /**
         * Длительность
         */
        dur: string | number;
        /**
         * Задержка
         */
        del: string | number;
        /**
         * Временная функция перехода
         */
        tf: string;
    }>, css?: TDynamicAttrs): {
        /**
         * Прослушивать события Drag-and-Drop
         * @param callback - обработчик события
         * @param element - HTML-элемент
         */
        observe: (callback: TDnDCallback, element?: HTMLElement) => () => void;
        /**
         * Перестать прослушивать события Drag-and-Drop
         * @param callback - обработчик события
         * @param element - HTML-элемент
         */
        unobserve: (callback: TDnDCallback, element?: HTMLElement) => void;
        /**
         * Использовать `item`
         * @param key - ключ
         */
        item: (key: string) => object;
        /**
         * Использовать `target`
         * @param key - ключ
         */
        target: (key: string, group?: string) => object;
        /**
         * Использовать `scope`
         * @param key - ключ
         */
        scope: (key?: string) => object;
        /**
         * Использовать кастомные стили
         */
        css: (params: TDynamicAttrs) => object;
    };
    customCount?: number;
    stylesheet?: CSSStyleSheet;
}

effdnd-trigger

Элемент может быть сконфигурирован с помощью атрибутов::

ts
interface ITriggerAttrs {
    /**
     * Ключ `scope`
     */
    scope?: string;
    /**
     * Ключ группы `target`
     */
    target?: string;
    /**
     * Дистанция срабатывания
     */
    dist?: string;
    /**
     * Событие для срабатывания
     * @description
     * По умолчанию оба события
     */
    event?: 'touch' | 'mouse';
}

Опубликовано под лицензией Apache License 2.0