Начало работы (V1)
Установка
Введите в своем терминале:
# 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-атрибутов.
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-атрибутов и прослушивания событий:
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
Элемент может быть сконфигурирован с помощью атрибутов::
interface ITriggerAttrs {
/**
* Ключ `scope`
*/
scope?: string;
/**
* Ключ группы `target`
*/
target?: string;
/**
* Дистанция срабатывания
*/
dist?: string;
/**
* Событие для срабатывания
* @description
* По умолчанию оба события
*/
event?: 'touch' | 'mouse';
}