/** * Small utility to help with processing mouse-drag events. Usage is: * dom('div', mouseDrag((startEvent, elem) => ({ * onMove(moveEvent) { ... }, * onStop(stopEvent) { ... }, * }))); * * The passed-in callback is called on 'mousedown' events. It may return null to ignore the event. * Otherwise, it should return a handler for mousemove/mouseup: we will then subscribe to these * events, and clean up on mouseup. */ import {dom, DomElementMethod, IDisposable} from "grainjs"; export interface MouseDragHandler { onMove(moveEv: MouseEvent): void; onStop(endEv: MouseEvent): void; } export type MouseDragStart = (startEv: MouseEvent, elem: Element) => MouseDragHandler|null; export function mouseDragElem(elem: HTMLElement, onStart: MouseDragStart): IDisposable { // This prevents the default text-drag behavior when elem is part of a text selection. elem.style.userSelect = 'none'; return dom.onElem(elem, 'mousedown', (ev, el) => _startDragging(ev, el, onStart)); } export function mouseDrag(onStart: MouseDragStart): DomElementMethod { return (elem) => { mouseDragElem(elem, onStart); }; } function _startDragging(startEv: MouseEvent, elem: Element, onStart: MouseDragStart) { const dragHandler = onStart(startEv, elem); if (dragHandler) { const {onMove, onStop} = dragHandler; const upLis = dom.onElem(document, 'mouseup', stop, {useCapture: true}); const moveLis = dom.onElem(document, 'mousemove', onMove, {useCapture: true}); function stop(stopEv: MouseEvent) { moveLis.dispose(); upLis.dispose(); onStop(stopEv); } } }