mirror of
https://github.com/langgenius/dify.git
synced 2026-07-24 04:58:32 +08:00
86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
import type { JSX } from 'react'
|
|
import { cn } from '@langgenius/dify-ui/cn'
|
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
import { DraggableBlockPlugin_EXPERIMENTAL } from '@lexical/react/LexicalDraggableBlockPlugin'
|
|
import { useEffect, useRef, useState } from 'react'
|
|
|
|
const DRAGGABLE_BLOCK_MENU_CLASSNAME = 'draggable-block-menu'
|
|
|
|
function isOnMenu(element: HTMLElement): boolean {
|
|
return !!element.closest(`.${DRAGGABLE_BLOCK_MENU_CLASSNAME}`)
|
|
}
|
|
|
|
const SUPPORT_DRAG_CLASS = 'support-drag'
|
|
function checkSupportDrag(element: Element | null): boolean {
|
|
if (!element) return false
|
|
|
|
if (element.classList.contains(SUPPORT_DRAG_CLASS)) return true
|
|
|
|
if (element.querySelector(`.${SUPPORT_DRAG_CLASS}`)) return true
|
|
|
|
return !!element.closest(`.${SUPPORT_DRAG_CLASS}`)
|
|
}
|
|
|
|
export default function DraggableBlockPlugin({
|
|
anchorElem = document.body,
|
|
}: {
|
|
anchorElem?: HTMLElement
|
|
}): JSX.Element {
|
|
const menuRef = useRef<HTMLDivElement>(null)
|
|
const targetLineRef = useRef<HTMLDivElement>(null)
|
|
const [, setDraggableElement] = useState<HTMLElement | null>(null)
|
|
const [editor] = useLexicalComposerContext()
|
|
|
|
const [isSupportDrag, setIsSupportDrag] = useState(false)
|
|
|
|
useEffect(() => {
|
|
const root = editor.getRootElement()
|
|
if (!root) return
|
|
|
|
const onMove = (e: MouseEvent) => {
|
|
const isSupportDrag = checkSupportDrag(e.target as Element)
|
|
setIsSupportDrag(isSupportDrag)
|
|
}
|
|
|
|
root.addEventListener('mousemove', onMove)
|
|
return () => root.removeEventListener('mousemove', onMove)
|
|
}, [editor])
|
|
|
|
return (
|
|
<DraggableBlockPlugin_EXPERIMENTAL
|
|
anchorElem={anchorElem}
|
|
menuRef={menuRef as any}
|
|
targetLineRef={targetLineRef as any}
|
|
menuComponent={
|
|
isSupportDrag ? (
|
|
<div
|
|
ref={menuRef}
|
|
className={cn(
|
|
DRAGGABLE_BLOCK_MENU_CLASSNAME,
|
|
'absolute top-4 right-2.5 cursor-grab opacity-0 will-change-transform active:cursor-move',
|
|
)}
|
|
data-testid="draggable-menu"
|
|
>
|
|
<span
|
|
className="i-ri-draggable size-3.5 text-text-tertiary"
|
|
data-testid="draggable-menu-icon"
|
|
/>
|
|
</div>
|
|
) : null
|
|
}
|
|
targetLineComponent={
|
|
<div
|
|
ref={targetLineRef}
|
|
className="pointer-events-none absolute top-0 left-[-21px] opacity-0 will-change-transform"
|
|
data-testid="draggable-target-line"
|
|
// style={{ width: 500 }} // width not worked here
|
|
>
|
|
<div className="absolute top-0 -right-10 left-0 h-[2px] bg-text-accent-secondary"></div>
|
|
</div>
|
|
}
|
|
isOnMenu={isOnMenu}
|
|
onElementChanged={setDraggableElement}
|
|
/>
|
|
)
|
|
}
|