Closed sabetAI closed 3 years ago
If you want to toggle a floating menu, without inputting a character like the experimental commands extension, I would suggest doing either of two things (which are pretty similar):
showFloatingMenu
as part of its state.
addKeyboardShortcuts
to tr.setMeta(pluginKey, true | false})
.apply(tr)
method, use tr.getMeta(pluginKey)
to update the plugin state.shouldShow
, show the floating menu if pluginKey.getState(view.state) == true
.FloatingMenu
plugin to have a show
state, update plugin state using setMeta
and getMeta
as mentioned beforee, use that state within update
to show or hide.Great suggestions! Implementing 1, it appears shouldShow
triggers before the addKeyboardShortcuts
callback, so tr.setMeta
doesn't have any effect. Oddly, apply(tr)
gets called twice after keyboard press, where tr.getMeta(pluginKey)
returns true the first time (because addKeyboardShortcuts
sets it to true), then undefined second time. Here are my snippets:
export const FloatingMenuPlugin = (options: FloatingMenuPluginProps) => {
return new Plugin({
key:
typeof options.pluginKey === "string"
? new PluginKey(options.pluginKey)
: options.pluginKey,
view: (view) => new FloatingMenuView({ view, ...options }),
state: {
init: () => {
return { showFloatingMenu: false };
},
apply: (tr, value) => {
return { showFloatingMenu: tr.getMeta(floatingMenuKey) };
},
},
});
};
export const floatingMenuKey = new PluginKey("floatingMenu");
extension:
FloatingMenuBase.extend({
addKeyboardShortcuts() {
return {
"Mod-e": () =>
this.editor.commands.command(({ tr, state }) => {
tr.setMeta(floatingMenuKey, true);
console.log(`keyboard: ${tr.getMeta(floatingMenuKey)}`);
return true;
}),
};
},
}),
and component:
<FloatingMenu
editor={editor}
pluginKey={floatingMenuKey}
shouldShow={({ editor, view, state, oldState }) => {
const menuState = floatingMenuKey.getState(view.state);
return menuState.showFloatingMenu;
}}
/>
@sabetAI Ah, I found the issue.
Within FloatingMenuView
, shouldShow
isn't called even though the plugin state updates because of these two lines: change in plugin state doesn't touch the document nor the selection so this always shortcircuits.
const isSame = oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection);
if (composing || isSame) {
return;
}
Workaround would be to remove isSame
, which requires either a change in tiptap and or you can fork FloatingMenuView
.
Here's a working demo with isSame
removed. Another note from the code sandbox is that you will have to copy the FloatingMenu
React or Vue component because it uses the default FloatingMenuPlugin
instead of the one you modified to have plugin state.
@BrianHung thanks for the correction and demo code 🙏, works beautifully. When I try to add some menu items to the FloatingMenu, the onClick
for none of them seem to get triggered, however. Here's a demo showing this. This wasn't this case with the original FloatingMenu or BubbleMenu. What might be causing this?
@sabetAI
The menu is closing before the click can register because apply
is being called beforehand, and getMeta
for that transaction is undefined
. To ignore transactions that don't have to do with floatingMenuKey
, we check whether it is undefined
first.
If it is undefined
, we just return the same plugin state as before (second argument to apply
); otherwise, we update the plugin state with the value we put into setMeta
.
apply: (tr, value) => {
let meta = tr.getMeta(floatingMenuKey);
if (meta !== undefined) {
return { showFloatingMenu: meta };
} else {
return value;
}
}
To close the menu, in the same transaction, call setMeta(floatingMenuKey, false)
.
@BrianHung ah thanks, makes a lot of sense 👍. I also added toggling the menu off with
Escape: () =>
this.editor.commands.command(({ tr, state, dispatch }) => {
dispatch(tr.setMeta(floatingMenuKey, false))
console.log("setfloatingOff");
return true;
}),
everything works smoothly now 🙏.
The problem I am facing In the example from the docs, the FloatingMenu displays when the cursor is set at a new line. I would like to toggle the floating menu (or the BubbleMenu) through a keyboard shortcut. How could I implement this? Do I use an addKeyboardShortcuts() {} plugin extension?
The solution I would like Toggle a floating menu through a keyboard shortcut.
Alternatives I have considered