mirror of
https://github.com/qier222/YesPlayMusic.git
synced 2025-03-30 19:55:26 +08:00
86 lines
2.3 KiB
TypeScript
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
|