chat-pc/src/components/editor/suggestion.js
2025-07-08 11:07:37 +08:00

117 lines
2.8 KiB
JavaScript

import { computePosition, flip, shift } from '@floating-ui/dom'
import { posToDOMRect, VueRenderer } from '@tiptap/vue-3'
import MentionList from './MentionList.vue'
import { defAvatar } from '@/constant/default'
const updatePosition = (editor, element) => {
const virtualElement = {
getBoundingClientRect: () => posToDOMRect(editor.view, editor.state.selection.from, editor.state.selection.to),
}
computePosition(virtualElement, element, {
placement: 'bottom-start',
strategy: 'absolute',
middleware: [shift(), flip()],
}).then(({ x, y, strategy }) => {
element.style.position = strategy
if (window.__POWERED_BY_WUJIE__) {
element.style.left = `${x + 200}px`
element.style.top = `${y + 100}px`
} else {
element.style.left = `${x}px`
element.style.top = `${y}px`
}
})
}
export default {
items: ({ query, editor, props }) => {
if (!props.members || !props.members.length) {
return []
}
let list = [...props.members]
// 如果是群组管理员,添加"所有人"选项
if (props.isGroupManager) {
list.unshift({ id: 0, nickname: '所有人', avatar: defAvatar })
}
// 排除掉自己
list.splice(list.findIndex((item) => item.id === props.uid), 1)
const filteredItems = list.filter(
(item) => item.nickname.toLowerCase().includes(query.toLowerCase())
)
// 如果没有匹配项,返回空数组以关闭弹窗
if (filteredItems.length === 0) {
return []
}
return filteredItems
},
render: () => {
let component
return {
onStart: props => {
// 如果没有匹配项,不创建弹窗
if (!props.items || props.items.length === 0) {
return
}
component = new VueRenderer(MentionList, {
// Vue 3 props格式
props,
editor: props.editor,
})
if (!props.clientRect) {
return
}
component.element.style.position = 'absolute'
document.body.appendChild(component.element)
updatePosition(props.editor, component.element)
},
onUpdate(props) {
component.updateProps(props)
if (props.items.length === 0) {
this.onExit()
return
}
if (!props.clientRect) {
return
}
updatePosition(props.editor, component.element)
},
onKeyDown(props) {
if (props.event.key === 'Escape') {
this.onExit()
return true
}
if(!component?.props.items?.length){
return false
}
return component.ref.onKeyDown(props)
},
onExit() {
console.log('component.element',component.element)
component.element.remove()
component.destroy()
},
}
},
}