import {dom, EventCB} from 'grainjs'; const DOUBLE_TAP_INTERVAL_MS = 500; /** * Helper to handle 'dblclick' events on either browser or mobile. * * This is equivalent to a 'dblclick' handler when touch events are not supported. When they are, * the callback will be called on second touch within a short time of a first one. (In that case, * preventDefault() prevents a 'dblclick' event from being emulated.) * * Background: though mobile browsers we care about already generate 'click' and 'dblclick' events * in response to touch events, it doesn't seem to be treated as a direct user interaction. E.g. * double-click to edit a cell should focus the editor and open the mobile keyboard, but a * JS-issued focus() call only works when triggered by a direct user interaction, and synthesized * dblclick doesn't seem to do that. * * Helpful links on emulated (synthesized) events: * - https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Supporting_both_TouchEvent_and_MouseEvent * - https://github.com/w3c/pointerevents/issues/171 */ export function onDblClickMatchElem(elem: EventTarget, selector: string, callback: EventCB): void { dom.onMatchElem(elem, selector, 'dblclick', (ev, _elem) => { callback(ev, _elem); }); let lastTapTime = 0; dom.onMatchElem(elem, selector, 'touchend', (ev, _elem) => { const currentTime = Date.now(); const tapLength = currentTime - lastTapTime; lastTapTime = currentTime; if (tapLength < DOUBLE_TAP_INTERVAL_MS && tapLength > 0) { ev.preventDefault(); callback(ev, _elem); } }); }