83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
import { HTMLEditor } from '../lib'
|
||
import { useEffect, useRef, useState } from 'react'
|
||
|
||
export const useToolPostion = (editor: HTMLEditor | null, isDoc: boolean) => {
|
||
const [position, setPosition] = useState<{ left: number; top: number, bottom: number, right: number, width: number, height: number } | null>(null)
|
||
// 标识是否从编辑器内开始选择
|
||
const isSelectingRef = useRef(false)
|
||
const updatePositionFromSelection = () => {
|
||
if (!editor) {
|
||
return
|
||
}
|
||
const view = editor.getDoc().view
|
||
if (!view) {
|
||
return
|
||
}
|
||
const selection = view.getSelection()
|
||
if (!selection) return
|
||
// 如果选区为空,不需要更新
|
||
const hasSelectAnything = selection.rangeCount === 0 || selection.toString().trim() === ''
|
||
if (selection.isCollapsed || selection.rangeCount === 0 || hasSelectAnything) {
|
||
setPosition(null)
|
||
return
|
||
}
|
||
|
||
// 获取选区的 Range 对象
|
||
const range = selection.getRangeAt(0);
|
||
// 获取选区末尾的位置
|
||
// 创建一个新的 Range,只包含选区的末尾点
|
||
const endRange = range.cloneRange();
|
||
endRange.collapse(false); // false 表示折叠到末尾
|
||
const rect = endRange.getBoundingClientRect();
|
||
|
||
const { top, left, bottom, right, width, height } = rect
|
||
setPosition({ top, left, bottom, right, width, height })
|
||
}
|
||
|
||
useEffect(() => {
|
||
if (!editor || !isDoc) {
|
||
return
|
||
}
|
||
const dom = editor.getDoc().document
|
||
if (!dom) {
|
||
return
|
||
}
|
||
|
||
const onMouseDown = () => {
|
||
isSelectingRef.current = true
|
||
}
|
||
|
||
const onMouseUp = () => {
|
||
// 只有从编辑器内开始选择时才处理
|
||
if (!isSelectingRef.current) {
|
||
return
|
||
}
|
||
isSelectingRef.current = false
|
||
setTimeout(() => {
|
||
updatePositionFromSelection()
|
||
}, 50)
|
||
}
|
||
|
||
const onScrollOrResize = () => {
|
||
updatePositionFromSelection()
|
||
}
|
||
|
||
dom.addEventListener('mousedown', onMouseDown)
|
||
dom.addEventListener('mouseup', onMouseUp)
|
||
dom.addEventListener('scroll', onScrollOrResize)
|
||
|
||
window.addEventListener('scroll', onScrollOrResize, true)
|
||
window.addEventListener('resize', onScrollOrResize)
|
||
|
||
return () => {
|
||
dom.removeEventListener('mousedown', onMouseDown)
|
||
dom.removeEventListener('mouseup', onMouseUp)
|
||
dom.removeEventListener('scroll', onScrollOrResize)
|
||
window.removeEventListener('scroll', onScrollOrResize, true)
|
||
window.removeEventListener('resize', onScrollOrResize)
|
||
}
|
||
}, [editor, updatePositionFromSelection, isDoc])
|
||
|
||
return position
|
||
}
|