mirror of
https://github.com/danog/telegram-tt.git
synced 2025-01-22 05:11:55 +01:00
Message Context Menu: Better animation anchor (#1676)
This commit is contained in:
parent
f3b0b75e4e
commit
eb261e9abe
@ -177,7 +177,7 @@ const MessageContextMenu: FC<OwnProps> = ({
|
|||||||
}, [isOpen, markIsReady, unmarkIsReady]);
|
}, [isOpen, markIsReady, unmarkIsReady]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
positionX, positionY, style, menuStyle, withScroll,
|
positionX, positionY, transformOriginX, transformOriginY, style, menuStyle, withScroll,
|
||||||
} = useContextMenuPosition(anchor, getTriggerElement, getRootElement, getMenuElement, getLayout);
|
} = useContextMenuPosition(anchor, getTriggerElement, getRootElement, getMenuElement, getLayout);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -192,6 +192,8 @@ const MessageContextMenu: FC<OwnProps> = ({
|
|||||||
<Menu
|
<Menu
|
||||||
ref={menuRef}
|
ref={menuRef}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
|
transformOriginX={transformOriginX}
|
||||||
|
transformOriginY={transformOriginY}
|
||||||
positionX={positionX}
|
positionX={positionX}
|
||||||
positionY={positionY}
|
positionY={positionY}
|
||||||
style={style}
|
style={style}
|
||||||
|
@ -123,7 +123,7 @@ export default function useOuterHandlers(
|
|||||||
|
|
||||||
function handleContextMenu(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
|
function handleContextMenu(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
|
||||||
if (IS_ANDROID) {
|
if (IS_ANDROID) {
|
||||||
if ((e.target as HTMLElement).matches('a[href]')) {
|
if ((e.target as HTMLElement).matches('a[href]') || isContextMenuShown) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,9 @@ const ListItem: FC<OwnProps> = ({
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { positionX, positionY, style: menuStyle } = useContextMenuPosition(
|
const {
|
||||||
|
positionX, positionY, transformOriginX, transformOriginY, style: menuStyle,
|
||||||
|
} = useContextMenuPosition(
|
||||||
contextMenuPosition,
|
contextMenuPosition,
|
||||||
getTriggerElement,
|
getTriggerElement,
|
||||||
getRootElement,
|
getRootElement,
|
||||||
@ -195,6 +197,8 @@ const ListItem: FC<OwnProps> = ({
|
|||||||
{contextActions && contextMenuPosition !== undefined && (
|
{contextActions && contextMenuPosition !== undefined && (
|
||||||
<Menu
|
<Menu
|
||||||
isOpen={isContextMenuOpen}
|
isOpen={isContextMenuOpen}
|
||||||
|
transformOriginX={transformOriginX}
|
||||||
|
transformOriginY={transformOriginY}
|
||||||
positionX={positionX}
|
positionX={positionX}
|
||||||
positionY={positionY}
|
positionY={positionY}
|
||||||
style={menuStyle}
|
style={menuStyle}
|
||||||
|
@ -20,6 +20,8 @@ type OwnProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
style?: string;
|
style?: string;
|
||||||
bubbleStyle?: string;
|
bubbleStyle?: string;
|
||||||
|
transformOriginX?: number;
|
||||||
|
transformOriginY?: number;
|
||||||
positionX?: 'left' | 'right';
|
positionX?: 'left' | 'right';
|
||||||
positionY?: 'top' | 'bottom';
|
positionY?: 'top' | 'bottom';
|
||||||
autoClose?: boolean;
|
autoClose?: boolean;
|
||||||
@ -44,6 +46,8 @@ const Menu: FC<OwnProps> = ({
|
|||||||
style,
|
style,
|
||||||
bubbleStyle,
|
bubbleStyle,
|
||||||
children,
|
children,
|
||||||
|
transformOriginX,
|
||||||
|
transformOriginY,
|
||||||
positionX = 'left',
|
positionX = 'left',
|
||||||
positionY = 'top',
|
positionY = 'top',
|
||||||
autoClose = false,
|
autoClose = false,
|
||||||
@ -101,6 +105,9 @@ const Menu: FC<OwnProps> = ({
|
|||||||
transitionClassNames,
|
transitionClassNames,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const transformOriginYStyle = transformOriginY !== undefined ? `${transformOriginY}px` : undefined;
|
||||||
|
const transformOriginXStyle = transformOriginX !== undefined ? `${transformOriginX}px` : undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={buildClassName('Menu no-selection', className)}
|
className={buildClassName('Menu no-selection', className)}
|
||||||
@ -118,7 +125,8 @@ const Menu: FC<OwnProps> = ({
|
|||||||
ref={menuRef}
|
ref={menuRef}
|
||||||
className={bubbleClassName}
|
className={bubbleClassName}
|
||||||
// @ts-ignore teact feature
|
// @ts-ignore teact feature
|
||||||
style={`transform-origin: ${positionY} ${positionX};${bubbleStyle || ''}`}
|
style={`transform-origin: ${transformOriginXStyle || positionX} ${transformOriginYStyle || positionY};${
|
||||||
|
bubbleStyle || ''}`}
|
||||||
onClick={autoClose ? onClose : undefined}
|
onClick={autoClose ? onClose : undefined}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@ -23,6 +23,8 @@ export default function useContextMenuPosition(
|
|||||||
) {
|
) {
|
||||||
const [positionX, setPositionX] = useState<'right' | 'left'>('right');
|
const [positionX, setPositionX] = useState<'right' | 'left'>('right');
|
||||||
const [positionY, setPositionY] = useState<'top' | 'bottom'>('bottom');
|
const [positionY, setPositionY] = useState<'top' | 'bottom'>('bottom');
|
||||||
|
const [transformOriginX, setTransformOriginX] = useState<number>();
|
||||||
|
const [transformOriginY, setTransformOriginY] = useState<number>();
|
||||||
const [withScroll, setWithScroll] = useState(false);
|
const [withScroll, setWithScroll] = useState(false);
|
||||||
const [style, setStyle] = useState('');
|
const [style, setStyle] = useState('');
|
||||||
const [menuStyle, setMenuStyle] = useState('opacity: 0;');
|
const [menuStyle, setMenuStyle] = useState('opacity: 0;');
|
||||||
@ -34,6 +36,8 @@ export default function useContextMenuPosition(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let { x, y } = anchor;
|
let { x, y } = anchor;
|
||||||
|
const anchorX = x;
|
||||||
|
const anchorY = y;
|
||||||
|
|
||||||
const menuEl = getMenuElement();
|
const menuEl = getMenuElement();
|
||||||
const rootEl = getRootElement();
|
const rootEl = getRootElement();
|
||||||
@ -55,6 +59,7 @@ export default function useContextMenuPosition(
|
|||||||
const rootRect = rootEl ? rootEl.getBoundingClientRect() : EMPTY_RECT;
|
const rootRect = rootEl ? rootEl.getBoundingClientRect() : EMPTY_RECT;
|
||||||
|
|
||||||
let horizontalPosition: 'left' | 'right';
|
let horizontalPosition: 'left' | 'right';
|
||||||
|
let verticalPosition: 'top' | 'bottom';
|
||||||
if (x + menuRect.width + extraPaddingX < rootRect.width + rootRect.left) {
|
if (x + menuRect.width + extraPaddingX < rootRect.width + rootRect.left) {
|
||||||
x += 3;
|
x += 3;
|
||||||
horizontalPosition = 'left';
|
horizontalPosition = 'left';
|
||||||
@ -81,14 +86,15 @@ export default function useContextMenuPosition(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (y + menuRect.height < rootRect.height + rootRect.top) {
|
if (y + menuRect.height < rootRect.height + rootRect.top) {
|
||||||
setPositionY('top');
|
verticalPosition = 'top';
|
||||||
} else {
|
} else {
|
||||||
setPositionY('bottom');
|
verticalPosition = 'bottom';
|
||||||
|
|
||||||
if (y - menuRect.height < rootRect.top + extraTopPadding) {
|
if (y - menuRect.height < rootRect.top + extraTopPadding) {
|
||||||
y = rootRect.top + rootRect.height;
|
y = rootRect.top + rootRect.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setPositionY(verticalPosition);
|
||||||
|
|
||||||
const triggerRect = triggerEl.getBoundingClientRect();
|
const triggerRect = triggerEl.getBoundingClientRect();
|
||||||
const left = horizontalPosition === 'left'
|
const left = horizontalPosition === 'left'
|
||||||
@ -103,6 +109,10 @@ export default function useContextMenuPosition(
|
|||||||
setWithScroll(menuMaxHeight < menuRect.height);
|
setWithScroll(menuMaxHeight < menuRect.height);
|
||||||
setMenuStyle(`max-height: ${menuMaxHeight}px;`);
|
setMenuStyle(`max-height: ${menuMaxHeight}px;`);
|
||||||
setStyle(`left: ${left}px; top: ${top}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,
|
anchor, getMenuElement, getRootElement, getTriggerElement, getLayout,
|
||||||
]);
|
]);
|
||||||
@ -110,6 +120,8 @@ export default function useContextMenuPosition(
|
|||||||
return {
|
return {
|
||||||
positionX,
|
positionX,
|
||||||
positionY,
|
positionY,
|
||||||
|
transformOriginX,
|
||||||
|
transformOriginY,
|
||||||
style,
|
style,
|
||||||
menuStyle,
|
menuStyle,
|
||||||
withScroll,
|
withScroll,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user