jitsi-meet/react/features/base/ui/hooks/useContextMenu.web.ts
theluyuan 38ba663466
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
init
2025-09-02 14:49:16 +08:00

78 lines
2.3 KiB
TypeScript

import { useCallback, useRef, useState } from 'react';
import { findAncestorByClass } from '../functions.web';
type RaiseContext<T> = {
/**
* The entity for which the menu is context menu is raised.
*/
entity?: T;
/**
* Target elements against which positioning calculations are made.
*/
offsetTarget?: HTMLElement | null;
};
const initialState = Object.freeze({});
const useContextMenu = <T>(): [(force?: boolean | Object) => void,
(entity: T, target: HTMLElement | null) => void,
(entity: T) => (e?: MouseEvent) => void,
() => void,
() => void,
RaiseContext<T>] => {
const [ raiseContext, setRaiseContext ] = useState < RaiseContext<T> >(initialState);
const isMouseOverMenu = useRef(false);
const lowerMenu = useCallback((force: boolean | Object = false) => {
/**
* We are tracking mouse movement over the active participant item and
* the context menu. Due to the order of enter/leave events, we need to
* defer checking if the mouse is over the context menu with
* queueMicrotask.
*/
window.queueMicrotask(() => {
if (isMouseOverMenu.current && !(force === true)) {
return;
}
if (raiseContext !== initialState || force) {
setRaiseContext(initialState);
}
});
}, [ raiseContext ]);
const raiseMenu = useCallback((entity: T, target: HTMLElement | null) => {
setRaiseContext({
entity,
offsetTarget: findAncestorByClass(target, 'list-item-container')
});
}, [ raiseContext ]);
const toggleMenu = useCallback((entity: T) => (e?: MouseEvent) => {
e?.stopPropagation();
const { entity: raisedEntity } = raiseContext;
if (raisedEntity && raisedEntity === entity) {
lowerMenu();
} else {
raiseMenu(entity, e?.target as HTMLElement);
}
}, [ raiseContext ]);
const menuEnter = useCallback(() => {
isMouseOverMenu.current = true;
}, []);
const menuLeave = useCallback(() => {
isMouseOverMenu.current = false;
}, [ lowerMenu ]);
return [ lowerMenu, raiseMenu, toggleMenu, menuEnter, menuLeave, raiseContext ];
};
export default useContextMenu;