diff --git a/client/src/components/cards/Card/Card.jsx b/client/src/components/cards/Card/Card.jsx
index c4d12b1a..37e614c0 100755
--- a/client/src/components/cards/Card/Card.jsx
+++ b/client/src/components/cards/Card/Card.jsx
@@ -5,13 +5,13 @@
import upperFirst from 'lodash/upperFirst';
import camelCase from 'lodash/camelCase';
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { useCallback, useMemo, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { Button, Icon } from 'semantic-ui-react';
import { push } from '../../../lib/redux-router';
-import { usePopup } from '../../../lib/popup';
+import { closePopup, usePopup } from '../../../lib/popup';
import selectors from '../../../selectors';
import Paths from '../../../constants/Paths';
@@ -51,6 +51,8 @@ const Card = React.memo(({ id, isInline }) => {
const dispatch = useDispatch();
const [isEditNameOpened, setIsEditNameOpened] = useState(false);
+ const actionsPopupRef = useRef(null);
+
const handleClick = useCallback(() => {
if (document.activeElement) {
document.activeElement.blur();
@@ -59,6 +61,17 @@ const Card = React.memo(({ id, isInline }) => {
dispatch(push(Paths.CARDS.replace(':id', id)));
}, [id, dispatch]);
+ const handleContextMenu = useCallback((event) => {
+ if (!actionsPopupRef.current) {
+ return;
+ }
+
+ event.preventDefault();
+
+ closePopup();
+ actionsPopupRef.current.open();
+ }, []);
+
const handleNameEdit = useCallback(() => {
setIsEditNameOpened(true);
}, []);
@@ -110,12 +123,13 @@ const Card = React.memo(({ id, isInline }) => {
{colorLineNode}
{canUseActions && (
-
+
diff --git a/client/src/lib/popup/use-popup.jsx b/client/src/lib/popup/use-popup.jsx
index 58ef95a8..d0f59110 100644
--- a/client/src/lib/popup/use-popup.jsx
+++ b/client/src/lib/popup/use-popup.jsx
@@ -4,7 +4,7 @@
*/
import { ResizeObserver } from '@juggle/resize-observer';
-import React, { useCallback, useMemo, useRef, useState } from 'react';
+import React, { useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { Button, Popup as SemanticUIPopup } from 'semantic-ui-react';
@@ -12,13 +12,13 @@ import styles from './Popup.module.css';
export default (Step, { position, onOpen, onClose } = {}) => {
return useMemo(() => {
- const Popup = React.memo(({ children, ...stepProps }) => {
+ const Popup = React.forwardRef(({ children, ...stepProps }, ref) => {
const [isOpened, setIsOpened] = useState(false);
const wrapperRef = useRef(null);
const resizeObserverRef = useRef(null);
- const handleOpen = useCallback(() => {
+ const open = useCallback(() => {
setIsOpened(true);
if (onOpen) {
@@ -26,6 +26,10 @@ export default (Step, { position, onOpen, onClose } = {}) => {
}
}, []);
+ const handleOpen = useCallback(() => {
+ open();
+ }, [open]);
+
const handleClose = useCallback(() => {
setIsOpened(false);
}, []);
@@ -73,6 +77,14 @@ export default (Step, { position, onOpen, onClose } = {}) => {
resizeObserverRef.current.observe(element);
}, []);
+ useImperativeHandle(
+ ref,
+ () => ({
+ open,
+ }),
+ [open],
+ );
+
const tigger = React.cloneElement(children, {
onClick: handleTriggerClick,
});
@@ -116,6 +128,6 @@ export default (Step, { position, onOpen, onClose } = {}) => {
children: PropTypes.node.isRequired,
};
- return Popup;
+ return React.memo(Popup);
}, [position, onOpen, onClose]);
};