Message Context Menu: Better animation anchor (#1676)

This commit is contained in:
Alexander Zinchuk 2022-01-28 20:59:39 +01:00
parent f3b0b75e4e
commit eb261e9abe
5 changed files with 32 additions and 6 deletions

View File

@ -177,7 +177,7 @@ const MessageContextMenu: FC<OwnProps> = ({
}, [isOpen, markIsReady, unmarkIsReady]);
const {
positionX, positionY, style, menuStyle, withScroll,
positionX, positionY, transformOriginX, transformOriginY, style, menuStyle, withScroll,
} = useContextMenuPosition(anchor, getTriggerElement, getRootElement, getMenuElement, getLayout);
useEffect(() => {
@ -192,6 +192,8 @@ const MessageContextMenu: FC<OwnProps> = ({
<Menu
ref={menuRef}
isOpen={isOpen}
transformOriginX={transformOriginX}
transformOriginY={transformOriginY}
positionX={positionX}
positionY={positionY}
style={style}

View File

@ -123,7 +123,7 @@ export default function useOuterHandlers(
function handleContextMenu(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
if (IS_ANDROID) {
if ((e.target as HTMLElement).matches('a[href]')) {
if ((e.target as HTMLElement).matches('a[href]') || isContextMenuShown) {
return;
}

View File

@ -91,7 +91,9 @@ const ListItem: FC<OwnProps> = ({
[],
);
const { positionX, positionY, style: menuStyle } = useContextMenuPosition(
const {
positionX, positionY, transformOriginX, transformOriginY, style: menuStyle,
} = useContextMenuPosition(
contextMenuPosition,
getTriggerElement,
getRootElement,
@ -195,6 +197,8 @@ const ListItem: FC<OwnProps> = ({
{contextActions && contextMenuPosition !== undefined && (
<Menu
isOpen={isContextMenuOpen}
transformOriginX={transformOriginX}
transformOriginY={transformOriginY}
positionX={positionX}
positionY={positionY}
style={menuStyle}

View File

@ -20,6 +20,8 @@ type OwnProps = {
className?: string;
style?: string;
bubbleStyle?: string;
transformOriginX?: number;
transformOriginY?: number;
positionX?: 'left' | 'right';
positionY?: 'top' | 'bottom';
autoClose?: boolean;
@ -44,6 +46,8 @@ const Menu: FC<OwnProps> = ({
style,
bubbleStyle,
children,
transformOriginX,
transformOriginY,
positionX = 'left',
positionY = 'top',
autoClose = false,
@ -101,6 +105,9 @@ const Menu: FC<OwnProps> = ({
transitionClassNames,
);
const transformOriginYStyle = transformOriginY !== undefined ? `${transformOriginY}px` : undefined;
const transformOriginXStyle = transformOriginX !== undefined ? `${transformOriginX}px` : undefined;
return (
<div
className={buildClassName('Menu no-selection', className)}
@ -118,7 +125,8 @@ const Menu: FC<OwnProps> = ({
ref={menuRef}
className={bubbleClassName}
// @ts-ignore teact feature
style={`transform-origin: ${positionY} ${positionX};${bubbleStyle || ''}`}
style={`transform-origin: ${transformOriginXStyle || positionX} ${transformOriginYStyle || positionY};${
bubbleStyle || ''}`}
onClick={autoClose ? onClose : undefined}
>
{children}

View File

@ -23,6 +23,8 @@ export default function useContextMenuPosition(
) {
const [positionX, setPositionX] = useState<'right' | 'left'>('right');
const [positionY, setPositionY] = useState<'top' | 'bottom'>('bottom');
const [transformOriginX, setTransformOriginX] = useState<number>();
const [transformOriginY, setTransformOriginY] = useState<number>();
const [withScroll, setWithScroll] = useState(false);
const [style, setStyle] = useState('');
const [menuStyle, setMenuStyle] = useState('opacity: 0;');
@ -34,6 +36,8 @@ export default function useContextMenuPosition(
}
let { x, y } = anchor;
const anchorX = x;
const anchorY = y;
const menuEl = getMenuElement();
const rootEl = getRootElement();
@ -55,6 +59,7 @@ export default function useContextMenuPosition(
const rootRect = rootEl ? rootEl.getBoundingClientRect() : EMPTY_RECT;
let horizontalPosition: 'left' | 'right';
let verticalPosition: 'top' | 'bottom';
if (x + menuRect.width + extraPaddingX < rootRect.width + rootRect.left) {
x += 3;
horizontalPosition = 'left';
@ -81,14 +86,15 @@ export default function useContextMenuPosition(
}
if (y + menuRect.height < rootRect.height + rootRect.top) {
setPositionY('top');
verticalPosition = 'top';
} else {
setPositionY('bottom');
verticalPosition = 'bottom';
if (y - menuRect.height < rootRect.top + extraTopPadding) {
y = rootRect.top + rootRect.height;
}
}
setPositionY(verticalPosition);
const triggerRect = triggerEl.getBoundingClientRect();
const left = horizontalPosition === 'left'
@ -103,6 +109,10 @@ export default function useContextMenuPosition(
setWithScroll(menuMaxHeight < menuRect.height);
setMenuStyle(`max-height: ${menuMaxHeight}px;`);
setStyle(`left: ${left}px; top: ${top}px`);
const offsetX = (anchorX - triggerRect.left) - left;
const offsetY = (anchorY - triggerRect.top) - top - (marginTop || 0);
setTransformOriginX(horizontalPosition === 'left' ? offsetX : menuRect.width + offsetX);
setTransformOriginY(verticalPosition === 'bottom' ? menuRect.height + offsetY : offsetY);
}, [
anchor, getMenuElement, getRootElement, getTriggerElement, getLayout,
]);
@ -110,6 +120,8 @@ export default function useContextMenuPosition(
return {
positionX,
positionY,
transformOriginX,
transformOriginY,
style,
menuStyle,
withScroll,