gristlabs_grist-core/app/client/ui/mouseDrag.ts

54 lines
1.9 KiB
TypeScript
Raw Normal View History

/**
* 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: HTMLElement) => 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); };
}
// Same as mouseDragElem, but listens for mousedown on descendants of elem that match selector.
export function mouseDragMatchElem(elem: HTMLElement, selector: string, onStart: MouseDragStart): IDisposable {
return dom.onMatchElem(elem, selector, 'mousedown',
(ev, el) => _startDragging(ev as MouseEvent, el as HTMLElement, onStart));
}
function _startDragging(startEv: MouseEvent, elem: HTMLElement, 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);
}
}
}