2022-10-28 20:29:04 +08:00

86 lines
2.3 KiB
TypeScript

import { useLayoutEffect, useRef, useState } from 'react'
import { useClickAway } from 'react-use'
import useLockMainScroll from '@/web/hooks/useLockMainScroll'
import useMeasure from 'react-use-measure'
import { ContextMenuItem } from './MenuItem'
import MenuPanel from './MenuPanel'
const BasicContextMenu = ({
onClose,
items,
target,
cursorPosition,
options,
classNames,
}: {
onClose: (e: MouseEvent) => void
items: ContextMenuItem[]
target: HTMLElement
cursorPosition: { x: number; y: number }
options?: {
useCursorPosition?: boolean
} | null
classNames?: string
}) => {
const menuRef = useRef<HTMLDivElement>(null)
const [measureRef, menu] = useMeasure()
const [position, setPosition] = useState<{ x: number; y: number } | null>(
null
)
useClickAway(menuRef, onClose)
useLockMainScroll(!!position)
useLayoutEffect(() => {
if (options?.useCursorPosition) {
const leftX = cursorPosition.x
const rightX = cursorPosition.x - menu.width
const bottomY = cursorPosition.y
const topY = cursorPosition.y - menu.height
const position = {
x: leftX + menu.width < window.innerWidth ? leftX : rightX,
y: bottomY + menu.height < window.innerHeight ? bottomY : topY,
}
setPosition(position)
} else {
const button = target.getBoundingClientRect()
const leftX = button.x
const rightX = button.x - menu.width + button.width
const bottomY = button.y + button.height + 8
const topY = button.y - menu.height - 8
const position = {
x: leftX + menu.width < window.innerWidth ? leftX : rightX,
y: bottomY + menu.height < window.innerHeight ? bottomY : topY,
}
setPosition(position)
}
}, [target, menu, options?.useCursorPosition, cursorPosition])
return (
<>
<MenuPanel
position={{ x: 99999, y: 99999 }}
items={items}
ref={measureRef}
onClose={() => {
//
}}
forMeasure={true}
classNames={classNames}
/>
{position && (
<MenuPanel
position={position}
items={items}
ref={menuRef}
onClose={onClose}
classNames={classNames}
/>
)}
</>
)
}
export default BasicContextMenu