Skip to content

Commit

Permalink
Node-aware Context Menu Items (facebook#5791)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivailop7 authored Apr 1, 2024
1 parent bde1c84 commit 48629ea
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
*
*/

import {$isLinkNode, TOGGLE_LINK_COMMAND} from '@lexical/link';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {
LexicalContextMenuPlugin,
MenuOption,
} from '@lexical/react/LexicalContextMenuPlugin';
import {
type LexicalNode,
$getNearestNodeFromDOMNode,
$getSelection,
$isRangeSelection,
COPY_COMMAND,
Expand Down Expand Up @@ -103,7 +105,7 @@ export class ContextMenuOption extends MenuOption {
export default function ContextMenuPlugin(): JSX.Element {
const [editor] = useLexicalComposerContext();

const options = useMemo(() => {
const defaultOptions = useMemo(() => {
return [
new ContextMenuOption(`Copy`, {
onSelect: (_node) => {
Expand Down Expand Up @@ -185,6 +187,8 @@ export default function ContextMenuPlugin(): JSX.Element {
];
}, [editor]);

const [options, setOptions] = React.useState(defaultOptions);

const onSelectOption = useCallback(
(
selectedOption: ContextMenuOption,
Expand All @@ -199,10 +203,32 @@ export default function ContextMenuPlugin(): JSX.Element {
[editor],
);

const onWillOpen = (event: MouseEvent) => {
let newOptions = defaultOptions;
editor.update(() => {
const node = $getNearestNodeFromDOMNode(event.target as Element);
if (node) {
const parent = node.getParent();
if ($isLinkNode(parent)) {
newOptions = [
new ContextMenuOption(`Remove Link`, {
onSelect: (_node) => {
editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
},
}),
...defaultOptions,
];
}
}
});
setOptions(newOptions);
};

return (
<LexicalContextMenuPlugin
options={options}
onSelectOption={onSelectOption}
onWillOpen={onWillOpen}
menuRenderFn={(
anchorElementRef,
{
Expand Down
7 changes: 6 additions & 1 deletion packages/lexical-react/src/LexicalContextMenuPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type LexicalContextMenuPluginProps<TOption extends MenuOption> = {
) => void;
options: Array<TOption>;
onClose?: () => void;
onWillOpen?: (event: MouseEvent) => void;
onOpen?: (resolution: MenuResolution) => void;
menuRenderFn: ContextMenuRenderFn<TOption>;
anchorClassName?: string;
Expand All @@ -58,6 +59,7 @@ const PRE_PORTAL_DIV_SIZE = 1;

export function LexicalContextMenuPlugin<TOption extends MenuOption>({
options,
onWillOpen,
onClose,
onOpen,
onSelectOption,
Expand Down Expand Up @@ -97,6 +99,9 @@ export function LexicalContextMenuPlugin<TOption extends MenuOption>({
const handleContextMenu = useCallback(
(event: MouseEvent) => {
event.preventDefault();
if (onWillOpen != null) {
onWillOpen(event);
}
const zoom = calculateZoomLevel(event.target as Element);
openNodeMenu({
getRect: () =>
Expand All @@ -108,7 +113,7 @@ export function LexicalContextMenuPlugin<TOption extends MenuOption>({
),
});
},
[openNodeMenu],
[openNodeMenu, onWillOpen],
);

const handleClick = useCallback(
Expand Down
4 changes: 1 addition & 3 deletions packages/lexical-react/src/shared/LexicalMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,7 @@ export function useMenuAnchorRef(
if (rootElement !== null && resolution !== null) {
const {left, top, width, height} = resolution.getRect();
const anchorHeight = anchorElementRef.current.offsetHeight; // use to position under anchor
containerDiv.style.top = `${
top + window.pageYOffset + anchorHeight + 3
}px`;
containerDiv.style.top = `${top + anchorHeight + 3}px`;
containerDiv.style.left = `${left + window.pageXOffset}px`;
containerDiv.style.height = `${height}px`;
containerDiv.style.width = `${width}px`;
Expand Down

0 comments on commit 48629ea

Please sign in to comment.