132 lines
3.0 KiB
TypeScript
132 lines
3.0 KiB
TypeScript
'use client'
|
|
|
|
import { useCallback, useEffect } from 'react'
|
|
|
|
export type ContextMenuType = 'canvas' | 'node' | 'edge'
|
|
|
|
type ContextMenuProps = {
|
|
x: number
|
|
y: number
|
|
type: ContextMenuType
|
|
onClose: () => void
|
|
onAddDialogue?: () => void
|
|
onAddChoice?: () => void
|
|
onAddVariable?: () => void
|
|
onDelete?: () => void
|
|
onAddCondition?: () => void
|
|
}
|
|
|
|
export default function ContextMenu({
|
|
x,
|
|
y,
|
|
type,
|
|
onClose,
|
|
onAddDialogue,
|
|
onAddChoice,
|
|
onAddVariable,
|
|
onDelete,
|
|
onAddCondition,
|
|
}: ContextMenuProps) {
|
|
// Close menu on Escape key
|
|
const handleKeyDown = useCallback(
|
|
(e: KeyboardEvent) => {
|
|
if (e.key === 'Escape') {
|
|
onClose()
|
|
}
|
|
},
|
|
[onClose]
|
|
)
|
|
|
|
// Close menu on click outside
|
|
const handleClickOutside = useCallback(() => {
|
|
onClose()
|
|
}, [onClose])
|
|
|
|
useEffect(() => {
|
|
document.addEventListener('keydown', handleKeyDown)
|
|
document.addEventListener('click', handleClickOutside)
|
|
return () => {
|
|
document.removeEventListener('keydown', handleKeyDown)
|
|
document.removeEventListener('click', handleClickOutside)
|
|
}
|
|
}, [handleKeyDown, handleClickOutside])
|
|
|
|
const menuItemClass =
|
|
'w-full px-4 py-2 text-left text-sm hover:bg-zinc-100 dark:hover:bg-zinc-700 cursor-pointer'
|
|
|
|
return (
|
|
<div
|
|
className="fixed z-50 min-w-40 rounded-md border border-zinc-200 bg-white shadow-lg dark:border-zinc-700 dark:bg-zinc-800"
|
|
style={{ left: x, top: y }}
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
{type === 'canvas' && (
|
|
<>
|
|
<button
|
|
className={`${menuItemClass} text-blue-600 dark:text-blue-400`}
|
|
onClick={() => {
|
|
onAddDialogue?.()
|
|
onClose()
|
|
}}
|
|
>
|
|
Add Dialogue
|
|
</button>
|
|
<button
|
|
className={`${menuItemClass} text-green-600 dark:text-green-400`}
|
|
onClick={() => {
|
|
onAddChoice?.()
|
|
onClose()
|
|
}}
|
|
>
|
|
Add Choice
|
|
</button>
|
|
<button
|
|
className={`${menuItemClass} text-orange-600 dark:text-orange-400`}
|
|
onClick={() => {
|
|
onAddVariable?.()
|
|
onClose()
|
|
}}
|
|
>
|
|
Add Variable
|
|
</button>
|
|
</>
|
|
)}
|
|
|
|
{type === 'node' && (
|
|
<button
|
|
className={`${menuItemClass} text-red-600 dark:text-red-400`}
|
|
onClick={() => {
|
|
onDelete?.()
|
|
onClose()
|
|
}}
|
|
>
|
|
Delete
|
|
</button>
|
|
)}
|
|
|
|
{type === 'edge' && (
|
|
<>
|
|
<button
|
|
className={`${menuItemClass} text-red-600 dark:text-red-400`}
|
|
onClick={() => {
|
|
onDelete?.()
|
|
onClose()
|
|
}}
|
|
>
|
|
Delete
|
|
</button>
|
|
<button
|
|
className={menuItemClass}
|
|
onClick={() => {
|
|
onAddCondition?.()
|
|
onClose()
|
|
}}
|
|
>
|
|
Add Condition
|
|
</button>
|
|
</>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|