Skip to content

Commit

Permalink
Override placement for link menu via button click
Browse files Browse the repository at this point in the history
When the editor is very short (not much content), we want to still
ensure that the bubble menu appears below the button, so we prefer
"bottom" as the default placement.
  • Loading branch information
sjdemartini committed Jun 23, 2023
1 parent 597163f commit 7c15e52
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/ControlledBubbleMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export default function ControlledBubbleMenu({
disablePortal,
placement = "top",
fallbackPlacements = [
"top",
"bottom",
"top-start",
"bottom-start",
Expand Down
2 changes: 1 addition & 1 deletion src/LinkBubbleMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default function LinkBubbleMenu({
<ControlledBubbleMenu
editor={editor}
open={menuState !== LinkMenuState.HIDDEN}
anchorEl={handlerStorage.anchorEl}
{...handlerStorage.bubbleMenuOptions}
{...controlledBubbleMenuProps}
>
<div className={classes.content}>{linkMenuContent}</div>
Expand Down
9 changes: 6 additions & 3 deletions src/controls/MenuButtonEditLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ export default function MenuButtonEditLink(props: MenuButtonEditLinkProps) {
selected={editor?.isActive("link")}
disabled={!editor?.isEditable}
onClick={() =>
// Anchor the link bubble menu to the button, when clicking the button
// to open it
editor?.commands.openLinkBubbleMenu({ anchorEl: buttonRef.current })
// When clicking the button to open the bubble menu, we'll place the
// menu below the button
editor?.commands.openLinkBubbleMenu({
anchorEl: buttonRef.current,
placement: "bottom",
})
}
{...props}
/>
Expand Down
30 changes: 17 additions & 13 deletions src/extensions/LinkBubbleMenuHandler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// <reference types="@tiptap/extension-link" />
import type { PopperProps } from "@mui/material";
import { Extension, getAttributes } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import type { LinkBubbleMenuProps } from "../LinkBubbleMenu";

declare module "@tiptap/core" {
interface Commands<ReturnType> {
Expand All @@ -11,15 +11,19 @@ declare module "@tiptap/core" {
* the current cursor selection, or edit the existing link if there is
* already a link at the current selection.
*
* If the anchorEl is provided, it's used to override the anchor point for
* positioning the bubble menu. Each call to `openLinkBubbleMenu` will
* reset the anchor based on the provided argument. If not provided, the
* bubble menu will be anchored to the location in the editor content
* where the link appears or will appear.
* If the options are provided, they're used to override the bubble menu
* props, which can be useful for specific positioning needs. Each call to
* `openLinkBubbleMenu` will reset the options based on the provided
* argument, falling back to default behavior if not provided.
*
* For instance, if the anchorEl option is provided, it overrides the
* anchor point for positioning the bubble menu. (The default anchorEl for
* LinkBubbleMenu is to anchor to the location in the editor content where
* the link appears or will appear.)
*/
openLinkBubbleMenu: (options?: {
anchorEl?: PopperProps["anchorEl"];
}) => ReturnType;
openLinkBubbleMenu: (
options?: Partial<LinkBubbleMenuProps>
) => ReturnType;
/**
* Edit an existing link in the bubble menu, to be used when currently
* viewing a link in the already-opened bubble menu.
Expand All @@ -39,7 +43,7 @@ export enum LinkMenuState {

export type LinkBubbleMenuHandlerStorage = {
state: LinkMenuState;
anchorEl?: PopperProps["anchorEl"];
bubbleMenuOptions: Partial<LinkBubbleMenuProps> | undefined;
};

const LinkBubbleMenuHandler = Extension.create<
Expand All @@ -51,14 +55,14 @@ const LinkBubbleMenuHandler = Extension.create<
addStorage() {
return {
state: LinkMenuState.HIDDEN,
anchorEl: undefined,
bubbleMenuOptions: undefined,
};
},

addCommands() {
return {
openLinkBubbleMenu:
({ anchorEl } = {}) =>
(bubbleMenuOptions = {}) =>
({ editor, chain, dispatch }) => {
const currentMenuState = this.storage.state;

Expand Down Expand Up @@ -95,7 +99,7 @@ const LinkBubbleMenuHandler = Extension.create<
// this happens automatically for the Tiptap built-in commands
// called with `chain()` above.
this.storage.state = newMenuState;
this.storage.anchorEl = anchorEl;
this.storage.bubbleMenuOptions = bubbleMenuOptions;
}

return true;
Expand Down

0 comments on commit 7c15e52

Please sign in to comment.