@carbon/react
Version:
React components for the Carbon Design System
105 lines (103 loc) • 3.3 kB
JavaScript
/**
* 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 };