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) => { const panelContentRef = useRef(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 = (
{showOverlay ? ( ) return open && createPortal(content, document.body) } export default Drawer