fix: 块编辑器输入斜杠无法弹出slash菜单
This commit is contained in:
parent
609393867d
commit
2aa3fa507b
@ -66,9 +66,26 @@ const key = new PluginKey(props.pluginKey)
|
||||
let renderer: VueRenderer | null = null
|
||||
let isRegistered = false
|
||||
|
||||
// ── Click-outside-to-close handler ───────────────────────────────────────
|
||||
/** Dismiss the suggestion when a mousedown lands outside both the editor
|
||||
* and the popup menu. This matches the standard UX pattern. */
|
||||
function onDocumentMousedown(event: MouseEvent) {
|
||||
if (!renderer?.el) return
|
||||
const target = event.target as Node
|
||||
// Click on the menu itself → allow interaction (keep open)
|
||||
if (renderer.el.contains(target)) return
|
||||
// Any click outside the menu → dismiss.
|
||||
// Defer to avoid interfering with ProseMirror's click handling.
|
||||
setTimeout(() => close(), 0)
|
||||
}
|
||||
|
||||
function onCreateHandler() {
|
||||
register()
|
||||
}
|
||||
|
||||
function register() {
|
||||
const editor = props.editor
|
||||
if (!editor || !editor.isInitialized) return
|
||||
if (!editor) return
|
||||
if (isRegistered) return
|
||||
|
||||
const plugin = Suggestion({
|
||||
@ -95,13 +112,15 @@ function register() {
|
||||
if (!renderer) {
|
||||
renderer = new VueRenderer(markRaw(props.component), {
|
||||
editor: suggestionProps.editor,
|
||||
props: suggestionProps,
|
||||
})
|
||||
}
|
||||
const container = suggestionProps.editor.view.dom.closest('.blockeditor-mount')
|
||||
if (container && renderer.element) {
|
||||
container.appendChild(renderer.element)
|
||||
if (container && renderer.el) {
|
||||
container.appendChild(renderer.el)
|
||||
}
|
||||
renderer.updateProps(suggestionProps)
|
||||
document.addEventListener('mousedown', onDocumentMousedown)
|
||||
},
|
||||
|
||||
onUpdate: (suggestionProps: SuggestionProps) => {
|
||||
@ -109,6 +128,7 @@ function register() {
|
||||
},
|
||||
|
||||
onExit: () => {
|
||||
document.removeEventListener('mousedown', onDocumentMousedown)
|
||||
renderer?.destroy()
|
||||
renderer = null
|
||||
},
|
||||
@ -128,7 +148,12 @@ function register() {
|
||||
}
|
||||
|
||||
function unregister() {
|
||||
if (!props.editor || !isRegistered) return
|
||||
if (!props.editor) return
|
||||
if (!isRegistered) {
|
||||
// Even if not registered, remove the event listener to avoid leaks
|
||||
try { props.editor.off('create', onCreateHandler) } catch { /* ignore */ }
|
||||
return
|
||||
}
|
||||
if (renderer) {
|
||||
renderer.destroy()
|
||||
renderer = null
|
||||
@ -140,21 +165,22 @@ function unregister() {
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.editor?.isInitialized,
|
||||
(initialized) => {
|
||||
if (initialized && props.editor) register()
|
||||
() => props.editor,
|
||||
(editor, oldEditor) => {
|
||||
if (oldEditor && oldEditor !== editor) unregister()
|
||||
if (!editor) return
|
||||
if (editor.isInitialized) {
|
||||
register()
|
||||
} else {
|
||||
// TipTap v3 sets isInitialized = true inside setTimeout(0),
|
||||
// so Vue's watch cannot detect the change on this non-reactive property.
|
||||
// We listen for the editor's 'create' event instead.
|
||||
editor.on('create', onCreateHandler, { once: true })
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.editor,
|
||||
(newEditor, oldEditor) => {
|
||||
if (oldEditor && oldEditor !== newEditor) unregister()
|
||||
if (newEditor && newEditor.isInitialized) register()
|
||||
},
|
||||
)
|
||||
|
||||
onBeforeUnmount(() => { unregister() })
|
||||
|
||||
function close() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user