Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add shouldShow callback to bubble menu #1710

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions docs/src/docPages/api/extensions/bubble-menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ yarn add @tiptap/extension-bubble-menu
```

## Settings
| Option | Type | Default | Description |
| ------------ | ------------- | ------- | ----------------------------------------------------------------------- |
| element | `HTMLElement` | `null` | The DOM element that contains your menu. |
| tippyOptions | `Object` | `{}` | [Options for tippy.js](https://atomiks.github.io/tippyjs/v6/all-props/) |
| Option | Type | Default | Description |
| ------------ | ------------- | ------------ | ----------------------------------------------------------------------- |
| element | `HTMLElement` | `null` | The DOM element that contains your menu. |
| tippyOptions | `Object` | `{}` | [Options for tippy.js](https://atomiks.github.io/tippyjs/v6/all-props/) |
| shouldShow | `Function` | `() => true` | A callback to control whether the menu should show |

## Source code
[packages/extension-bubble-menu/](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-bubble-menu/)
Expand All @@ -34,6 +35,10 @@ new Editor({
extensions: [
BubbleMenu.configure({
element: document.querySelector('.menu'),
shouldShow: ({ editor }) => {
// only show the buble menu for images and links
return editor.isActive('image') || editor.isActive('link')
}
}),
],
})
Expand Down
13 changes: 13 additions & 0 deletions packages/extension-bubble-menu/src/bubble-menu-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ import {
import { EditorState, Plugin, PluginKey } from 'prosemirror-state'
import { EditorView } from 'prosemirror-view'
import tippy, { Instance, Props } from 'tippy.js'
import { ShouldShow } from './bubble-menu'

export interface BubbleMenuPluginProps {
editor: Editor,
element: HTMLElement,
tippyOptions?: Partial<Props>,
shouldShow: ShouldShow,
}

export type BubbleMenuViewProps = BubbleMenuPluginProps & {
view: EditorView,
shouldShow: ShouldShow,
}

export class BubbleMenuView {
Expand All @@ -29,15 +32,19 @@ export class BubbleMenuView {

public tippy!: Instance

public shouldShow: ShouldShow

constructor({
editor,
element,
view,
tippyOptions,
shouldShow,
}: BubbleMenuViewProps) {
this.editor = editor
this.element = element
this.view = view
this.shouldShow = shouldShow
this.element.addEventListener('mousedown', this.mousedownHandler, { capture: true })
this.view.dom.addEventListener('dragstart', this.dragstartHandler)
this.editor.on('focus', this.focusHandler)
Expand Down Expand Up @@ -98,6 +105,12 @@ export class BubbleMenuView {
return
}

if (!this.shouldShow({ editor: this.editor, view: this.view })) {
this.hide()

return
}

const { empty, ranges } = selection

// support for CellSelections
Expand Down
7 changes: 6 additions & 1 deletion packages/extension-bubble-menu/src/bubble-menu.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { Extension } from '@tiptap/core'
import { Editor, Extension } from '@tiptap/core'
import { EditorView } from 'prosemirror-view'
import { BubbleMenuPlugin, BubbleMenuPluginProps } from './bubble-menu-plugin'

export type BubbleMenuOptions = Omit<BubbleMenuPluginProps, 'editor' | 'element'> & {
element: HTMLElement | null,
}

export type ShouldShow = (props?: { editor: Editor, view: EditorView }) => boolean

export const BubbleMenu = Extension.create<BubbleMenuOptions>({
name: 'bubbleMenu',

defaultOptions: {
element: null,
tippyOptions: {},
shouldShow: () => true,
},

addProseMirrorPlugins() {
Expand All @@ -23,6 +27,7 @@ export const BubbleMenu = Extension.create<BubbleMenuOptions>({
editor: this.editor,
element: this.options.element,
tippyOptions: this.options.tippyOptions,
shouldShow: this.options.shouldShow,
}),
]
},
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/BubbleMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ export const BubbleMenu: React.FC<BubbleMenuProps> = props => {
const element = useRef<HTMLDivElement>(null)

useEffect(() => {
const { editor, tippyOptions } = props
const { editor, tippyOptions, shouldShow } = props

editor.registerPlugin(BubbleMenuPlugin({
editor,
element: element.current as HTMLElement,
tippyOptions,
shouldShow,
}))

return () => {
Expand Down
7 changes: 7 additions & 0 deletions packages/vue-2/src/BubbleMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BubbleMenuPlugin, BubbleMenuPluginKey, BubbleMenuPluginProps } from '@t
export interface BubbleMenuInterface extends Vue {
tippyOptions: BubbleMenuPluginProps['tippyOptions'],
editor: BubbleMenuPluginProps['editor'],
shouldShow: BubbleMenuPluginProps['shouldShow'],
}

export const BubbleMenu: Component = {
Expand All @@ -19,6 +20,11 @@ export const BubbleMenu: Component = {
type: Object as PropType<BubbleMenuPluginProps['tippyOptions']>,
default: () => ({}),
},

shouldShow: {
type: Function as PropType<BubbleMenuPluginProps['shouldShow']>,
default: () => true,
},
},

watch: {
Expand All @@ -34,6 +40,7 @@ export const BubbleMenu: Component = {
editor,
element: this.$el as HTMLElement,
tippyOptions: this.tippyOptions,
shouldShow: this.shouldShow,
}))
})
},
Expand Down
8 changes: 7 additions & 1 deletion packages/vue-3/src/BubbleMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,24 @@ export const BubbleMenu = defineComponent({
type: Object as PropType<BubbleMenuPluginProps['tippyOptions']>,
default: () => ({}),
},

shouldShow: {
type: Function as PropType<BubbleMenuPluginProps['shouldShow']>,
default: () => true,
},
},

setup(props, { slots }) {
const root = ref<HTMLElement | null>(null)

onMounted(() => {
const { editor, tippyOptions } = props
const { editor, tippyOptions, shouldShow } = props

editor.registerPlugin(BubbleMenuPlugin({
editor,
element: root.value as HTMLElement,
tippyOptions,
shouldShow,
}))
})

Expand Down