// Copyright (c) Meta Platforms, Inc. and affiliates. 'use client'; /** * @file useTouchTrigger.ts * @input Touch trigger mode, layer open state, trigger ref, show/hide callbacks * @output Exports useTouchTrigger hook, isActionTrigger, LayerTouchTrigger type * @position Layer hook; shared touch behavior for useTooltip and useHoverCard * * SYNC: When modified, update: * - /packages/core/src/Layer/index.ts * * Hover is the one trigger a touch screen cannot express. A tap synthesizes * `mouseenter`, so an untreated hover layer either opens on every tap and * lingers with nothing to close it, or swallows the tap the user aimed at the * control underneath. * * What the trigger DOES decides which of those the tap deserves. A trigger * that performs an action — a button, a link, a form control — keeps its tap: * the layer stays shut, because the tap already has somewhere to go and a hint * about a control the user just operated is noise. A trigger that performs no * action — an info icon, an abbreviation, a truncated label — has nothing to * lose, so the tap opens the layer and the next tap outside dismisses it. That * is `auto`; `tap` and `none` state the choice outright, which is what an * icon-button whose only job is to reveal the layer needs. */ import { useCallback, useEffect, useRef, type RefObject } from 'react'; import { getInteractionModality, useInteractionModalityTracking } from "../utils/interactionModality.js"; /** * How a hover layer behaves on a touch pointer. * * - `auto`: tap-to-open, unless the trigger performs an action of its own * - `tap`: always tap-to-open, even on a trigger that performs an action * - `none`: never open on touch */ export type LayerTouchTrigger = 'auto' | 'tap' | 'none'; /** * Pointer types whose *press* is a tap rather than a click. * * A pen belongs here but not in the arrival path: in detection range it hovers * — firing `pointerenter`/`pointermove` with no contact, exactly as a mouse * does, on a device where `(hover: hover)` matches — and only becomes a tap * once it lands. See `handlePointerEnter`. */ const TOUCH_POINTER_TYPES = new Set(['touch', 'pen']); /** * ARIA roles that make an element do something when activated. An explicit * role wins over the tag: `