UNPKG

@mskcc/carbon-react

Version:

Carbon react components for the MSKCC DSM

136 lines (125 loc) 4.11 kB
/** * MSKCC 2021, 2024 */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var React = require('react'); /** * @param {React.RefObject<HTMLElement>} ref * * @param {{ * onPress?(state: { longPress: boolean }): void, * onPressIn?(): void, * onPressOut?(): void, * onLongPress?(): void, * delayLongPressMs?: number, * }} options */ function usePressable(ref) { let { onPress, onPressIn, onPressOut, onLongPress, delayLongPressMs = 500 } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; const savedOnPress = React.useRef(onPress); const savedOnPressIn = React.useRef(onPressIn); const savedOnPressOut = React.useRef(onPressOut); const savedOnLongPress = React.useRef(onLongPress); const [pendingLongPress, setPendingLongPress] = React.useState(false); const [longPress, setLongPress] = React.useState(false); const state = React.useRef({ longPress: false }); React.useEffect(() => { savedOnPress.current = onPress; }, [onPress]); React.useEffect(() => { savedOnPressIn.current = onPressIn; }, [onPressIn]); React.useEffect(() => { savedOnPressOut.current = onPressOut; }, [onPressOut]); React.useEffect(() => { savedOnLongPress.current = onLongPress; }, [onLongPress]); React.useEffect(() => { const { current: element } = ref; // Fired when a pointer becomes active buttons state. function onPointerDown(event) { setPendingLongPress(true); savedOnPressIn.current?.(); event.preventDefault(); } // Fired when a pointer is no longer active buttons state. function onPointerUp() { setPendingLongPress(false); setLongPress(false); savedOnPressOut.current?.(state.current); } // A browser fires this event if it concludes the pointer // will no longer be able to generate events (for example // the related device is deactivated). function onPointerCancel() { setPendingLongPress(false); setLongPress(false); savedOnPressOut.current?.(); state.current.longPress = false; } // Fired when a pointer is moved out of the hit test // boundaries of an element. For pen devices, this event // is fired when the stylus leaves the hover range // detectable by the digitizer. function onPointerLeave() { setPendingLongPress(false); setLongPress(false); savedOnPressOut.current?.(); state.current.longPress = false; } function onClick() { setLongPress(false); setPendingLongPress(false); savedOnPress.current?.(state.current); state.current.longPress = false; } // Certain devices treat long press events as context menu triggers function onContextMenu(event) { event.preventDefault(); } element.addEventListener('pointerdown', onPointerDown); element.addEventListener('pointerup', onPointerUp); element.addEventListener('pointercancel', onPointerCancel); element.addEventListener('pointerleave', onPointerLeave); element.addEventListener('click', onClick); element.addEventListener('contextmenu', onContextMenu); return () => { element.removeEventListener('pointerdown', onPointerDown); element.removeEventListener('pointerup', onPointerUp); element.removeEventListener('pointercancel', onPointerCancel); element.removeEventListener('pointerleave', onPointerLeave); element.removeEventListener('click', onClick); element.removeEventListener('contextmenu', onContextMenu); }; }, [ref]); React.useEffect(() => { if (pendingLongPress) { const timeoutId = setTimeout(() => { setPendingLongPress(false); setLongPress(true); }, delayLongPressMs); return () => { clearTimeout(timeoutId); }; } }, [pendingLongPress, delayLongPressMs]); React.useEffect(() => { if (longPress) { state.current.longPress = true; return savedOnLongPress.current?.(); } }, [longPress]); } exports.usePressable = usePressable;