-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathwithContextMenu.tsx
More file actions
71 lines (66 loc) · 2.51 KB
/
withContextMenu.tsx
File metadata and controls
71 lines (66 loc) · 2.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { useContext, useState, useCallback, useEffect } from 'react';
import { observer } from 'mobx-react';
import { Spinner } from '@patternfly/react-core';
import { GraphElement as TopologyElement } from '../types';
import ElementContext from '../utils/ElementContext';
import ContextMenu from '../components/contextmenu/ContextMenu';
type Reference = React.ComponentProps<typeof ContextMenu>['reference'];
export interface WithContextMenuProps {
onContextMenu?: (e: React.MouseEvent) => void;
contextMenuOpen?: boolean;
}
export const withContextMenu =
<E extends TopologyElement>(
actions: (element: E) => React.ReactElement[] | Promise<React.ReactElement[]>,
container?: Element | null | undefined | (() => Element),
className?: string,
atPoint: boolean = true,
waitElement: React.ReactElement = <Spinner className="pf-v6-u-mx-md" size="md" />
) =>
<P extends WithContextMenuProps>(WrappedComponent: React.ComponentType<P>) => {
const Component: React.FunctionComponent<Omit<P, keyof WithContextMenuProps>> = (props) => {
const element = useContext(ElementContext);
const [reference, setReference] = useState<Reference | null>(null);
const [elementActions, setElementActions] = useState<React.ReactElement[] | null>(null);
const onContextMenu = useCallback((e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
setReference(
atPoint
? {
x: e.clientX,
y: e.clientY
}
: e.currentTarget
);
}, []);
useEffect(() => {
if (reference) {
const actionsElements = actions(element as E);
Promise.resolve(actionsElements).then((resultActions) => {
setElementActions(resultActions);
});
} else {
setElementActions(null);
}
}, [element, reference]);
return (
<>
<WrappedComponent {...(props as any)} onContextMenu={onContextMenu} contextMenuOpen={!!reference} />
{reference ? (
<ContextMenu
reference={reference}
container={container}
className={className}
open
onRequestClose={() => setReference(null)}
>
{elementActions || waitElement}
</ContextMenu>
) : null}
</>
);
};
Component.displayName = `withContextMenu(${WrappedComponent.displayName || WrappedComponent.name})`;
return observer(Component);
};