UNPKG

@carbon/react

Version:

React components for the Carbon Design System

105 lines (103 loc) 3.3 kB
/** * Copyright IBM Corp. 2016, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ import { useEffect, useRef, useState } from "react"; //#region src/components/Tabs/usePressable.ts /** * Copyright IBM Corp. 2016, 2025 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const usePressable = (ref, { onPress, onPressIn, onPressOut, onLongPress, delayLongPressMs = 500 } = {}) => { const savedOnPress = useRef(onPress); const savedOnPressIn = useRef(onPressIn); const savedOnPressOut = useRef(onPressOut); const savedOnLongPress = useRef(onLongPress); const [pendingLongPress, setPendingLongPress] = useState(false); const [longPress, setLongPress] = useState(false); const state = useRef({ longPress: false }); useEffect(() => { savedOnPress.current = onPress; }, [onPress]); useEffect(() => { savedOnPressIn.current = onPressIn; }, [onPressIn]); useEffect(() => { savedOnPressOut.current = onPressOut; }, [onPressOut]); useEffect(() => { savedOnLongPress.current = onLongPress; }, [onLongPress]); useEffect(() => { const element = ref.current; if (!element) return; const onPointerDown = (event) => { setPendingLongPress(true); savedOnPressIn.current?.(); event.preventDefault(); }; const onPointerUp = () => { setPendingLongPress(false); setLongPress(false); savedOnPressOut.current?.(state.current); }; const onPointerCancel = () => { setPendingLongPress(false); setLongPress(false); savedOnPressOut.current?.(state.current); state.current.longPress = false; }; const onPointerLeave = () => { setPendingLongPress(false); setLongPress(false); savedOnPressOut.current?.(state.current); state.current.longPress = false; }; const onClick = () => { setLongPress(false); setPendingLongPress(false); savedOnPress.current?.(state.current); state.current.longPress = false; }; const 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]); useEffect(() => { if (pendingLongPress) { const timeoutId = setTimeout(() => { setPendingLongPress(false); setLongPress(true); }, delayLongPressMs); return () => { clearTimeout(timeoutId); }; } }, [pendingLongPress, delayLongPressMs]); useEffect(() => { if (longPress) { state.current.longPress = true; return savedOnLongPress.current?.(); } }, [longPress]); }; //#endregion export { usePressable };