fix(context-menu): Move the reposition logic from the context menu to the dialog component. (#5060)
This commit is contained in:
parent
fa9bbe3afc
commit
cb814e6a60
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../components/Dialog/Dialog';
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../components/Dialog/Dialog';
|
||||||
import { cn } from '../lib/utils';
|
import { cn } from '../lib/utils';
|
||||||
|
|
||||||
@ -34,6 +34,37 @@ const ManagedDialog: React.FC<ManagedDialogProps> = ({
|
|||||||
unstyled,
|
unstyled,
|
||||||
containerClassName,
|
containerClassName,
|
||||||
}) => {
|
}) => {
|
||||||
|
// When a default position is provided, the assumption is that the position
|
||||||
|
// is respected unless the position chosen results in the dialog being
|
||||||
|
// clipped off-screen (i.e. part of the dialog is rendered outside the browser
|
||||||
|
// window). When the dialog is clipped it will be repositioned about
|
||||||
|
// the default position such that it is no longer clipped. To avoid a flash
|
||||||
|
// during the reposition, we initially hide the dialog.
|
||||||
|
const [contentVisibility, setContentVisibility] = useState(
|
||||||
|
defaultPosition ? 'invisible' : 'visible'
|
||||||
|
);
|
||||||
|
|
||||||
|
// The callback to reposition an explicitly positioned dialog. Note that
|
||||||
|
// if the dialog is larger than the window (in either dimension), the
|
||||||
|
// dialog will still be clipped in some manner.
|
||||||
|
const contentRef = useCallback(
|
||||||
|
contentNode => {
|
||||||
|
if (!contentNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const boundingClientRect = contentNode.getBoundingClientRect();
|
||||||
|
if (boundingClientRect.bottom > window.innerHeight) {
|
||||||
|
defaultPosition.y = defaultPosition.y - boundingClientRect.height;
|
||||||
|
}
|
||||||
|
if (boundingClientRect.right > window.innerWidth) {
|
||||||
|
defaultPosition.x = defaultPosition.x - boundingClientRect.width;
|
||||||
|
}
|
||||||
|
setContentVisibility('visible');
|
||||||
|
},
|
||||||
|
[defaultPosition]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
@ -49,7 +80,8 @@ const ManagedDialog: React.FC<ManagedDialogProps> = ({
|
|||||||
showOverlay={showOverlay}
|
showOverlay={showOverlay}
|
||||||
>
|
>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className={cn(unstyled ? 'p-0' : '', containerClassName)}
|
ref={contentRef}
|
||||||
|
className={cn(unstyled ? 'p-0' : '', containerClassName, contentVisibility)}
|
||||||
unstyled={unstyled}
|
unstyled={unstyled}
|
||||||
style={{
|
style={{
|
||||||
...(defaultPosition
|
...(defaultPosition
|
||||||
@ -60,6 +92,7 @@ const ManagedDialog: React.FC<ManagedDialogProps> = ({
|
|||||||
transform: 'translate(0, 0)',
|
transform: 'translate(0, 0)',
|
||||||
margin: 0,
|
margin: 0,
|
||||||
animation: 'none',
|
animation: 'none',
|
||||||
|
transition: 'none',
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -1,33 +1,15 @@
|
|||||||
import React, { useEffect, useRef } from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Typography from '../Typography';
|
import Typography from '../Typography';
|
||||||
import { Icons } from '@ohif/ui-next';
|
import { Icons } from '@ohif/ui-next';
|
||||||
|
|
||||||
const ContextMenu = ({ items, ...props }) => {
|
const ContextMenu = ({ items, ...props }) => {
|
||||||
const contextMenuRef = useRef<HTMLDivElement>(null);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!contextMenuRef?.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const contextMenu = contextMenuRef.current;
|
|
||||||
|
|
||||||
const boundingClientRect = contextMenu.getBoundingClientRect();
|
|
||||||
if (boundingClientRect.bottom > window.innerHeight) {
|
|
||||||
props.defaultPosition.y = props.defaultPosition.y - boundingClientRect.height;
|
|
||||||
}
|
|
||||||
if (boundingClientRect.right > window.innerWidth) {
|
|
||||||
props.defaultPosition.x = props.defaultPosition.x - boundingClientRect.width;
|
|
||||||
}
|
|
||||||
}, [props.defaultPosition]);
|
|
||||||
|
|
||||||
if (!items) {
|
if (!items) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={contextMenuRef}
|
|
||||||
data-cy="context-menu"
|
data-cy="context-menu"
|
||||||
className="bg-secondary-dark relative z-50 block w-48 rounded"
|
className="bg-secondary-dark relative z-50 block w-48 rounded"
|
||||||
onContextMenu={e => e.preventDefault()}
|
onContextMenu={e => e.preventDefault()}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user