Долгое нажатие — secondary action: показать контекстное меню, выделить элемент, открыть детали. Mobile-аналог right-click. Запускаем timer на pointer down, отменяем на pointer up если рано.
Какую проблему решаем
Императивные setTimeout в pointer handlers быстро превращаются в гонку между: обычный click, long press, context menu, destroy. Состояние сложно отследить, баги типа «один тап выполнил оба действия» очень частые.
Операторы и зачем они нужны
switchMap(() => timer(N)) — на каждый pointer down создаём timer. Новый down отменяет предыдущий.
timer(N) — длительность удержания.
takeUntil(pointerUp$) — если отпустили до срабатывания timer, long press НЕ срабатывает.
mapTo('long-press') — успех = команда.
Подводные камни
delay без отмены — long press сработает после обычного коротко тапа.
exhaustMap — второе нажатие игнорируется, пока первый timer не завершился. Пользователь подумает, что UI не отвечает.
Синхронизируйте long press с обычным click. Если оба зарегистрированы, нужно решать чьё событие применять.
Что в итоге получаем
Secondary action срабатывает только при реальном удержании. Короткие тапы остаются обычными click.