add renderless FloatingMenu

This commit is contained in:
Philipp Kühn
2018-11-04 19:46:09 +01:00
parent 41f38e1041
commit d4f6708daa
3 changed files with 57 additions and 22 deletions

View File

@@ -1,7 +1,12 @@
<template> <template>
<div class="editor"> <div class="editor">
<floating-menu class="editor__floating-menu" :editor="editor"> <floating-menu :editor="editor">
<template slot-scope="{ commands, isActive }"> <div
slot-scope="{ commands, isActive, menu }"
class="editor__floating-menu"
:class="{ 'is-active': menu.isActive }"
:style="`top: ${menu.top}px`"
>
<button <button
class="menubar__button" class="menubar__button"
@@ -59,7 +64,7 @@
<icon name="code" /> <icon name="code" />
</button> </button>
</template> </div>
</floating-menu> </floating-menu>
<editor-content class="editor__content" :editor="editor" /> <editor-content class="editor__content" :editor="editor" />
@@ -138,6 +143,11 @@ export default {
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
transition: opacity 0.2s, visibility 0.2s; transition: opacity 0.2s, visibility 0.2s;
&.is-active {
opacity: 1;
visibility: visible;
}
} }
} }

View File

@@ -7,29 +7,44 @@ export default {
type: Object, type: Object,
}, },
}, },
data() {
return {
menu: {
isActive: false,
left: 0,
bottom: 0,
},
}
},
watch: { watch: {
editor: { editor: {
immediate: true, immediate: true,
handler(editor) { handler(editor) {
if (editor) { if (editor) {
this.$nextTick(() => { this.$nextTick(() => {
editor.registerPlugin(FloatingMenu(this.$el)) editor.registerPlugin(FloatingMenu({
element: this.$el,
onUpdate: menu => {
this.menu = menu
},
}))
}) })
} }
}, },
}, },
}, },
render(createElement) { render() {
if (!this.editor) { if (!this.editor) {
return null return null
} }
return createElement('div', this.$scopedSlots.default({ return this.$scopedSlots.default({
focused: this.editor.view.focused, focused: this.editor.view.focused,
focus: this.editor.focus, focus: this.editor.focus,
commands: this.editor.commands, commands: this.editor.commands,
isActive: this.editor.isActive.bind(this.editor), isActive: this.editor.isActive.bind(this.editor),
markAttrs: this.editor.markAttrs.bind(this.editor), markAttrs: this.editor.markAttrs.bind(this.editor),
})) menu: this.menu,
})
}, },
} }

View File

@@ -1,12 +1,18 @@
import { Plugin } from 'prosemirror-state' import { Plugin } from 'prosemirror-state'
class Toolbar { class Menu {
constructor({ element, editorView }) { constructor({ options, editorView }) {
this.options = {
...{
element: null,
onUpdate: () => false,
},
...options,
}
this.editorView = editorView this.editorView = editorView
this.element = element this.isActive = false
this.element.style.visibility = 'hidden' this.top = 0
this.element.style.opacity = 0
this.editorView.dom.addEventListener('blur', this.hide.bind(this)) this.editorView.dom.addEventListener('blur', this.hide.bind(this))
} }
@@ -35,17 +41,21 @@ class Toolbar {
return return
} }
const editorBoundings = this.element.offsetParent.getBoundingClientRect() const editorBoundings = this.options.element.offsetParent.getBoundingClientRect()
const cursorBoundings = view.coordsAtPos(state.selection.$anchor.pos) const cursorBoundings = view.coordsAtPos(state.selection.$anchor.pos)
const top = cursorBoundings.top - editorBoundings.top const top = cursorBoundings.top - editorBoundings.top
this.element.style.top = `${top}px` this.isActive = true
this.show() this.top = top
this.sendUpdate()
} }
show() { sendUpdate() {
this.element.style.visibility = 'visible' this.options.onUpdate({
this.element.style.opacity = 1 isActive: this.isActive,
top: this.top,
})
} }
hide(event) { hide(event) {
@@ -53,8 +63,8 @@ class Toolbar {
return return
} }
this.element.style.visibility = 'hidden' this.isActive = false
this.element.style.opacity = 0 this.sendUpdate()
} }
destroy() { destroy() {
@@ -63,10 +73,10 @@ class Toolbar {
} }
export default function (element) { export default function (options) {
return new Plugin({ return new Plugin({
view(editorView) { view(editorView) {
return new Toolbar({ editorView, element }) return new Menu({ editorView, options })
}, },
}) })
} }