import { Throttler } from '@ephox/katamari'; import { type Bindable, Event, Events } from '@ephox/porkbun'; import type { EventArgs, SugarElement } from '@ephox/sugar'; import { DragApi, type DragMode, type DragMutation } from '../api/DragApis'; import type { BlockerOptions } from '../detect/Blocker'; import { Movement } from '../detect/Movement'; interface DragActionEvents { readonly registry: { start: Bindable<{}>; stop: Bindable<{}>; }; readonly trigger: { start: () => void; stop: () => void; }; } export interface Dragging { readonly element: () => SugarElement; readonly go: (parent: SugarElement) => void; readonly on: () => void; readonly off: () => void; readonly isActive: () => boolean; readonly destroy: () => void; readonly events: DragActionEvents['registry']; } const setup = (mutation: DragMutation, mode: DragMode, settings: Partial): Dragging => { let active = false; const events: DragActionEvents = Events.create({ start: Event([]), stop: Event([]) }); const movement = Movement(); const drop = () => { sink.stop(); if (movement.isOn()) { movement.off(); events.trigger.stop(); } }; const throttledDrop = Throttler.last(drop, 200); const go = (parent: SugarElement) => { sink.start(parent); movement.on(); events.trigger.start(); }; const mousemove = (event: EventArgs) => { throttledDrop.cancel(); movement.onEvent(event, mode); }; movement.events.move.bind((event) => { mode.mutate(mutation, event.info); }); const on = () => { active = true; }; const off = () => { active = false; // acivate some events here? }; const isActive = () => active; const runIfActive = any> (f: F) => { return (...args: Parameters) => { if (active) { f.apply(null, args); } }; }; const sink = mode.sink(DragApi({ // ASSUMPTION: runIfActive is not needed for mousedown. This is pretty much a safety measure for // inconsistent situations so that we don't block input. forceDrop: drop, drop: runIfActive(drop), move: runIfActive(mousemove), delayDrop: runIfActive(throttledDrop.throttle) }), settings); const destroy = () => { sink.destroy(); }; return { element: sink.element, go, on, off, isActive, destroy, events: events.registry }; }; export { setup };