dify/web/app/components/datasets/documents/detail/completed/common/drawer.tsx
-LAN- 85cda47c70
feat: knowledge pipeline (#25360)
Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: twwu <twwu@dify.ai>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
Co-authored-by: jyong <718720800@qq.com>
Co-authored-by: Wu Tianwei <30284043+WTW0313@users.noreply.github.com>
Co-authored-by: QuantumGhost <obelisk.reg+git@gmail.com>
Co-authored-by: lyzno1 <yuanyouhuilyz@gmail.com>
Co-authored-by: quicksand <quicksandzn@gmail.com>
Co-authored-by: Jyong <76649700+JohnJyong@users.noreply.github.com>
Co-authored-by: lyzno1 <92089059+lyzno1@users.noreply.github.com>
Co-authored-by: zxhlyh <jasonapring2015@outlook.com>
Co-authored-by: Yongtao Huang <yongtaoh2022@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: nite-knite <nkCoding@gmail.com>
Co-authored-by: Hanqing Zhao <sherry9277@gmail.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Harry <xh001x@hotmail.com>
2025-09-18 12:49:10 +08:00

112 lines
3.6 KiB
TypeScript

import React, { useCallback, useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
import cn from '@/utils/classnames'
import { useKeyPress } from 'ahooks'
import { useSegmentListContext } from '..'
type DrawerProps = {
open: boolean
onClose: () => void
side?: 'right' | 'left' | 'bottom' | 'top'
showOverlay?: boolean
modal?: boolean // click outside event can pass through if modal is false
closeOnOutsideClick?: boolean
panelClassName?: string
panelContentClassName?: string
needCheckChunks?: boolean
}
const Drawer = ({
open,
onClose,
side = 'right',
showOverlay = true,
modal = false,
needCheckChunks = false,
children,
panelClassName,
panelContentClassName,
}: React.PropsWithChildren<DrawerProps>) => {
const panelContentRef = useRef<HTMLDivElement>(null)
const currSegment = useSegmentListContext(s => s.currSegment)
const currChildChunk = useSegmentListContext(s => s.currChildChunk)
useKeyPress('esc', (e) => {
if (!open) return
e.preventDefault()
onClose()
}, { exactMatch: true, useCapture: true })
const shouldCloseDrawer = useCallback((target: Node | null) => {
const panelContent = panelContentRef.current
if (!panelContent) return false
const chunks = document.querySelectorAll('.chunk-card')
const childChunks = document.querySelectorAll('.child-chunk')
const isClickOnChunk = Array.from(chunks).some((chunk) => {
return chunk && chunk.contains(target)
})
const isClickOnChildChunk = Array.from(childChunks).some((chunk) => {
return chunk && chunk.contains(target)
})
const reopenChunkDetail = (currSegment.showModal && isClickOnChildChunk)
|| (currChildChunk.showModal && isClickOnChunk && !isClickOnChildChunk) || (!isClickOnChunk && !isClickOnChildChunk)
return target && !panelContent.contains(target) && (!needCheckChunks || reopenChunkDetail)
}, [currSegment, currChildChunk, needCheckChunks])
const onDownCapture = useCallback((e: PointerEvent) => {
if (!open || modal) return
const panelContent = panelContentRef.current
if (!panelContent) return
const target = e.target as Node | null
if (shouldCloseDrawer(target))
queueMicrotask(onClose)
}, [shouldCloseDrawer, onClose, open, modal])
useEffect(() => {
window.addEventListener('pointerdown', onDownCapture, { capture: true })
return () =>
window.removeEventListener('pointerdown', onDownCapture, { capture: true })
}, [onDownCapture])
const isHorizontal = side === 'left' || side === 'right'
const content = (
<div className='pointer-events-none fixed inset-0 z-[9999]'>
{showOverlay ? (
<div
onClick={modal ? onClose : undefined}
aria-hidden='true'
className={cn(
'fixed inset-0 bg-black/30 opacity-0 transition-opacity duration-200 ease-in',
open && 'opacity-100',
modal && open ? 'pointer-events-auto' : 'pointer-events-none',
)}
/>
) : null}
{/* Drawer panel */}
<div
role='dialog'
aria-modal={modal ? 'true' : 'false'}
className={cn(
'pointer-events-auto fixed flex flex-col',
side === 'right' && 'right-0',
side === 'left' && 'left-0',
side === 'bottom' && 'bottom-0',
side === 'top' && 'top-0',
isHorizontal ? 'h-screen' : 'w-screen',
panelClassName,
)}
>
<div ref={panelContentRef} className={cn('flex grow flex-col', panelContentClassName)}>
{children}
</div>
</div>
</div>
)
return open && createPortal(content, document.body)
}
export default Drawer