dify/web/app/components/base/prompt-editor/plugins/draggable-plugin/index.tsx
Stephen Zhou a84c2d36a3
style: format with vp fmt (#38803)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-12 15:57:46 +00:00

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}
/>
)
}