From 2fb5e2f03be32fdadd439f6ed8ac672f68261c19 Mon Sep 17 00:00:00 2001 From: Nicolai Horlacher Date: Mon, 20 May 2024 19:32:29 +0200 Subject: [PATCH] extended SortableJS events with data attribute --- src/types/index.ts | 11 +++++++- src/useDraggable.ts | 62 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/types/index.ts b/src/types/index.ts index 43008f57..f5a56698 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,5 +1,14 @@ import type { Ref } from 'vue' -export { type Options, type SortableEvent } from 'sortablejs' +import type { SortableEvent, MoveEvent } from 'sortablejs' +export { type Options, type SortableEvent, type MoveEvent } from 'sortablejs' + +export interface SortableDataEvent extends SortableEvent { + itemData?: any +} + +export interface MoveDataEvent extends MoveEvent { + draggedData?: any +} export type RefOrValue = T | Ref export type RefOrElement = diff --git a/src/useDraggable.ts b/src/useDraggable.ts index b04307c2..0b4c9099 100644 --- a/src/useDraggable.ts +++ b/src/useDraggable.ts @@ -9,7 +9,13 @@ import { watch, type Ref } from 'vue-demi' -import type { Fn, RefOrElement, RefOrValue } from './types' +import { + Fn, + MoveDataEvent, + RefOrElement, + RefOrValue, + SortableDataEvent +} from './types' import { error } from './utils/log' @@ -51,10 +57,24 @@ function tryOnMounted(fn: Fn) { else nextTick(fn) } -const CLONE_ELEMENT_KEY = Symbol('cloneElement') +const DATA_ELEMENT_KEY = Symbol('dataElement') + +const sortableEventKeys = [ + "onStart", + "onEnd", + "onAdd", + "onClone", + "onChoose", + "onUnchoose", + "onUpdate", + "onSort", + "onRemove", + "onFilter", + "onChange" +] as const; interface DraggableEvent extends SortableEvent { - item: HTMLElement & { [CLONE_ELEMENT_KEY]: any } + item: HTMLElement & { [DATA_ELEMENT_KEY]: any } } type SortableMethod = 'closest' | 'save' | 'toArray' | 'destroy' | 'option' @@ -69,7 +89,15 @@ export interface UseDraggableReturn extends Pick { resume: () => void } -export interface UseDraggableOptions extends Options { +type MoveDataFunction = (evt: MoveDataEvent, originalEvent: Event) => boolean | -1 | 1 | void + +type ExtendedOptions = Options & { + [key in typeof sortableEventKeys[number]]?: (evt: SortableDataEvent) => void +} & { + onMove?: MoveDataFunction; +} + +export interface UseDraggableOptions extends ExtendedOptions { clone?: (element: T) => T immediate?: boolean customUpdate?: (event: SortableEvent) => void @@ -130,8 +158,8 @@ export function useDraggable(...args: any[]): UseDraggableReturn { * Element dragging started * @param {DraggableEvent} evt - DraggableEvent */ - function onStart(evt: DraggableEvent) { - evt.item[CLONE_ELEMENT_KEY] = clone(unref(unref(list)?.[evt.oldIndex!])) + function onChoose(evt: DraggableEvent) { + evt.item[DATA_ELEMENT_KEY] = clone(unref(unref(list)?.[evt.oldIndex!])) } /** @@ -139,7 +167,7 @@ export function useDraggable(...args: any[]): UseDraggableReturn { * @param {DraggableEvent} evt */ function onAdd(evt: DraggableEvent) { - const element = evt.item[CLONE_ELEMENT_KEY] + const element = evt.item[DATA_ELEMENT_KEY] if (isUndefined(element)) return removeNode(evt.item) if (isRef(list)) { @@ -193,8 +221,8 @@ export function useDraggable(...args: any[]): UseDraggableReturn { * preset options */ const presetOptions: UseDraggableOptions = { + onChoose, onUpdate, - onStart, onAdd, onRemove } @@ -216,12 +244,30 @@ export function useDraggable(...args: any[]): UseDraggableReturn { function mergeOptions() { // eslint-disable-next-line const { immediate, clone, ...restOptions } = unref(options) ?? {} + sortableEventKeys.forEach(key => { + if (restOptions[key]) { + restOptions[key] = extendSortableEvent(restOptions[key]) + } + }) + if (restOptions.onMove) { + restOptions.onMove = extendMoveEvent(restOptions.onMove) + } return mergeOptionsEvents( list === null ? {} : presetOptions, restOptions ) as Options } + function extendSortableEvent(fn: (evt: SortableDataEvent) => void) { + return (evt: DraggableEvent) => + fn({ ...evt, itemData: evt.item[DATA_ELEMENT_KEY] }) + } + + function extendMoveEvent(fn: MoveDataFunction) { + return (moveEvent: any, originalEvent: Event) => + fn({ ...moveEvent, draggedData: moveEvent.dragged[DATA_ELEMENT_KEY] }, originalEvent) + } + const start = (target?: HTMLElement) => { target = getTarget(target) if (instance) methods.destroy()