Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extended SortalbeJS events with data attribute #139

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
@@ -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> = T | Ref<T>
export type RefOrElement<T = HTMLElement> =
Expand Down
62 changes: 54 additions & 8 deletions src/useDraggable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -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'

Expand All @@ -69,7 +89,15 @@ export interface UseDraggableReturn extends Pick<Sortable, SortableMethod> {
resume: () => void
}

export interface UseDraggableOptions<T> 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<T> extends ExtendedOptions {
clone?: (element: T) => T
immediate?: boolean
customUpdate?: (event: SortableEvent) => void
Expand Down Expand Up @@ -130,16 +158,16 @@ export function useDraggable<T>(...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!]))
}

/**
* Element is dropped into the list from another list
* @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<any[]>(list)) {
Expand Down Expand Up @@ -193,8 +221,8 @@ export function useDraggable<T>(...args: any[]): UseDraggableReturn {
* preset options
*/
const presetOptions: UseDraggableOptions<T> = {
onChoose,
onUpdate,
onStart,
onAdd,
onRemove
}
Expand All @@ -216,12 +244,30 @@ export function useDraggable<T>(...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()
Expand Down